diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index b1711f01c47b37b5fce11546146c2e432357abfb..41a89918e25e80a760da57a086d19596513c87e2 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -5,6 +5,7 @@ use std::ops::{Index, IndexMut}; use super::arena::{Arena, Id}; use crate::collections::StringRef; use crate::protocol::input_source::InputSpan; +use crate::protocol::TypeId; /// Helper macro that defines a type alias for a AST element ID. In this case /// only used to alias the `Id` types. @@ -1015,6 +1016,18 @@ pub enum ProcedureKind { Composite, } +/// Monomorphed instantiation of a procedure (or the sole instantiation of a +/// non-polymorphic procedure). +pub struct ProcedureDefinitionMonomorph { + pub argument_types: Vec, + pub expr_info: Vec +} + +pub struct MonomorphExpressionInfo { + pub type_id: TypeId, + pub index: i32, // for called procedure's monomorphs, or selected field indices +} + /// Generic storage for functions, primitive components and composite /// components. // Note that we will have function definitions for builtin functions as well. In @@ -1035,7 +1048,7 @@ pub struct ProcedureDefinition { pub scope: ScopeId, pub body: BlockStatementId, // Monomorphization of typed procedures - + pub monomorphs: Vec, // Validation/linking pub num_expressions_in_body: i32, } @@ -1054,6 +1067,7 @@ impl ProcedureDefinition { parameters: Vec::new(), scope: ScopeId::new_invalid(), body: BlockStatementId::new_invalid(), + monomorphs: Vec::new(), num_expressions_in_body: -1, } } @@ -1568,7 +1582,8 @@ pub struct AssignmentExpression { pub right: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1581,7 +1596,8 @@ pub struct BindingExpression { pub bound_from: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1595,7 +1611,8 @@ pub struct ConditionalExpression { pub false_expression: ExpressionId, // Validator/Linking pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1632,7 +1649,8 @@ pub struct BinaryExpression { pub right: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1653,7 +1671,8 @@ pub struct UnaryExpression { pub expression: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1666,7 +1685,8 @@ pub struct IndexingExpression { pub index: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1680,7 +1700,8 @@ pub struct SlicingExpression { pub to_index: ExpressionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1699,7 +1720,8 @@ pub struct SelectExpression { pub kind: SelectKind, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1712,7 +1734,8 @@ pub struct CastExpression { pub subject: ExpressionId, // Validator/linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1727,7 +1750,8 @@ pub struct CallExpression { pub procedure: ProcedureDefinitionId, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -1763,7 +1787,8 @@ pub struct LiteralExpression { pub value: Literal, // Validator/Linker pub parent: ExpressionParent, - pub unique_id_in_definition: i32, + // Typing + pub expr_index: i32, } #[derive(Debug, Clone)] @@ -1860,5 +1885,6 @@ pub struct VariableExpression { pub declaration: Option, pub used_as_binding_target: bool, pub parent: ExpressionParent, - pub unique_id_in_definition: i32, // used to index into type table after all types are determined + // Typing + pub expr_index: i32, } \ No newline at end of file diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 3986dc01dc01c708ef54ca8b842dc8d7ef17c998..8b33f76bb65bc6a3f0045dd34d282ffd36f9301c 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -1989,8 +1989,11 @@ impl PassTyping { Ok(concrete_type) } - // Inference is now done. But we may still have uninferred types. So we - // check for these. + // Inference is now done. But we may still have polymorphic data that is + // not fully inferred, while the associated expression is. An example + // being a polymorphic function call: we need to instantiate a + // monomorph, so need all of its polymorphic variables, but the call + // expression was only interested in the return value. for infer_expr in self.infer_nodes.iter_mut() { if !infer_expr.expr_type.is_done { let expr = &ctx.heap[infer_expr.expr_id]; @@ -2004,9 +2007,6 @@ impl PassTyping { // Expression is fine, check if any extra data is attached if infer_expr.poly_data_index < 0 { continue; } - - // Extra data is attached, perform typechecking and transfer - // resolved information to the expression let poly_data = &self.poly_data[infer_expr.poly_data_index as usize]; // Note that only call and literal expressions need full inference. @@ -2058,7 +2058,7 @@ impl PassTyping { let concrete_type = inference_type_to_concrete_type( ctx, infer_expr.expr_id, &poly_data.poly_vars, first_concrete_part )?; - let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, definition_id, concrete_type)?; + let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, concrete_type)?; infer_expr.type_id = type_id; }, Expression::Select(_) => { @@ -2071,20 +2071,25 @@ impl PassTyping { } // Every expression checked, and new monomorphs are queued. Transfer the - // expression information to the type table. - let procedure_arguments = &ctx.heap[self.procedure_id].parameters; - - let target = ctx.types.get_procedure_monomorph_mut(self.reserved_type_id); - debug_assert!(target.arg_types.is_empty()); // makes sure we never queue a procedure's type inferencing twice - debug_assert!(target.expr_data.is_empty()); + // expression information to the AST. If this is the first time we're + // visiting this procedure then we assign expression indices as well. + let procedure = &mut ctx.heap[self.procedure_id]; + let mut monomorph = ProcedureDefinitionMonomorph{ + argument_types: Vec::with_capacity(procedure.parameters.len()), + expr_info: Vec::with_capacity(self.infer_nodes().len()), // TODO: Initial reservation + }; - // - Write the arguments to the procedure - target.arg_types.reserve(procedure_arguments.len()); - for argument_id in procedure_arguments { + // - Write the arguments + for parameter_id in procedure.parameters.iter().copied() { let mut concrete = ConcreteType::default(); - let var_data = self.var_data.iter().find(|v| v.var_id == *argument_id).unwrap(); + let var_data = self.var_data.iter().find(|v| v.var_id == parameter_id).unwrap(); var_data.var_type.write_concrete_type(&mut concrete); - target.arg_types.push(concrete); + let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, concrete)?; + monomorph.argument_types.push(type_id) + } + + for infer_node in self.infer_nodes.iter() { + let expr = &ctx.heap[infer_node.expr_id]; } // - Write the expression data diff --git a/src/protocol/parser/type_table.rs b/src/protocol/parser/type_table.rs index 24c7dafe70fa6df85b069b86e64321caba4c2469..297eff27cdf56ffe75d1182fa356e24f186ec1f8 100644 --- a/src/protocol/parser/type_table.rs +++ b/src/protocol/parser/type_table.rs @@ -699,20 +699,6 @@ impl TypeTable { return &self.mono_types[type_id.0 as usize]; } - /// Returns a mutable reference to a procedure's monomorph expression data. - /// Used by typechecker to fill in previously reserved type information - #[inline] - pub(crate) fn get_procedure_monomorph_mut(&mut self, type_id: TypeId) -> &mut ProcedureMonomorph { - let mono_type = &mut self.mono_types[type_id.0 as usize]; - return mono_type.variant.as_procedure_mut(); - } - - #[inline] - pub(crate) fn get_procedure_monomorph(&self, type_id: TypeId) -> &ProcedureMonomorph { - let mono_type = &self.mono_types[type_id.0 as usize]; - return mono_type.variant.as_procedure(); - } - /// Reserves space for a monomorph of a polymorphic procedure. The index /// will point into a (reserved) slot of the array of expression types. The /// monomorph may NOT exist yet (because the reservation implies that we're @@ -736,7 +722,6 @@ impl TypeTable { /// Adds a builtin type to the type table. As this is only called by the /// compiler during setup we assume it cannot fail. - // TODO: Finish this train of thought, requires a little bit of design work pub(crate) fn add_builtin_type(&mut self, concrete_type: ConcreteType, poly_vars: &[PolymorphicVariable], size: usize, alignment: usize) -> TypeId { self.mono_search_key.set(&concrete_type.parts, poly_vars); debug_assert!(!self.mono_type_lookup.contains_key(&self.mono_search_key)); @@ -757,15 +742,20 @@ impl TypeTable { /// Adds a monomorphed type to the type table. If it already exists then the /// previous entry will be used. pub(crate) fn add_monomorphed_type( - &mut self, modules: &[Module], heap: &Heap, arch: &TargetArch, - definition_id: DefinitionId, concrete_type: ConcreteType + &mut self, modules: &[Module], heap: &Heap, arch: &TargetArch, concrete_type: ConcreteType ) -> Result { - debug_assert_eq!(definition_id, get_concrete_type_definition(&concrete_type.parts).unwrap()); + let poly_vars = match get_concrete_type_definition(&concrete_type.parts) { + Some(definition_id) => { + let definition = self.definition_lookup.get(&definition_id).unwrap(); + definition.poly_vars.as_slice() + }, + None => { + &[] + } + }; // Check if the concrete type was already added - let definition = self.definition_lookup.get(&definition_id).unwrap(); - let poly_var_in_use = &definition.poly_vars; - self.mono_search_key.set(&concrete_type.parts, poly_var_in_use.as_slice()); + self.mono_search_key.set(&concrete_type.parts, poly_vars); if let Some(type_id) = self.mono_type_lookup.get(&self.mono_search_key) { return Ok(*type_id); }