Skip to content

Commit

Permalink
Switch to WorkingOnResolver-less typecheck
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Oct 28, 2024
1 parent 2190f77 commit 5729446
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 56 deletions.
6 changes: 6 additions & 0 deletions src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ pub struct UUIDAllocator<IndexMarker> {
cur : UUID<IndexMarker>
}

impl<IndexMarker> Clone for UUIDAllocator<IndexMarker> {
fn clone(&self) -> Self {
Self { cur: self.cur.clone() }
}
}

impl<IndexMarker> UUIDAllocator<IndexMarker> {
pub fn new() -> Self {
Self {
Expand Down
2 changes: 1 addition & 1 deletion src/flattening/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ pub enum ModuleOrWrittenType {
Module(GlobalReference<ModuleUUID>),
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct TypingAllocator {
pub type_variable_alloc: UUIDAllocator<TypeVariableIDMarker>,
pub domain_variable_alloc: UUIDAllocator<DomainVariableIDMarker>
Expand Down
90 changes: 56 additions & 34 deletions src/flattening/typechecking.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::alloc::ArenaAllocator;
use crate::prelude::*;
use crate::typing::type_inference::{FailedUnification, HindleyMilner};

use crate::debug::SpanDebugger;
use crate::linker::{
with_module_editing_context, Linkable, NameElem, NamedConstant, Resolver, WorkingOnResolver,
make_resolvers, with_module_editing_context, FileData, Linkable, NameElem, NamedConstant, Resolver
};

use crate::typing::{
Expand All @@ -14,38 +15,59 @@ use crate::typing::{
use super::*;

pub fn typecheck_all_modules(linker: &mut Linker) {
let linker_ptr: *mut Linker = linker;
for (module_uuid, module) in &mut linker.modules {
let ctx_info_string = format!("Typechecking {}", &module.link_info.name);
let module_uuids : Vec<ModuleUUID> = linker.modules.iter().map(|(id, _md)| id).collect();
for module_uuid in module_uuids {
let obj_link_info = &mut linker.modules[module_uuid].link_info;

let ctx_info_string = format!("Typechecking {}", &obj_link_info.name);
println!("{ctx_info_string}");
let mut span_debugger = SpanDebugger::new(
&ctx_info_string,
&linker.files[module.link_info.file],
&linker.files[obj_link_info.file],
);

with_module_editing_context(
linker_ptr,
module_uuid,
|modules, types, constants, name_resolver| {
let mut context = TypeCheckingContext {
errors: name_resolver.errors,
type_checker: TypeUnifier::new(
&modules.working_on.link_info.template_arguments,
name_resolver.errors,
&modules.working_on.link_info.type_variable_alloc
),
types,
constants,
runtime_condition_stack: Vec::new(),
working_on: module,
modules,
};

context.typecheck();
apply_types(&mut context.type_checker, context.modules.working_on, context.errors, &context.types);
},
);
let file: &FileData = &linker.files[obj_link_info.file];

// Extract errors and resolved_globals for easier editing
let errors_globals = obj_link_info.take_errors_globals_for_editing(&linker.files);

let working_on: &Module = &linker.modules[module_uuid];

let (modules, types, constants, name_resolver) = make_resolvers(linker, &file.file_text, &errors_globals);

let type_checker = {
let mut context = TypeCheckingContext {
errors: name_resolver.errors,
type_checker: TypeUnifier::new(
&working_on.link_info.template_arguments,
name_resolver.errors,
working_on.link_info.type_variable_alloc.clone()
),
types,
constants,
runtime_condition_stack: Vec::new(),
working_on,
modules,
};

context.typecheck();
context.type_checker
};


let new_type_checker = TypeUnifier {
template_type_names: type_checker.template_type_names,
errors: &errors_globals.0,
type_substitutor: type_checker.type_substitutor,
domain_substitutor: type_checker.domain_substitutor,
};
// Grab another mutable copy of md so it doesn't force a borrow conflict
let working_on_mut = &mut linker.modules[module_uuid];
apply_types(new_type_checker, working_on_mut, &errors_globals.0, &linker.types);

working_on_mut.link_info.reabsorb_errors_globals(errors_globals);

span_debugger.defuse();
}
}
Expand All @@ -56,17 +78,17 @@ struct ConditionStackElem {
domain: DomainType,
}

struct TypeCheckingContext<'l, 'errs> {
pub working_on: &'l Module,
modules: WorkingOnResolver<'l, 'errs, ModuleUUIDMarker, Module>,
type_checker: TypeUnifier<'l, 'errs>,
struct TypeCheckingContext<'l, 'errs, 'linker_file_texts> {
working_on: &'l Module,
modules: Resolver<'l, 'errs, ModuleUUIDMarker, Module>,
type_checker: TypeUnifier<'linker_file_texts, 'errs>,
types: Resolver<'l, 'errs, TypeUUIDMarker, StructType>,
constants: Resolver<'l, 'errs, ConstantUUIDMarker, NamedConstant>,
errors: &'errs ErrorCollector<'l>,
runtime_condition_stack: Vec<ConditionStackElem>,
}

impl<'l, 'errs> TypeCheckingContext<'l, 'errs> {
impl<'l, 'errs, 'linker_file_texts> TypeCheckingContext<'l, 'errs, 'linker_file_texts> {
fn get_link_info<ID: Into<NameElem>>(&self, id: ID) -> Option<&LinkInfo> {
let ne: NameElem = id.into();
match ne {
Expand Down Expand Up @@ -499,11 +521,11 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> {

// ====== Free functions for actually applying the result of type checking ======

pub fn apply_types<'linker, 'errs>(
type_checker: &mut TypeUnifier,
pub fn apply_types(
mut type_checker: TypeUnifier,
working_on: &mut Module,
errors: &ErrorCollector,
types: &Resolver<'linker, 'errs, TypeUUIDMarker, StructType>
types: &ArenaAllocator<StructType, TypeUUIDMarker>
) {
// Set the remaining domain variables that aren't associated with a module port.
// We just find domain IDs that haven't been
Expand Down
31 changes: 16 additions & 15 deletions src/linker/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,17 @@ where
pub struct NameResolver<'linker, 'err_and_globals> {
pub file_text: &'linker FileText,
pub errors: &'err_and_globals ErrorCollector<'linker>,
linker: *const Linker,
linker: &'linker Linker,
resolved_globals: &'err_and_globals RefCell<ResolvedGlobals>,
}

impl<'linker, 'err_and_globals> NameResolver<'linker, 'err_and_globals> {
/// SAFETY: Files are never touched, and as long as this object is managed properly linker will also exist long enough.
pub fn resolve_global<'slf>(&'slf self, name_span: Span) -> Option<(NameElem, Span)> {
let name = &self.file_text[name_span];
let linker = unsafe { &*self.linker };

let mut resolved_globals = self.resolved_globals.borrow_mut();
match linker.global_namespace.get(name) {
match self.linker.global_namespace.get(name) {
Some(NamespaceElement::Global(found)) => {
resolved_globals.referenced_globals.push(*found);
Some((*found, name_span))
Expand All @@ -104,7 +103,7 @@ impl<'linker, 'err_and_globals> NameResolver<'linker, 'err_and_globals> {
let err_ref = self.errors.error(name_span, format!("There were colliding imports for the name '{name}'. Pick one and import it by name."));

for collider_global in coll.iter() {
let err_loc = linker.get_linking_error_location(*collider_global);
let err_loc = self.linker.get_linking_error_location(*collider_global);
if let Some(span_file) = err_loc.location {
err_ref.info(
span_file,
Expand Down Expand Up @@ -137,7 +136,7 @@ impl<'linker, 'err_and_globals> NameResolver<'linker, 'err_and_globals> {
}

pub fn get_linking_error_location(&self, name_elem: NameElem) -> LinkingErrorLocation {
unsafe { &*self.linker }.get_linking_error_location(name_elem)
self.linker.get_linking_error_location(name_elem)
}
pub fn not_expected_global_error(&self, name_elem: NameElem, span: Span, expected: &str) {
// SAFETY: The allocated linker objects aren't going to change.
Expand All @@ -155,26 +154,25 @@ impl<'linker, 'err_and_globals> NameResolver<'linker, 'err_and_globals> {
}

/// pub struct ModuleEditContext<'linker, 'err_and_globals> {
/// pub modules : InternalResolver<'linker, 'err_and_globals, ModuleUUIDMarker, Module>,
/// pub modules : Resolver<'linker, 'err_and_globals, ModuleUUIDMarker, Module>,
/// pub types : Resolver<'linker, 'err_and_globals, TypeUUIDMarker, NamedType>,
/// pub constants : Resolver<'linker, 'err_and_globals, ConstantUUIDMarker, NamedConstant>,
/// pub name_resolver : NameResolver<'linker, 'err_and_globals>,
/// pub errors : &'err_and_globals ErrorCollector
/// }
pub fn with_module_editing_context<
F: for<'linker, 'errs> FnOnce(
WorkingOnResolver<'linker, 'errs, ModuleUUIDMarker, Module>,
Resolver<'linker, 'errs, ModuleUUIDMarker, Module>,
Resolver<'linker, 'errs, TypeUUIDMarker, StructType>,
Resolver<'linker, 'errs, ConstantUUIDMarker, NamedConstant>,
NameResolver<'linker, 'errs>,
&'linker Module
),
>(
linker_ptr: *mut Linker,
linker: &mut Linker,
module_uuid: ModuleUUID,
f: F,
) {
let linker = unsafe { &mut *linker_ptr };
let linker_modules_ptr: *const _ = &linker.modules;
let md: &mut Module = &mut linker.modules[module_uuid];
let file: &FileData = &linker.files[md.link_info.file];

Expand All @@ -184,11 +182,11 @@ pub fn with_module_editing_context<
let errors = &errors_a;
let resolved_globals = &resolved_globals_a;

let md: &Module = &linker.modules[module_uuid];
// Use context
f(
WorkingOnResolver {
working_on: md,
arr: linker_modules_ptr,
Resolver {
arr: &linker.modules,
resolved_globals,
},
Resolver {
Expand All @@ -201,12 +199,15 @@ pub fn with_module_editing_context<
},
NameResolver {
file_text: &file.file_text,
linker: linker_ptr,
linker,
errors,
resolved_globals,
},
md
);

// Grab another mutable copy of md so it doesn't force a borrow conflict
let md: &mut Module = &mut linker.modules[module_uuid];
md.link_info.reabsorb_errors_globals((errors_a, resolved_globals_a));
}

Expand All @@ -230,7 +231,7 @@ pub fn make_resolvers<'linker, 'errors>(linker: &'linker Linker, file_text: &'li
},
NameResolver {
file_text,
linker: linker as *const Linker,
linker,
errors,
resolved_globals,
})
Expand Down
13 changes: 7 additions & 6 deletions src/typing/abstract_type.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::alloc::ArenaAllocator;
use crate::prelude::*;
use crate::value::Value;

Expand Down Expand Up @@ -82,18 +83,18 @@ pub struct FullType {
/// 'A U 'x -> 'x = 'A
///
/// 'x U 'y -> 'x = 'y
pub struct TypeUnifier<'linker, 'errs> {
pub struct TypeUnifier<'linker_file_texts, 'errs> {
pub template_type_names: FlatAlloc<String, TemplateIDMarker>,
errors: &'errs ErrorCollector<'linker>,
pub errors: &'errs ErrorCollector<'linker_file_texts>,
pub type_substitutor: TypeSubstitutor<AbstractType, TypeVariableIDMarker>,
pub domain_substitutor: TypeSubstitutor<DomainType, DomainVariableIDMarker>,
}

impl<'linker, 'errs> TypeUnifier<'linker, 'errs> {
impl<'linker_file_texts, 'errs> TypeUnifier<'linker_file_texts, 'errs> {
pub fn new(
template_inputs: &TemplateInputs,
errors: &'errs ErrorCollector<'linker>,
typing_alloc: &TypingAllocator
errors: &'errs ErrorCollector<'linker_file_texts>,
typing_alloc: TypingAllocator
) -> Self {
Self {
template_type_names: map_to_type_names(template_inputs),
Expand Down Expand Up @@ -319,7 +320,7 @@ impl<'linker, 'errs> TypeUnifier<'linker, 'errs> {
self.unify_domains(&found.domain, &expected.domain, span, context);
}

pub fn finalize_type(&mut self, types: &Resolver<'_, '_, TypeUUIDMarker, StructType>, typ: &mut FullType, span: Span) {
pub fn finalize_type(&mut self, types: &ArenaAllocator<StructType, TypeUUIDMarker>, typ: &mut FullType, span: Span) {
use super::type_inference::HindleyMilner;

typ.domain.fully_substitute(&self.domain_substitutor).unwrap();
Expand Down

0 comments on commit 5729446

Please sign in to comment.