From 29e29db5e6b4b2a7b3f2dacc7dfb42a9133135c2 2022-02-24 11:45:19 From: MH Date: 2022-02-24 11:45:19 Subject: [PATCH] WIP: Remove unique id inside definition, replace with type index --- diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 41a89918e25e80a760da57a086d19596513c87e2..61bb609a30e47f16729f36900525d3e3745007f0 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -1020,12 +1020,53 @@ pub enum ProcedureKind { /// non-polymorphic procedure). pub struct ProcedureDefinitionMonomorph { pub argument_types: Vec, - pub expr_info: Vec + pub expr_info: Vec } -pub struct MonomorphExpressionInfo { +impl ProcedureDefinitionMonomorph { + pub(crate) fn new_invalid() -> Self { + return Self{ + argument_types: Vec::new(), + expr_info: Vec::new(), + } + } +} + +pub struct ExpressionInfo { pub type_id: TypeId, - pub index: i32, // for called procedure's monomorphs, or selected field indices + pub variant: ExpressionInfoVariant, +} + +impl ExpressionInfo { + pub(crate) fn new_invalid() -> Self { + return Self{ + type_id: TypeId::new_invalid(), + variant: ExpressionInfoVariant::Generic, + } + } +} + +#[derive(Clone, Copy)] +pub enum ExpressionInfoVariant { + Generic, + Procedure(TypeId, u32), // procedure TypeID and its monomorph index + Select(i32), // index +} + +impl ExpressionInfoVariant { + pub(crate) fn as_select(&self) -> i32 { + match self { + ExpressionInfoVariant::Select(v) => *v, + _ => unreachable!(), + } + } + + pub(crate) fn as_procedure(&self) -> (TypeId, u32) { + match self { + ExpressionInfoVariant::Procedure(type_id, monomorph_index) => (*type_id, *monomorph_index), + _ => unreachable!(), + } + } } /// Generic storage for functions, primitive components and composite @@ -1048,7 +1089,7 @@ pub struct ProcedureDefinition { pub scope: ScopeId, pub body: BlockStatementId, // Monomorphization of typed procedures - pub monomorphs: Vec, + pub monomorphs: Vec, // Validation/linking pub num_expressions_in_body: i32, } @@ -1537,20 +1578,37 @@ impl Expression { } } - pub fn get_unique_id_in_definition(&self) -> i32 { + pub fn type_index(&self) -> i32 { + match self { + Expression::Assignment(expr) => expr.type_index, + Expression::Binding(expr) => expr.type_index, + Expression::Conditional(expr) => expr.type_index, + Expression::Binary(expr) => expr.type_index, + Expression::Unary(expr) => expr.type_index, + Expression::Indexing(expr) => expr.type_index, + Expression::Slicing(expr) => expr.type_index, + Expression::Select(expr) => expr.type_index, + Expression::Literal(expr) => expr.type_index, + Expression::Cast(expr) => expr.type_index, + Expression::Call(expr) => expr.type_index, + Expression::Variable(expr) => expr.type_index, + } + } + + pub fn type_index_mut(&mut self) -> &mut i32 { match self { - Expression::Assignment(expr) => expr.unique_id_in_definition, - Expression::Binding(expr) => expr.unique_id_in_definition, - Expression::Conditional(expr) => expr.unique_id_in_definition, - Expression::Binary(expr) => expr.unique_id_in_definition, - Expression::Unary(expr) => expr.unique_id_in_definition, - Expression::Indexing(expr) => expr.unique_id_in_definition, - Expression::Slicing(expr) => expr.unique_id_in_definition, - Expression::Select(expr) => expr.unique_id_in_definition, - Expression::Literal(expr) => expr.unique_id_in_definition, - Expression::Cast(expr) => expr.unique_id_in_definition, - Expression::Call(expr) => expr.unique_id_in_definition, - Expression::Variable(expr) => expr.unique_id_in_definition, + Expression::Assignment(expr) => &mut expr.type_index, + Expression::Binding(expr) => &mut expr.type_index, + Expression::Conditional(expr) => &mut expr.type_index, + Expression::Binary(expr) => &mut expr.type_index, + Expression::Unary(expr) => &mut expr.type_index, + Expression::Indexing(expr) => &mut expr.type_index, + Expression::Slicing(expr) => &mut expr.type_index, + Expression::Select(expr) => &mut expr.type_index, + Expression::Literal(expr) => &mut expr.type_index, + Expression::Cast(expr) => &mut expr.type_index, + Expression::Call(expr) => &mut expr.type_index, + Expression::Variable(expr) => &mut expr.type_index, } } } @@ -1583,7 +1641,7 @@ pub struct AssignmentExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1597,7 +1655,7 @@ pub struct BindingExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1612,7 +1670,7 @@ pub struct ConditionalExpression { // Validator/Linking pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1650,7 +1708,7 @@ pub struct BinaryExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1672,7 +1730,7 @@ pub struct UnaryExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1686,7 +1744,7 @@ pub struct IndexingExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1701,7 +1759,7 @@ pub struct SlicingExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1721,7 +1779,7 @@ pub struct SelectExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1735,7 +1793,7 @@ pub struct CastExpression { // Validator/linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1751,7 +1809,7 @@ pub struct CallExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -1769,14 +1827,26 @@ pub enum Method { SelectRegisterCasePort, // SelectRegisterCasePort(case_index, port_index, port_id) SelectWait, // SelectWait() -> u32 // User-defined - UserProcedure, + UserFunction, UserComponent, } -#[derive(Debug, Clone)] -pub struct MethodSymbolic { - pub(crate) parser_type: ParserType, - pub(crate) definition: DefinitionId +impl Method { + pub(crate) fn is_public_builtin(&self) -> bool { + use Method::*; + match self { + Get | Put | Fires | Create | Length | Assert | Print => true, + _ => false, + } + } + + pub(crate) fn is_user_defined(&self) -> bool { + use Method::*; + match self { + UserFunction | UserComponent => true, + _ => false, + } + } } #[derive(Debug, Clone)] @@ -1788,7 +1858,7 @@ pub struct LiteralExpression { // Validator/Linker pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } #[derive(Debug, Clone)] @@ -1886,5 +1956,5 @@ pub struct VariableExpression { pub used_as_binding_target: bool, pub parent: ExpressionParent, // Typing - pub expr_index: i32, + pub type_index: i32, } \ No newline at end of file diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_printer.rs index a64b56f724bf3f8e7ccf788fa9e740f5628db24e..9b894301378e1cc8be76cbde116323b30b0cc3c9 100644 --- a/src/protocol/ast_printer.rs +++ b/src/protocol/ast_printer.rs @@ -574,7 +574,7 @@ impl ASTWriter { Expression::Assignment(expr) => { self.kv(indent).with_id(PREFIX_ASSIGNMENT_EXPR_ID, expr.this.0.index) .with_s_key("AssignmentExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); self.kv(indent2).with_s_key("Left"); self.write_expr(heap, expr.left, indent3); @@ -586,7 +586,7 @@ impl ASTWriter { Expression::Binding(expr) => { self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index) .with_s_key("BindingExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("BindToExpression"); self.write_expr(heap, expr.bound_to, indent3); self.kv(indent2).with_s_key("BindFromExpression"); @@ -597,7 +597,7 @@ impl ASTWriter { Expression::Conditional(expr) => { self.kv(indent).with_id(PREFIX_CONDITIONAL_EXPR_ID, expr.this.0.index) .with_s_key("ConditionalExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Condition"); self.write_expr(heap, expr.test, indent3); self.kv(indent2).with_s_key("TrueExpression"); @@ -610,7 +610,7 @@ impl ASTWriter { Expression::Binary(expr) => { self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index) .with_s_key("BinaryExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); self.kv(indent2).with_s_key("Left"); self.write_expr(heap, expr.left, indent3); @@ -622,7 +622,7 @@ impl ASTWriter { Expression::Unary(expr) => { self.kv(indent).with_id(PREFIX_UNARY_EXPR_ID, expr.this.0.index) .with_s_key("UnaryExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); self.kv(indent2).with_s_key("Argument"); self.write_expr(heap, expr.expression, indent3); @@ -632,7 +632,7 @@ impl ASTWriter { Expression::Indexing(expr) => { self.kv(indent).with_id(PREFIX_INDEXING_EXPR_ID, expr.this.0.index) .with_s_key("IndexingExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Subject"); self.write_expr(heap, expr.subject, indent3); self.kv(indent2).with_s_key("Index"); @@ -643,7 +643,7 @@ impl ASTWriter { Expression::Slicing(expr) => { self.kv(indent).with_id(PREFIX_SLICING_EXPR_ID, expr.this.0.index) .with_s_key("SlicingExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Subject"); self.write_expr(heap, expr.subject, indent3); self.kv(indent2).with_s_key("FromIndex"); @@ -656,7 +656,7 @@ impl ASTWriter { Expression::Select(expr) => { self.kv(indent).with_id(PREFIX_SELECT_EXPR_ID, expr.this.0.index) .with_s_key("SelectExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Subject"); self.write_expr(heap, expr.subject, indent3); @@ -676,7 +676,7 @@ impl ASTWriter { self.kv(indent).with_id(PREFIX_LITERAL_EXPR_ID, expr.this.0.index) .with_s_key("LiteralExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); let val = self.kv(indent2).with_s_key("Value"); match &expr.value { Literal::Null => { val.with_s_val("null"); }, @@ -752,7 +752,7 @@ impl ASTWriter { Expression::Cast(expr) => { self.kv(indent).with_id(PREFIX_CAST_EXPR_ID, expr.this.0.index) .with_s_key("CallExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("ToType") .with_custom_val(|t| write_parser_type(t, heap, &expr.to_type)); self.kv(indent2).with_s_key("Subject"); @@ -764,7 +764,7 @@ impl ASTWriter { self.kv(indent).with_id(PREFIX_CALL_EXPR_ID, expr.this.0.index) .with_s_key("CallExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); let definition = &heap[expr.procedure]; self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&false); @@ -786,7 +786,7 @@ impl ASTWriter { Expression::Variable(expr) => { self.kv(indent).with_id(PREFIX_VARIABLE_EXPR_ID, expr.this.0.index) .with_s_key("VariableExpr"); - self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition); + self.kv(indent2).with_s_key("TypeIndex").with_disp_val(&expr.type_index); self.kv(indent2).with_s_key("Name").with_identifier_val(&expr.identifier); self.kv(indent2).with_s_key("Definition") .with_opt_disp_val(expr.declaration.as_ref().map(|v| &v.index)); diff --git a/src/protocol/eval/executor.rs b/src/protocol/eval/executor.rs index 0adc2ab8e4b87ff2b35cf6bea6f6286f39e49683..a3ff4fdb1d881b97dd0aebbfe8115871e5a5f51c 100644 --- a/src/protocol/eval/executor.rs +++ b/src/protocol/eval/executor.rs @@ -28,6 +28,7 @@ pub(crate) enum ExprInstruction { pub(crate) struct Frame { pub(crate) definition: ProcedureDefinitionId, pub(crate) monomorph_type_id: TypeId, + pub(crate) monomorph_index: usize, pub(crate) position: StatementId, pub(crate) expr_stack: VecDeque, // hack for expression evaluation, evaluated by popping from back pub(crate) expr_values: VecDeque, // hack for expression results, evaluated by popping from front/back @@ -476,8 +477,8 @@ impl Prompt { }, Expression::Select(expr) => { let subject= cur_frame.expr_values.pop_back().unwrap(); - let mono_data = types.get_procedure_monomorph(cur_frame.monomorph_type_id); - let field_idx = mono_data.expr_data[expr.unique_id_in_definition as usize].field_or_monomorph_idx as u32; + let mono_data = &heap[cur_frame.definition].monomorphs[cur_frame.monomorph_index]; + let field_idx = mono_data.expr_info[expr.type_index as usize].variant.as_select() as u32; // Note: same as above: clone if value lives on expr stack, simply // refer to it if it already lives on the stack/heap. @@ -524,8 +525,9 @@ impl Prompt { } Literal::Integer(lit_value) => { use ConcreteTypePart as CTP; - let def_types = types.get_procedure_monomorph(cur_frame.monomorph_type_id); - let concrete_type = &def_types.expr_data[expr.unique_id_in_definition as usize].expr_type; + let mono_data = &heap[cur_frame.definition].monomorphs[cur_frame.monomorph_index]; + let type_id = mono_data.expr_info[expr.type_index as usize].type_id; + let concrete_type = &types.get_monomorph(type_id).concrete_type; debug_assert_eq!(concrete_type.parts.len(), 1); match concrete_type.parts[0] { @@ -572,14 +574,15 @@ impl Prompt { cur_frame.expr_values.push_back(value); }, Expression::Cast(expr) => { - let mono_data = types.get_procedure_monomorph(cur_frame.monomorph_type_id); - let output_type = &mono_data.expr_data[expr.unique_id_in_definition as usize].expr_type; + let mono_data = &heap[cur_frame.definition].monomorphs[cur_frame.monomorph_index]; + let type_id = mono_data.expr_info[expr.type_index as usize].type_id; + let concrete_type = &types.get_monomorph(type_id).concrete_type; // Typechecking reduced this to two cases: either we // have casting noop (same types), or we're casting // between integer/bool/char types. let subject = cur_frame.expr_values.pop_back().unwrap(); - match apply_casting(&mut self.store, output_type, &subject) { + match apply_casting(&mut self.store, concrete_type, &subject) { Ok(value) => cur_frame.expr_values.push_back(value), Err(msg) => { return Err(EvalError::new_error_at_expr(self, modules, heap, expr.this.upcast(), msg)); @@ -745,7 +748,7 @@ impl Prompt { debug_assert_eq!(heap[expr.procedure].parameters.len(), cur_frame.expr_values.len()); debug_assert_eq!(heap[cur_frame.position].as_new().expression, expr.this) }, - Method::UserProcedure => { + Method::UserFunction => { // Push a new frame. Note that all expressions have // been pushed to the front, so they're in the order // of the definition. @@ -763,11 +766,11 @@ impl Prompt { } // Determine the monomorph index of the function we're calling - let mono_data = types.get_procedure_monomorph(cur_frame.monomorph_type_id); - let call_data = &mono_data.expr_data[expr.unique_id_in_definition as usize]; + let mono_data = &heap[cur_frame.definition].monomorphs[cur_frame.monomorph_index]; + let type_id = mono_data.expr_info[expr.type_index as usize].variant.as_procedure().0; // Push the new frame and reserve its stack size - let new_frame = Frame::new(heap, expr.procedure, call_data.type_id); + let new_frame = Frame::new(heap, expr.procedure, type_id); let new_stack_size = new_frame.max_stack_size; self.frames.push(new_frame); self.store.cur_stack_boundary = new_stack_boundary; @@ -1025,8 +1028,8 @@ impl Prompt { "mismatch in expr stack size and number of arguments for new statement" ); - let mono_data = types.get_procedure_monomorph(cur_frame.monomorph_type_id); - let expr_data = &mono_data.expr_data[call_expr.unique_id_in_definition as usize]; + let mono_data = &heap[cur_frame.definition].monomorphs[cur_frame.monomorph_index]; + let type_id = mono_data.expr_info[expr.type_index as usize].variant.as_procedure().0; // Note that due to expression value evaluation they exist in // reverse order on the stack. @@ -1038,7 +1041,6 @@ impl Prompt { // Construct argument group, thereby copying heap regions let argument_group = ValueGroup::from_store(&self.store, &args); - // println!("Creating {} with\n{:#?}", heap[call_expr.definition].identifier().value.as_str(), argument_group); // Clear any heap regions for arg in &args { @@ -1047,7 +1049,7 @@ impl Prompt { cur_frame.position = stmt.next; - Ok(EvalContinuation::NewComponent(call_expr.procedure, expr_data.type_id, argument_group)) + Ok(EvalContinuation::NewComponent(call_expr.procedure, type_id, argument_group)) }, Statement::Expression(stmt) => { // The expression has just been completely evaluated. Some diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index 303d9ec425c5551f0e2a93ea8ba656fd2d27687a..8ce576bcfa720aef0e2e4d9701150fb216f14b7a 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -759,7 +759,7 @@ impl PassDefinitions { if let Expression::Call(expression) = expression { // Allow both components and functions, as it makes more sense to // check their correct use in the validation and linking pass - if expression.method == Method::UserComponent || expression.method == Method::UserProcedure { + if expression.method == Method::UserComponent || expression.method == Method::UserFunction { call_id = expression.this; valid = true; } @@ -924,7 +924,7 @@ impl PassDefinitions { declaration: Some(local_id), used_as_binding_target: false, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); let assignment_expr_id = ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{ this, @@ -934,7 +934,7 @@ impl PassDefinitions { operation: AssignmentOperator::Set, right: initial_expr_id, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); // Put both together in the memory statement @@ -1029,7 +1029,7 @@ impl PassDefinitions { Ok(ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{ this, operator_span, full_span, left, operation, right, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast()) } else { Ok(expr) @@ -1057,7 +1057,7 @@ impl PassDefinitions { Ok(ctx.heap.alloc_conditional_expression(|this| ConditionalExpression{ this, operator_span, full_span, test, true_expression, false_expression, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast()) } else { Ok(result) @@ -1242,7 +1242,7 @@ impl PassDefinitions { Ok(ctx.heap.alloc_unary_expression(|this| UnaryExpression { this, operator_span, full_span, operation, expression, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast()) } else if next == Some(TokenKind::PlusPlus) { return Err(ParseError::new_error_str_at_span( @@ -1306,7 +1306,7 @@ impl PassDefinitions { slicing_span: operator_span, full_span, subject, from_index, to_index, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast(); } else if Some(TokenKind::CloseSquare) == next { let end_span = consume_token(&module.source, iter, TokenKind::CloseSquare)?; @@ -1320,7 +1320,7 @@ impl PassDefinitions { this, operator_span, full_span, subject, index: from_index, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast(); } else { return Err(ParseError::new_error_str_at_pos( @@ -1361,7 +1361,7 @@ impl PassDefinitions { this, operator_span, full_span, subject, kind: select_kind, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast(); } @@ -1397,7 +1397,7 @@ impl PassDefinitions { span: InputSpan::from_positions(open_paren_pos, close_paren_pos), value: Literal::Tuple(Vec::new()), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); literal_id.upcast() @@ -1423,7 +1423,7 @@ impl PassDefinitions { span: InputSpan::from_positions(open_paren_pos, close_paren_pos), value: Literal::Tuple(scoped_section.into_vec()), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); literal_id.upcast() @@ -1451,7 +1451,7 @@ impl PassDefinitions { span: InputSpan::from_positions(start_pos, end_pos), value: Literal::Array(scoped_section.into_vec()), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if next == Some(TokenKind::Integer) { let (literal, span) = consume_integer_literal(&module.source, iter, &mut self.buffer)?; @@ -1460,7 +1460,7 @@ impl PassDefinitions { this, span, value: Literal::Integer(LiteralInteger{ unsigned_value: literal, negated: false }), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if next == Some(TokenKind::String) { let span = consume_string_literal(&module.source, iter, &mut self.buffer)?; @@ -1470,7 +1470,7 @@ impl PassDefinitions { this, span, value: Literal::String(interned), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if next == Some(TokenKind::Character) { let (character, span) = consume_character_literal(&module.source, iter)?; @@ -1479,7 +1479,7 @@ impl PassDefinitions { this, span, value: Literal::Character(character), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if next == Some(TokenKind::Ident) { // May be a variable, a type instantiation or a function call. If we @@ -1531,7 +1531,7 @@ impl PassDefinitions { definition: target_definition_id, }), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() }, Definition::Enum(_) => { @@ -1549,7 +1549,7 @@ impl PassDefinitions { variant_idx: 0 }), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() }, Definition::Union(_) => { @@ -1574,7 +1574,7 @@ impl PassDefinitions { variant_idx: 0, }), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() }, Definition::Procedure(proc_def) => { @@ -1592,7 +1592,7 @@ impl PassDefinitions { _ => unreachable!(), } } else if proc_def.kind == ProcedureKind::Function { - Method::UserProcedure + Method::UserFunction } else { Method::UserComponent }; @@ -1608,7 +1608,7 @@ impl PassDefinitions { this, func_span, full_span, parser_type, method, arguments, procedure: procedure_id, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } } @@ -1637,7 +1637,7 @@ impl PassDefinitions { span: ident_span, value, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if ident_text == KW_LET { // Binding expression @@ -1655,7 +1655,7 @@ impl PassDefinitions { ctx.heap.alloc_binding_expression(|this| BindingExpression{ this, operator_span, full_span, bound_to, bound_from, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else if ident_text == KW_CAST { // Casting expression @@ -1692,7 +1692,7 @@ impl PassDefinitions { cast_span: to_type.full_span, full_span, to_type, subject, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } else { // Not a builtin literal, but also not a known type. So we @@ -1727,7 +1727,7 @@ impl PassDefinitions { declaration: None, used_as_binding_target: false, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast() } } @@ -1767,7 +1767,7 @@ impl PassDefinitions { result = ctx.heap.alloc_binary_expression(|this| BinaryExpression{ this, operator_span, full_span, left, operation, right, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }).upcast(); } diff --git a/src/protocol/parser/pass_rewriting.rs b/src/protocol/parser/pass_rewriting.rs index 640f4cf286afc7a09790dae0f3539cb163000cb5..724f9d0c42354424329169b1510e4520b4720c19 100644 --- a/src/protocol/parser/pass_rewriting.rs +++ b/src/protocol/parser/pass_rewriting.rs @@ -308,7 +308,6 @@ impl PassRewriting { arguments, procedure: ProcedureDefinitionId::new_invalid(), parent: ExpressionParent::None, - unique_id_in_definition: -1, }); let call_stmt_id = ctx.heap.alloc_expression_statement(|this| ExpressionStatement{ this, @@ -353,7 +352,7 @@ fn create_ast_variable_expr(ctx: &mut Ctx, variable_id: VariableId) -> VariableE declaration: Some(variable_id), used_as_binding_target: false, parent: ExpressionParent::None, - unique_id_in_definition: -1 + type_index: -1 }); } @@ -371,7 +370,7 @@ fn create_ast_call_expr(ctx: &mut Ctx, method: Method, buffer: &mut ScopedBuffer arguments, procedure: ProcedureDefinitionId::new_invalid(), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); for argument_index in 0..expression_ids.len() { @@ -392,7 +391,7 @@ fn create_ast_literal_integer_expr(ctx: &mut Ctx, unsigned_value: u64) -> Litera negated: false, }), parent: ExpressionParent::None, - unique_id_in_definition: -1 + type_index: -1 }); } @@ -407,7 +406,7 @@ fn create_ast_equality_comparison_expr(ctx: &mut Ctx, variable_id: VariableId, v operation: BinaryOperator::Equality, right: int_expr_id.upcast(), parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); let var_expr = &mut ctx.heap[var_expr_id]; @@ -443,7 +442,7 @@ fn create_ast_variable_declaration_stmt(ctx: &mut Ctx, variable_id: VariableId, operation: AssignmentOperator::Set, right: initial_value_expr_id, parent: ExpressionParent::None, - unique_id_in_definition: -1, + type_index: -1, }); // Create the memory statement diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 8b33f76bb65bc6a3f0045dd34d282ffd36f9301c..4015356be244b9435be552673f0d20939e9d7e64 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -817,18 +817,32 @@ pub(crate) struct ResolveQueueElement { pub(crate) root_id: RootId, pub(crate) definition_id: DefinitionId, pub(crate) reserved_type_id: TypeId, + pub(crate) reserved_monomorph_index: u32, } pub(crate) type ResolveQueue = Vec; struct InferenceNode { - expr_type: InferenceType, // result type from expression - expr_id: ExpressionId, // expression that is evaluated - inference_rule: InferenceRule, - parent_index: Option, - field_or_monomorph_index: i32, // index of field - poly_data_index: PolyDataIndex, // index of extra data needed for inference - type_id: TypeId, // when applicable indexes into type table + // filled in during type inference + expr_type: InferenceType, // result type from expression + expr_id: ExpressionId, // expression that is evaluated + inference_rule: InferenceRule, // rule used to infer node type + parent_index: Option, // parent of inference node + field_index: i32, // index of struct field or tuple member + poly_data_index: PolyDataIndex, // index to inference data for polymorphic types + // filled in once type inference is done + info_type_id: TypeId, + info_variant: ExpressionInfoVariant, +} + +impl InferenceNode { + #[inline] + fn as_expression_info(&self) -> ExpressionInfo { + return ExpressionInfo { + type_id: self.info_type_id, + variant: self.info_variant + } + } } /// Inferencing rule to apply. Some of these are reasonably generic. Other ones @@ -1000,6 +1014,7 @@ struct InferenceRuleVariableExpr { pub(crate) struct PassTyping { // Current definition we're typechecking. reserved_type_id: TypeId, + reserved_monomorph_index: u32, procedure_id: ProcedureDefinitionId, procedure_kind: ProcedureKind, poly_vars: Vec, @@ -1079,6 +1094,7 @@ impl PassTyping { pub(crate) fn new() -> Self { PassTyping { reserved_type_id: TypeId::new_invalid(), + reserved_monomorph_index: u32::MAX, procedure_id: ProcedureDefinitionId::new_invalid(), procedure_kind: ProcedureKind::Function, poly_vars: Vec::new(), @@ -1103,13 +1119,13 @@ impl PassTyping { for definition_id in &root.definitions { let definition = &ctx.heap[*definition_id]; - let first_concrete_part = match definition { + let first_concrete_part_and_procedure_id = match definition { Definition::Procedure(definition) => { if definition.poly_vars.is_empty() { if definition.kind == ProcedureKind::Function { - Some(ConcreteTypePart::Function(definition.this, 0)) + Some((ConcreteTypePart::Function(definition.this, 0), definition.this)) } else { - Some(ConcreteTypePart::Component(definition.this, 0)) + Some((ConcreteTypePart::Component(definition.this, 0), definition.this)) } } else { None @@ -1118,13 +1134,18 @@ impl PassTyping { Definition::Enum(_) | Definition::Struct(_) | Definition::Union(_) => None, }; - if let Some(first_concrete_part) = first_concrete_part { + if let Some((first_concrete_part, procedure_id)) = first_concrete_part_and_procedure_id { + let procedure = &mut ctx.heap[procedure_id]; + let monomorph_index = procedure.monomorphs.len() as u32; + procedure.monomorphs.push(ProcedureDefinitionMonomorph::new_invalid()); + let concrete_type = ConcreteType{ parts: vec![first_concrete_part] }; - let type_id = ctx.types.reserve_procedure_monomorph_type_id(definition_id, concrete_type); + let type_id = ctx.types.reserve_procedure_monomorph_type_id(definition_id, concrete_type, monomorph_index); queue.push(ResolveQueueElement{ root_id, definition_id: *definition_id, reserved_type_id: type_id, + reserved_monomorph_index: monomorph_index, }) } } @@ -1139,6 +1160,7 @@ impl PassTyping { // Prepare for visiting the definition self.reserved_type_id = element.reserved_type_id; + self.reserved_monomorph_index = element.reserved_monomorph_index; let proc_base = ctx.types.get_base_definition(&element.definition_id).unwrap(); if proc_base.is_polymorph { @@ -1825,7 +1847,7 @@ impl PassTyping { // By default we set the polymorph idx for calls to 0. If the call // refers to a non-polymorphic function, then it will be "monomorphed" // once, hence we end up pointing to the correct instance. - self.infer_nodes[self_index].field_or_monomorph_index = 0; + self.infer_nodes[self_index].field_index = 0; // Visit all arguments let old_parent = self.parent_index.replace(self_index); @@ -1909,9 +1931,8 @@ impl PassTyping { impl PassTyping { #[allow(dead_code)] // used when debug flag at the top of this file is true. - fn debug_get_display_name(&self, ctx: &Ctx, expr_id: ExpressionId) -> String { - let expr_idx = ctx.heap[expr_id].get_unique_id_in_definition(); - let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; + fn debug_get_display_name(&self, ctx: &Ctx, node_index: InferNodeIndex) -> String { + let expr_type = &self.infer_nodes[node_index].expr_type; expr_type.display_name(&ctx.heap) } @@ -1944,13 +1965,13 @@ impl PassTyping { // Helper for transferring polymorphic variables to concrete types and // checking if they're completely specified - fn inference_type_to_concrete_type( - ctx: &Ctx, expr_id: ExpressionId, inference: &Vec, + fn poly_data_type_to_concrete_type( + ctx: &Ctx, expr_id: ExpressionId, inference_poly_args: &Vec, first_concrete_part: ConcreteTypePart, ) -> Result { // Prepare storage vector let mut num_inference_parts = 0; - for inference_type in inference { + for inference_type in inference_poly_args { num_inference_parts += inference_type.parts.len(); } @@ -1961,7 +1982,7 @@ impl PassTyping { // Go through all polymorphic arguments and add them to the concrete // types. - for (poly_idx, poly_type) in inference.iter().enumerate() { + for (poly_idx, poly_type) in inference_poly_args.iter().enumerate() { if !poly_type.is_done { let expr = &ctx.heap[expr_id]; let definition = match expr { @@ -1989,97 +2010,81 @@ impl PassTyping { Ok(concrete_type) } - // 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]; - return Err(ParseError::new_error_at_span( - &ctx.module().source, expr.full_span(), format!( - "could not fully infer the type of this expression (got '{}')", - infer_expr.expr_type.display_name(&ctx.heap) - ) - )); - } - - // Expression is fine, check if any extra data is attached - if infer_expr.poly_data_index < 0 { continue; } - let poly_data = &self.poly_data[infer_expr.poly_data_index as usize]; - - // Note that only call and literal expressions need full inference. - // Select expressions also use `extra_data`, but only for temporary - // storage of the struct type whose field it is selecting. - match &ctx.heap[infer_expr.expr_id] { - Expression::Call(expr) => { - // Check if it is not a builtin function. If not, then - // construct the first part of the concrete type. - let first_concrete_part = if expr.method == Method::UserProcedure { - ConcreteTypePart::Function(expr.procedure, poly_data.poly_vars.len() as u32) - } else if expr.method == Method::UserComponent { - ConcreteTypePart::Component(expr.procedure, poly_data.poly_vars.len() as u32) - } else { - // Builtin function - continue; - }; - - let definition_id = expr.procedure.upcast(); - let concrete_type = inference_type_to_concrete_type( - ctx, infer_expr.expr_id, &poly_data.poly_vars, first_concrete_part - )?; - - match ctx.types.get_procedure_monomorph_type_id(&definition_id, &concrete_type.parts) { - Some(type_id) => { - // Already typechecked, or already put into the resolve queue - infer_expr.type_id = type_id; - }, - None => { - // Not typechecked yet, so add an entry in the queue - let reserved_type_id = ctx.types.reserve_procedure_monomorph_type_id(&definition_id, concrete_type); - infer_expr.type_id = reserved_type_id; - queue.push(ResolveQueueElement { - root_id: ctx.heap[definition_id].defined_in(), - definition_id, - reserved_type_id, - }); - } - } - }, - Expression::Literal(expr) => { - let definition_id = match &expr.value { - Literal::Enum(lit) => lit.definition, - Literal::Union(lit) => lit.definition, - Literal::Struct(lit) => lit.definition, - _ => unreachable!(), - }; - let first_concrete_part = ConcreteTypePart::Instance(definition_id, poly_data.poly_vars.len() as u32); - 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, concrete_type)?; - infer_expr.type_id = type_id; - }, - Expression::Select(_) => { - debug_assert!(infer_expr.field_or_monomorph_index >= 0); - }, - _ => { - unreachable!("handling extra data for expression {:?}", &ctx.heap[infer_expr.expr_id]); - } - } - } - // Every expression checked, and new monomorphs are queued. Transfer the // 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 procedure = &ctx.heap[self.procedure_id]; + let num_infer_nodes = self.infer_nodes().len(); let mut monomorph = ProcedureDefinitionMonomorph{ argument_types: Vec::with_capacity(procedure.parameters.len()), - expr_info: Vec::with_capacity(self.infer_nodes().len()), // TODO: Initial reservation + expr_info: Vec::with_capacity(num_infer_nodes), }; - // - Write the arguments + // For all of the expressions look up the TypeId (or create a new one). + // For function calls and component instantiations figure out if they + // need to be typechecked + for infer_node in self.infer_nodes.iter_mut() { + // Determine type ID + let expr = &ctx.heap[infer_node.expr_id]; + let poly_data = &self.poly_data[infer_node.poly_data_index as usize]; + + // TODO: Maybe optimize? Split insertion up into lookup, then clone + // if needed? + let mut concrete_type = ConcreteType::default(); + infer_node.expr_type.write_concrete_type(&mut concrete_type); + let info_type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, concrete_type)?; + + // Determine procedure type ID, i.e. a called/instantiated + // procedure's signature. + let info_variant = if let Expression::Call(expr) = expr { + // Construct full function type. If not yet typechecked then + // queue it for typechecking. + debug_assert!(expr.method.is_user_defined() || expr.method.is_public_builtin()); + let num_poly_vars = poly_data.poly_vars.len() as u32; + let first_part = match expr.method { + Method::UserFunction => ConcreteTypePart::Function(expr.procedure, num_poly_vars), + Method::UserComponent => ConcreteTypePart::Component(expr.procedure, num_poly_vars), + _ => ConcreteTypePart::Function(expr.procedure, num_poly_vars), + }; + + + let definition_id = expr.procedure.upcast(); + let signature_type = poly_data_type_to_concrete_type( + ctx, infer_node.expr_id, &poly_data.poly_vars, first_part + )?; + + let (type_id, monomorph_index) = if let Some(type_id) = ctx.types.get_procedure_monomorph_type_id(&definition_id, &signature_type.parts) { + // Procedure is already typechecked + let monomorph_index = ctx.types.get_monomorph(type_id).variant.as_procedure().monomorph_index; + (type_id, monomorph_index) + } else { + // Procedure is not yet typechecked, reserve a TypeID and a monomorph index + let procedure_to_check = &mut ctx.heap[expr.procedure]; + let monomorph_index = procedure_to_check.monomorphs.len() as u32; + procedure_to_check.monomorphs.push(ProcedureDefinitionMonomorph::new_invalid()); + let type_id = ctx.types.reserve_procedure_monomorph_type_id(&definition_id, signature_type, monomorph_index); + queue.push(ResolveQueueElement{ + root_id: ctx.heap[definition_id].defined_in(), + definition_id, + reserved_type_id: type_id, + reserved_monomorph_index: monomorph_index, + }); + + (type_id, monomorph_index) + }; + + ExpressionInfoVariant::Procedure(type_id, monomorph_index) + } else if let Expression::Select(expr) = expr { + ExpressionInfoVariant::Select(infer_node.field_index) + } else { + ExpressionInfoVariant::Generic + }; + + infer_node.info_type_id = info_type_id; + infer_node.info_variant = info_variant; + } + + // Write the types of 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 == parameter_id).unwrap(); @@ -2088,21 +2093,29 @@ impl PassTyping { monomorph.argument_types.push(type_id) } - for infer_node in self.infer_nodes.iter() { - let expr = &ctx.heap[infer_node.expr_id]; + // Determine if we have already assigned type indices to the expressions + // before (the indices that, for a monomorph, can retrieve the type of + // the expression). + let has_type_indices = self.reserved_monomorph_index == 0; + if has_type_indices { + // already have indices, so resize and then index into it + monomorph.expr_info.resize_with(num_infer_nodes, ExpressionInfo::new_invalid()); + for infer_node in self.infer_nodes.iter() { + let type_index = ctx.heap[infer_node.expr_id].type_index(); + monomorph.expr_info[type_index as usize] = infer_node.as_expression_info(); + } + } else { + // no indices yet, need to be assigned in AST + for infer_node in self.infer_nodes.iter() { + let type_index = monomorph.expr_info.len(); + monomorph.expr_info.push(infer_node.as_expression_info()); + *ctx.heap[infer_node.expr_id].type_index_mut() = type_index as i32; + } } - // - Write the expression data - target.expr_data.reserve(self.infer_nodes.len()); - for infer_expr in self.infer_nodes.iter() { - let mut concrete = ConcreteType::default(); - infer_expr.expr_type.write_concrete_type(&mut concrete); - target.expr_data.push(MonomorphExpression{ - expr_type: concrete, - field_or_monomorph_idx: infer_expr.field_or_monomorph_index, - type_id: infer_expr.type_id, - }); - } + // Push the information into the AST + let procedure = &mut ctx.heap[self.procedure_id]; + procedure.monomorphs[self.reserved_monomorph_index as usize] = monomorph; Ok(()) } @@ -2361,7 +2374,7 @@ impl PassTyping { return Ok(None); } - if node.field_or_monomorph_index < 0 { + if node.field_index < 0 { // Don't know the subject definition, hence the field yet. Try to // determine it. let subject_node = &self.infer_nodes[subject_index]; @@ -2388,7 +2401,7 @@ impl PassTyping { // Found the field of interest field_found = true; let node = &mut self.infer_nodes[node_index]; - node.field_or_monomorph_index = field_index as i32; + node.field_index = field_index as i32; break; } } @@ -2462,7 +2475,7 @@ impl PassTyping { let subject_index = rule.subject_index; let tuple_member_index = rule.selected_index; - if node.field_or_monomorph_index < 0 { + if node.field_index < 0 { let subject_type = &self.infer_nodes[subject_index].expr_type; let tuple_size = get_tuple_size_from_inference_type(subject_type); let tuple_size = match tuple_size { @@ -2498,7 +2511,7 @@ impl PassTyping { // Within bounds, set index on the type inference node let node = &mut self.infer_nodes[node_index]; - node.field_or_monomorph_index = tuple_member_index as i32; + node.field_index = tuple_member_index as i32; } // If here then we know we can use `tuple_member_index`. We need to keep @@ -3402,9 +3415,10 @@ impl PassTyping { expr_id, inference_rule: InferenceRule::Noop, parent_index: self.parent_index, - field_or_monomorph_index: -1, + field_index: -1, poly_data_index: -1, - type_id: TypeId::new_invalid(), + info_type_id: TypeId::new_invalid(), + info_variant: ExpressionInfoVariant::Generic, }); return Ok(infer_index); @@ -3654,7 +3668,7 @@ impl PassTyping { let definition = ctx.heap[struct_def_id].as_struct(); let node = &self.infer_nodes[node_index]; - let field_index = node.field_or_monomorph_index as usize; + let field_index = node.field_index as usize; // Generate initial polyvar types and struct type // TODO: @Performance: we can immediately set the polyvars of the subject's struct type diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index e810ad3b936071042027a5b2409a30d75b7775fe..27e54b7192d2d66775b95d2c5474e1d3dad0316d 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -94,7 +94,6 @@ pub(crate) struct PassValidationLinking { must_be_assignable: Option, // Keeping track of relative positions and unique IDs. relative_pos_in_parent: i32, // of statements: to determine when variables are visible - next_expr_index: i32, // to arrive at a unique ID for all expressions within a definition // Control flow statements that require label resolving control_flow_stmts: Vec, // Various temporary buffers for traversal. Essentially working around @@ -625,7 +624,6 @@ impl Visitor for PassValidationLinking { let right_expr_id = assignment_expr.right; let old_expr_parent = self.expr_parent; assignment_expr.parent = old_expr_parent; - assignment_expr.unique_id_in_definition = self.next_expr_index; self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); @@ -715,8 +713,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; binding_expr.parent = old_expr_parent; - binding_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.in_binding_expr = id; // Perform preliminary check on children: binding expressions only make @@ -770,8 +766,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; conditional_expr.parent = old_expr_parent; - conditional_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); self.visit_expr(ctx, test_expr_id)?; @@ -799,8 +793,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; binary_expr.parent = old_expr_parent; - binary_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); self.visit_expr(ctx, left_expr_id)?; @@ -823,8 +815,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; unary_expr.parent = old_expr_parent; - unary_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(id.upcast(), 0); self.visit_expr(ctx, expr_id)?; @@ -842,8 +832,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; indexing_expr.parent = old_expr_parent; - indexing_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); self.visit_expr(ctx, subject_expr_id)?; @@ -875,8 +863,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; slicing_expr.parent = old_expr_parent; - slicing_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); self.visit_expr(ctx, subject_expr_id)?; @@ -899,8 +885,6 @@ impl Visitor for PassValidationLinking { let old_expr_parent = self.expr_parent; select_expr.parent = old_expr_parent; - select_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(id.upcast(), 0); self.visit_expr(ctx, expr_id)?; @@ -913,8 +897,6 @@ impl Visitor for PassValidationLinking { let literal_expr = &mut ctx.heap[id]; let old_expr_parent = self.expr_parent; literal_expr.parent = old_expr_parent; - literal_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; if let Some(span) = self.must_be_assignable { return Err(ParseError::new_error_str_at_span( @@ -1112,8 +1094,6 @@ impl Visitor for PassValidationLinking { let upcast_id = id.upcast(); let old_expr_parent = self.expr_parent; cast_expr.parent = old_expr_parent; - cast_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; // Recurse into the thing that we're casting self.expr_parent = ExpressionParent::Expression(upcast_id, 0); @@ -1184,7 +1164,7 @@ impl Visitor for PassValidationLinking { Method::SelectStart | Method::SelectRegisterCasePort | Method::SelectWait => unreachable!(), // not usable by programmer directly - Method::UserProcedure => {} + Method::UserFunction => {} Method::UserComponent => { expecting_wrapping_new_stmt = true; }, @@ -1271,8 +1251,6 @@ impl Visitor for PassValidationLinking { let section = self.expression_buffer.start_section_initialized(&call_expr.arguments); let old_expr_parent = self.expr_parent; call_expr.parent = old_expr_parent; - call_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; for arg_expr_idx in 0..section.len() { let arg_expr_id = section[arg_expr_idx]; @@ -1392,8 +1370,6 @@ impl Visitor for PassValidationLinking { var_expr.declaration = Some(variable_id); var_expr.used_as_binding_target = is_binding_target; var_expr.parent = self.expr_parent; - var_expr.unique_id_in_definition = self.next_expr_index; - self.next_expr_index += 1; Ok(()) } diff --git a/src/protocol/parser/type_table.rs b/src/protocol/parser/type_table.rs index 297eff27cdf56ffe75d1182fa356e24f186ec1f8..08f9a12d4ccb7e7a19b92190a7da7c2ae10e7fe4 100644 --- a/src/protocol/parser/type_table.rs +++ b/src/protocol/parser/type_table.rs @@ -228,7 +228,7 @@ impl MonoTypeVariant { } } - fn as_procedure(&self) -> &ProcedureMonomorph { + pub(crate) fn as_procedure(&self) -> &ProcedureMonomorph { match self { MonoTypeVariant::Procedure(v) => v, _ => unreachable!(), @@ -292,9 +292,7 @@ pub struct UnionMonomorphEmbedded { /// Procedure (functions and components of all possible types) monomorph. Also /// stores the expression type data from the typechecking/inferencing pass. pub struct ProcedureMonomorph { - // Expression data for one particular monomorph - pub arg_types: Vec, - pub expr_data: Vec, + pub monomorph_index: u32, } /// Tuple monomorph. Again a kind of exception because one cannot define a named @@ -704,7 +702,7 @@ impl TypeTable { /// monomorph may NOT exist yet (because the reservation implies that we're /// going to be performing typechecking on it, and we don't want to /// check the same monomorph twice) - pub(crate) fn reserve_procedure_monomorph_type_id(&mut self, definition_id: &DefinitionId, concrete_type: ConcreteType) -> TypeId { + pub(crate) fn reserve_procedure_monomorph_type_id(&mut self, definition_id: &DefinitionId, concrete_type: ConcreteType, monomorph_index: u32) -> TypeId { debug_assert_eq!(get_concrete_type_definition(&concrete_type.parts).unwrap(), *definition_id); let type_id = TypeId(self.mono_types.len() as i64); let base_type = self.definition_lookup.get_mut(definition_id).unwrap(); @@ -713,8 +711,7 @@ impl TypeTable { debug_assert!(!self.mono_type_lookup.contains_key(&self.mono_search_key)); self.mono_type_lookup.insert(self.mono_search_key.clone(), type_id); self.mono_types.push(MonoType::new_empty(type_id, concrete_type, MonoTypeVariant::Procedure(ProcedureMonomorph{ - arg_types: Vec::new(), - expr_data: Vec::new(), + monomorph_index, }))); return type_id; diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index 802e5625a6ccb1640a5a36cea919568fada4d3d7..c39dedfc5eeac57e4908f14b69524ce22b87bbd3 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -748,8 +748,11 @@ impl<'a> VariableTester<'a> { pub(crate) fn assert_concrete_type(self, expected: &str) -> Self { // Lookup concrete type in type table - let mono_data = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); - let concrete_type = &mono_data.expr_data[self.var_expr.unique_id_in_definition as usize].expr_type; + let mono_proc = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); + let mono_index = mono_proc.monomorph_index; + let mono_data = &self.ctx.heap[self.definition_id].as_procedure().monomorphs[mono_index as usize]; + let expr_info = &mono_data.expr_info[self.var_expr.type_index as usize]; + let concrete_type = &self.ctx.types.get_monomorph(expr_info.type_id).concrete_type; // Serialize and check let serialized = concrete_type.display_name(self.ctx.heap); @@ -782,9 +785,11 @@ impl<'a> ExpressionTester<'a> { pub(crate) fn assert_concrete_type(self, expected: &str) -> Self { // Lookup concrete type - let mono_data = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); - let expr_index = self.expr.get_unique_id_in_definition(); - let concrete_type = &mono_data.expr_data[expr_index as usize].expr_type; + let mono_proc = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); + let mono_index = mono_proc.monomorph_index; + let mono_data = &self.ctx.heap[self.definition_id].as_procedure().monomorphs[mono_index as usize]; + let expr_info = &mono_data.expr_info[self.var_expr.type_index as usize]; + let concrete_type = &self.ctx.types.get_monomorph(expr_info.type_id).concrete_type; // Serialize and check type let serialized = concrete_type.display_name(self.ctx.heap);