diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 17686469649a7f39d1834d2ebef80e4824512e2e..ac535c5c199153d28754234af77a9b7fb19a89fd 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -837,19 +837,21 @@ pub(crate) struct ResolveQueueElement { pub(crate) type ResolveQueue = Vec; #[derive(Clone)] -struct InferenceExpression { +struct InferenceNode { expr_type: InferenceType, // result type from expression expr_id: ExpressionId, // expression that is evaluated + inference_rule: InferenceRule, field_or_monomorph_idx: i32, // index of field extra_data_idx: i32, // index of extra data needed for inference type_id: TypeId, // when applicable indexes into type table } -impl Default for InferenceExpression { +impl Default for InferenceNode { fn default() -> Self { Self{ expr_type: InferenceType::default(), expr_id: ExpressionId::new_invalid(), + inference_rule: InferenceRule::Noop, field_or_monomorph_idx: -1, extra_data_idx: -1, type_id: TypeId::new_invalid(), @@ -857,6 +859,102 @@ impl Default for InferenceExpression { } } +/// Inferencing rule to apply. Some of these are reasonably generic. Other ones +/// require so much custom logic that we'll not try to come up with an +/// abstraction. +enum InferenceRule { + Noop, + MonoTemplate(InferenceRuleTemplate), + BiEqual(InferenceRuleBiEqual), + TriEqualArgs(InferenceRuleTriEqualArgs), + TriEqualAll(InferenceRuleTriEqualAll), + Concatenate(InferenceRuleTwoArgs), + IndexingExpr(InferenceRuleIndexingExpr), + SlicingExpr(InferenceRuleSlicingExpr), + SelectExpr(InferenceRuleSelectExpr), + LiteralStruct, + LiteralEnum, + LiteralUnion, + LiteralArray, + LiteralTuple, + CastExpr, + CallExpr, + VariableExpr, +} + +struct InferenceRuleTemplate { + template: &'static [InferenceTypePart], + application: InferenceRuleTemplateApplication, +} + +impl InferenceRuleTemplate { + fn new_none() -> Self { + return Self{ + template: &[], + application: InferenceRuleTemplateApplication::None, + }; + } + + fn new_forced(template: &'static [InferenceTypePart]) -> Self { + return Self{ + template, + application: InferenceRuleTemplateApplication::Forced, + }; + } + + fn new_template(template: &'static [InferenceTypePart]) -> Self { + return Self{ + template, + application: InferenceRuleTemplateApplication::Template, + } + } +} + +enum InferenceRuleTemplateApplication { + None, // do not apply template, silly, but saves some bytes + Forced, + Template, +} + +struct InferenceRuleBiEqual { + template: InferenceRuleTemplate, + argument_index: InferIndex, +} + +struct InferenceRuleTriEqualArgs { + argument_template: InferenceRuleTemplate, + result_template: InferenceRuleTemplate, + argument1_index: InferIndex, + argument2_index: InferIndex, +} + +struct InferenceRuleTriEqualAll { + template: InferenceRuleTemplate, + argument1_index: InferIndex, + argument2_index: InferIndex, +} + +// generic two-argument (excluding expression itself) inference rule arguments +struct InferenceRuleTwoArgs { + argument1_index: InferIndex, + argument2_index: InferIndex, +} + +struct InferenceRuleIndexingExpr { + subject_index: InferIndex, + index_index: InferIndex, +} + +struct InferenceRuleSlicingExpr { + subject_index: InferIndex, + from_index: InferIndex, + to_index: InferIndex, +} + +struct InferenceRuleSelectExpr { + subject_index: InferIndex, +} + /// This particular visitor will recurse depth-first into the AST and ensures /// that all expressions have the appropriate types. pub(crate) struct PassTyping { @@ -872,7 +970,7 @@ pub(crate) struct PassTyping { // Mapping from parser type to inferred type. We attempt to continue to // specify these types until we're stuck or we've fully determined the type. var_types: HashMap, // types of variables - expr_types: Vec, // will be transferred to type table at end + infer_nodes: Vec, // will be transferred to type table at end extra_data: Vec, // data for polymorph inference // Keeping track of which expressions need to be reinferred because the // expressions they're linked to made progression on an associated type @@ -933,7 +1031,7 @@ impl PassTyping { stmt_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAP_LARGE), bool_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAP_SMALL), var_types: HashMap::new(), - expr_types: Vec::new(), + infer_nodes: Vec::new(), extra_data: Vec::new(), expr_queued: DequeSet::new(), } @@ -1006,7 +1104,7 @@ impl PassTyping { self.definition_type = DefinitionType::Function(FunctionDefinitionId::new_invalid()); self.poly_vars.clear(); self.var_types.clear(); - self.expr_types.clear(); + self.infer_nodes.clear(); self.extra_data.clear(); self.expr_queued.clear(); } @@ -1017,7 +1115,7 @@ impl PassTyping { // ----------------------------------------------------------------------------- type VisitorResult = Result<(), ParseError>; -type VisitStmtResult = Result<> +type VisitExprResult = Result; impl PassTyping { // Definitions @@ -1041,8 +1139,8 @@ impl PassTyping { debug_log!("{}", "-".repeat(50)); // Reserve data for expression types - debug_assert!(self.expr_types.is_empty()); - self.expr_types.resize(comp_def.num_expressions_in_body as usize, Default::default()); + debug_assert!(self.infer_nodes.is_empty()); + self.infer_nodes.resize(comp_def.num_expressions_in_body as usize, Default::default()); // Visit parameters let section = self.var_buffer.start_section_initialized(comp_def.parameters.as_slice()); @@ -1081,8 +1179,8 @@ impl PassTyping { debug_log!("{}", "-".repeat(50)); // Reserve data for expression types - debug_assert!(self.expr_types.is_empty()); - self.expr_types.resize(func_def.num_expressions_in_body as usize, Default::default()); + debug_assert!(self.infer_nodes.is_empty()); + self.infer_nodes.resize(func_def.num_expressions_in_body as usize, Default::default()); // Visit parameters let section = self.var_buffer.start_section_initialized(func_def.parameters.as_slice()); @@ -1237,7 +1335,8 @@ impl PassTyping { debug_assert_eq!(return_stmt.expressions.len(), 1); let expr_id = return_stmt.expressions[0]; - self.visit_expr(ctx, expr_id) + self.visit_expr(ctx, expr_id)?; + return Ok(()); } fn visit_goto_stmt(&mut self, _: &mut Ctx, _: GotoStatementId) -> VisitorResult { return Ok(()) } @@ -1246,53 +1345,86 @@ impl PassTyping { let new_stmt = &ctx.heap[id]; let call_expr_id = new_stmt.expression; - self.visit_call_expr(ctx, call_expr_id) + self.visit_call_expr(ctx, call_expr_id)?; + return Ok(()); } fn visit_expr_stmt(&mut self, ctx: &mut Ctx, id: ExpressionStatementId) -> VisitorResult { let expr_stmt = &ctx.heap[id]; let subexpr_id = expr_stmt.expression; - self.visit_expr(ctx, subexpr_id) + self.visit_expr(ctx, subexpr_id)?; + return Ok(()); } // Expressions - fn visit_expr(&mut self, ctx: &mut Ctx, id: ExpressionId) -> VisitorResult { + fn visit_expr(&mut self, ctx: &mut Ctx, id: ExpressionId) -> VisitExprResult { return visitor_recursive_expression_impl!(self, &ctx.heap[id], ctx); } - fn visit_assignment_expr(&mut self, ctx: &mut Ctx, id: AssignmentExpressionId) -> VisitorResult { + fn visit_assignment_expr(&mut self, ctx: &mut Ctx, id: AssignmentExpressionId) -> VisitExprResult { + use AssignmentOperator as AO; + let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let assign_expr = &ctx.heap[id]; + let assign_op = assign_expr.operation; let left_expr_id = assign_expr.left; let right_expr_id = assign_expr.right; - self.visit_expr(ctx, left_expr_id)?; - self.visit_expr(ctx, right_expr_id)?; + let left_index = self.visit_expr(ctx, left_expr_id)?; + let right_index = self.visit_expr(ctx, right_expr_id)?; + + let node = &mut self.infer_nodes[self_index]; + let argument_template = match assign_op { + AO::Set => + InferenceRuleTemplate::new_none(), + AO::Concatenated => + InferenceRuleTemplate::new_template(&ARRAYLIKE_TEMPLATE), + AO::Multiplied | AO::Divided | AO::Added | AO::Subtracted => + InferenceRuleTemplate::new_template(&NUMBERLIKE_TEMPLATE), + AO::Remained | AO::ShiftedLeft | AO::ShiftedRight | + AO::BitwiseAnded | AO::BitwiseXored | AO::BitwiseOred => + InferenceRuleTemplate::new_template(&INTEGERLIKE_TEMPLATE), + }; + + node.inference_rule = InferenceRule::TriEqualArgs(InferenceRuleTriEqualArgs{ + argument_template, + result_template: InferenceRuleTemplate::new_forced(&VOID_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }); self.progress_assignment_expr(ctx, id) } - fn visit_binding_expr(&mut self, ctx: &mut Ctx, id: BindingExpressionId) -> VisitorResult { + fn visit_binding_expr(&mut self, ctx: &mut Ctx, id: BindingExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let binding_expr = &ctx.heap[id]; let bound_to_id = binding_expr.bound_to; let bound_from_id = binding_expr.bound_from; - self.visit_expr(ctx, bound_to_id)?; - self.visit_expr(ctx, bound_from_id)?; + let arg_to_index = self.visit_expr(ctx, bound_to_id)?; + let arg_from_index = self.visit_expr(ctx, bound_from_id)?; + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::TriEqualArgs(InferenceRuleTriEqualArgs{ + argument_template: InferenceRuleTemplate::new_none(), + result_template: InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE), + argument1_index: arg_to_index, + argument2_index: arg_from_index, + }); self.progress_binding_expr(ctx, id) } - fn visit_conditional_expr(&mut self, ctx: &mut Ctx, id: ConditionalExpressionId) -> VisitorResult { + fn visit_conditional_expr(&mut self, ctx: &mut Ctx, id: ConditionalExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let conditional_expr = &ctx.heap[id]; let test_expr_id = conditional_expr.test; @@ -1300,89 +1432,194 @@ impl PassTyping { let false_expr_id = conditional_expr.false_expression; self.visit_expr(ctx, test_expr_id)?; - self.visit_expr(ctx, true_expr_id)?; - self.visit_expr(ctx, false_expr_id)?; + let true_index = self.visit_expr(ctx, true_expr_id)?; + let false_index = self.visit_expr(ctx, false_expr_id)?; + + // Note: the test to the conditional expression has already been forced + // to the boolean type. So the only thing we need to do while progressing + // is to apply an equal3 constraint to the arguments and the result of + // the expression. + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::TriEqualAll(InferenceRuleTriEqualAll{ + template: InferenceRuleTemplate::new_none(), + argument1_index: true_index, + argument2_index: false_index, + }); self.progress_conditional_expr(ctx, id) } - fn visit_binary_expr(&mut self, ctx: &mut Ctx, id: BinaryExpressionId) -> VisitorResult { + fn visit_binary_expr(&mut self, ctx: &mut Ctx, id: BinaryExpressionId) -> VisitExprResult { + use BinaryOperator as BO; + let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let binary_expr = &ctx.heap[id]; + let binary_op = binary_expr.operation; let lhs_expr_id = binary_expr.left; let rhs_expr_id = binary_expr.right; - self.visit_expr(ctx, lhs_expr_id)?; - self.visit_expr(ctx, rhs_expr_id)?; + let left_index = self.visit_expr(ctx, lhs_expr_id)?; + let right_index = self.visit_expr(ctx, rhs_expr_id)?; + + let inference_rule = match binary_op { + BO::Concatenate => + InferenceRule::Concatenate(InferenceRuleTwoArgs{ + argument1_index: left_index, + argument2_index: right_index, + }), + BO::LogicalAnd | BO::LogicalOr => + InferenceRule::TriEqualAll(InferenceRuleTriEqualAll{ + template: InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }), + BO::BitwiseOr | BO::BitwiseXor | BO::BitwiseAnd | BO::Remainder | BO::ShiftLeft | BO::ShiftRight => + InferenceRule::TriEqualAll(InferenceRuleTriEqualAll{ + template: InferenceRuleTemplate::new_template(&INTEGERLIKE_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }), + BO::Equality | BO::Inequality => + InferenceRule::TriEqualArgs(InferenceRuleTriEqualArgs{ + argument_template: InferenceRuleTemplate::new_none(), + result_template: InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }), + BO::LessThan | BO::GreaterThan | BO::LessThanEqual | BO::GreaterThanEqual => + InferenceRule::TriEqualArgs(InferenceRuleTriEqualArgs{ + argument_template: InferenceRuleTemplate::new_template(&NUMBERLIKE_TEMPLATE), + result_template: InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }), + BO::Add | BO::Subtract | BO::Multiply | BO::Divide => + InferenceRule::TriEqualAll(InferenceRuleTriEqualAll{ + template: InferenceRuleTemplate::new_template(&NUMBERLIKE_TEMPLATE), + argument1_index: left_index, + argument2_index: right_index, + }), + }; + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = inference_rule; self.progress_binary_expr(ctx, id) } - fn visit_unary_expr(&mut self, ctx: &mut Ctx, id: UnaryExpressionId) -> VisitorResult { + fn visit_unary_expr(&mut self, ctx: &mut Ctx, id: UnaryExpressionId) -> VisitExprResult { + use UnaryOperator as UO; + let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let unary_expr = &ctx.heap[id]; + let operation = unary_expr.operation; let arg_expr_id = unary_expr.expression; - self.visit_expr(ctx, arg_expr_id)?; + let argument_index = self.visit_expr(ctx, arg_expr_id)?; + + let template = match operation { + UO::Positive | UO::Negative => + InferenceRuleTemplate::new_template(&NUMBERLIKE_TEMPLATE), + UO::BitwiseNot => + InferenceRuleTemplate::new_template(&INTEGERLIKE_TEMPLATE), + UO::LogicalNot => + InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE), + }; + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::BiEqual(InferenceRuleBiEqual{ + template, argument_index, + }); self.progress_unary_expr(ctx, id) } - fn visit_indexing_expr(&mut self, ctx: &mut Ctx, id: IndexingExpressionId) -> VisitorResult { + fn visit_indexing_expr(&mut self, ctx: &mut Ctx, id: IndexingExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let indexing_expr = &ctx.heap[id]; let subject_expr_id = indexing_expr.subject; let index_expr_id = indexing_expr.index; - self.visit_expr(ctx, subject_expr_id)?; - self.visit_expr(ctx, index_expr_id)?; + let subject_index = self.visit_expr(ctx, subject_expr_id)?; + let index_index = self.visit_expr(ctx, index_expr_id)?; // cool name, bro + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::IndexingExpr(InferenceRuleIndexingExpr{ + subject_index, index_index, + }); self.progress_indexing_expr(ctx, id) } - fn visit_slicing_expr(&mut self, ctx: &mut Ctx, id: SlicingExpressionId) -> VisitorResult { + fn visit_slicing_expr(&mut self, ctx: &mut Ctx, id: SlicingExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let slicing_expr = &ctx.heap[id]; let subject_expr_id = slicing_expr.subject; let from_expr_id = slicing_expr.from_index; let to_expr_id = slicing_expr.to_index; - self.visit_expr(ctx, subject_expr_id)?; - self.visit_expr(ctx, from_expr_id)?; - self.visit_expr(ctx, to_expr_id)?; + let subject_index = self.visit_expr(ctx, subject_expr_id)?; + let from_index = self.visit_expr(ctx, from_expr_id)?; + let to_index = self.visit_expr(ctx, to_expr_id)?; + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::SlicingExpr(InferenceRuleSlicingExpr{ + subject_index, from_index, to_index, + }); self.progress_slicing_expr(ctx, id) } - fn visit_select_expr(&mut self, ctx: &mut Ctx, id: SelectExpressionId) -> VisitorResult { + fn visit_select_expr(&mut self, ctx: &mut Ctx, id: SelectExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let select_expr = &ctx.heap[id]; let subject_expr_id = select_expr.subject; - self.visit_expr(ctx, subject_expr_id)?; + let subject_index = self.visit_expr(ctx, subject_expr_id)?; + + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::SelectExpr(InferenceRuleSelectExpr{ + subject_index, + }); self.progress_select_expr(ctx, id) } - fn visit_literal_expr(&mut self, ctx: &mut Ctx, id: LiteralExpressionId) -> VisitorResult { + fn visit_literal_expr(&mut self, ctx: &mut Ctx, id: LiteralExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); - self.insert_initial_expr_inference_type(ctx, upcast_id)?; + let self_index = self.insert_initial_expr_inference_type(ctx, upcast_id)?; let literal_expr = &ctx.heap[id]; match &literal_expr.value { - Literal::Null | Literal::False | Literal::True | - Literal::Integer(_) | Literal::Character(_) | Literal::String(_) => { - // No subexpressions + Literal::Null => { + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::MonoTemplate(InferenceRuleTemplate::new_template(&MESSAGE_TEMPLATE)); + }, + Literal::Integer(_) => { + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::MonoTemplate(InferenceRuleTemplate::new_template(&INTEGERLIKE_TEMPLATE)); + }, + Literal::True | Literal::False => { + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::MonoTemplate(InferenceRuleTemplate::new_forced(&BOOL_TEMPLATE)); + }, + Literal::Character(_) => { + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::MonoTemplate(InferenceRuleTemplate::new_forced(&CHARACTER_TEMPLATE)); + }, + Literal::String(_) => { + let node = &mut self.infer_nodes[self_index]; + node.inference_rule = InferenceRule::MonoTemplate(InferenceRuleTemplate::new_forced(&STRING_TEMPLATE)); }, Literal::Struct(literal) => { let mut expr_ids = self.expr_buffer.start_section(); @@ -1425,7 +1662,7 @@ impl PassTyping { self.progress_literal_expr(ctx, id) } - fn visit_cast_expr(&mut self, ctx: &mut Ctx, id: CastExpressionId) -> VisitorResult { + fn visit_cast_expr(&mut self, ctx: &mut Ctx, id: CastExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); self.insert_initial_expr_inference_type(ctx, upcast_id)?; @@ -1437,7 +1674,7 @@ impl PassTyping { self.progress_cast_expr(ctx, id) } - fn visit_call_expr(&mut self, ctx: &mut Ctx, id: CallExpressionId) -> VisitorResult { + fn visit_call_expr(&mut self, ctx: &mut Ctx, id: CallExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); self.insert_initial_expr_inference_type(ctx, upcast_id)?; self.insert_initial_call_polymorph_data(ctx, id); @@ -1446,7 +1683,7 @@ impl PassTyping { // up not being a polymorphic one, then we will select the default // expression types in the type table let call_expr = &ctx.heap[id]; - self.expr_types[call_expr.unique_id_in_definition as usize].field_or_monomorph_idx = 0; + self.infer_nodes[call_expr.unique_id_in_definition as usize].field_or_monomorph_idx = 0; // Visit all arguments let expr_ids = self.expr_buffer.start_section_initialized(call_expr.arguments.as_slice()); @@ -1458,7 +1695,7 @@ impl PassTyping { self.progress_call_expr(ctx, id) } - fn visit_variable_expr(&mut self, ctx: &mut Ctx, id: VariableExpressionId) -> VisitorResult { + fn visit_variable_expr(&mut self, ctx: &mut Ctx, id: VariableExpressionId) -> VisitExprResult { let upcast_id = id.upcast(); self.insert_initial_expr_inference_type(ctx, upcast_id)?; @@ -1495,7 +1732,7 @@ 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.expr_types[expr_idx as usize].expr_type; + let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; expr_type.display_name(&ctx.heap) } @@ -1512,7 +1749,7 @@ impl PassTyping { // Nothing is queued anymore. However we might have integer literals // whose type cannot be inferred. For convenience's sake we'll // infer these to be s32. - for (infer_expr_idx, infer_expr) in self.expr_types.iter_mut().enumerate() { + for (infer_expr_idx, infer_expr) in self.infer_nodes.iter_mut().enumerate() { let expr_type = &mut infer_expr.expr_type; if !expr_type.is_done && expr_type.parts.len() == 1 && expr_type.parts[0] == InferenceTypePart::IntegerLike { // Force integer type to s32 @@ -1579,7 +1816,7 @@ impl PassTyping { // Inference is now done. But we may still have uninferred types. So we // check for these. - for infer_expr in self.expr_types.iter_mut() { + 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( @@ -1685,8 +1922,8 @@ impl PassTyping { } // - Write the expression data - target.expr_data.reserve(self.expr_types.len()); - for infer_expr in self.expr_types.iter() { + 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{ @@ -1700,7 +1937,7 @@ impl PassTyping { } fn progress_expr(&mut self, ctx: &mut Ctx, idx: i32) -> Result<(), ParseError> { - let id = self.expr_types[idx as usize].expr_id; + let id = self.infer_nodes[idx as usize].expr_id; match &ctx.heap[id] { Expression::Assignment(expr) => { let id = expr.this; @@ -1753,10 +1990,9 @@ impl PassTyping { } } - fn progress_assignment_expr(&mut self, ctx: &mut Ctx, id: AssignmentExpressionId) -> Result<(), ParseError> { + fn progress_assignment_expr(&mut self, ctx: &mut Ctx, infer_index: InferIndex) -> Result<(), ParseError> { use AssignmentOperator as AO; - let upcast_id = id.upcast(); let expr = &ctx.heap[id]; let arg1_expr_id = expr.left; @@ -1872,7 +2108,7 @@ impl PassTyping { BO::Concatenate => { // Two cases: if one of the arguments or the output type is a // string, then all must be strings. Otherwise the arguments - // must be arraylike and the output will be a array. + // must be arraylike and the output will be an array. let (expr_is_str, expr_is_not_str) = self.type_is_certainly_or_certainly_not_string(ctx, upcast_id); let (arg1_is_str, arg1_is_not_str) = self.type_is_certainly_or_certainly_not_string(ctx, arg1_id); let (arg2_is_str, arg2_is_not_str) = self.type_is_certainly_or_certainly_not_string(ctx, arg2_id); @@ -1903,15 +2139,7 @@ impl PassTyping { (progress_expr || subtype_expr, progress_arg1 || subtype_arg1, progress_arg2 || subtype_arg2) } }, - BO::LogicalAnd => { - // Forced boolean on all - let progress_expr = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; - let progress_arg1 = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; - let progress_arg2 = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; - - (progress_expr, progress_arg1, progress_arg2) - }, - BO::LogicalOr => { + BO::LogicalAnd | BO::LogicalOr => { // Forced boolean on all let progress_expr = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; let progress_arg1 = self.apply_forced_constraint(ctx, arg1_id, &BOOL_TEMPLATE)?; @@ -2114,7 +2342,7 @@ impl PassTyping { let select_expr = &ctx.heap[id]; let expr_idx = select_expr.unique_id_in_definition; - let infer_expr = &self.expr_types[expr_idx as usize]; + let infer_expr = &self.infer_nodes[expr_idx as usize]; let extra_idx = infer_expr.extra_data_idx; fn try_get_definition_id_from_inference_type<'a>(types: &'a TypeTable, infer_type: &InferenceType) -> Result, ()> { @@ -2166,7 +2394,7 @@ impl PassTyping { if infer_expr.field_or_monomorph_idx < 0 { // We don't know the field or the definition it is pointing to yet // Not yet known, check if we can determine it - let subject_type = &self.expr_types[subject_expr_idx as usize].expr_type; + let subject_type = &self.infer_nodes[subject_expr_idx as usize].expr_type; let type_def = try_get_definition_id_from_inference_type(&ctx.types, subject_type); match type_def { @@ -2189,7 +2417,7 @@ impl PassTyping { for (field_def_idx, field_def) in struct_def.fields.iter().enumerate() { if field_def.identifier == *field_name { // Set field definition and index - let infer_expr = &mut self.expr_types[expr_idx as usize]; + let infer_expr = &mut self.infer_nodes[expr_idx as usize]; infer_expr.field_or_monomorph_idx = field_def_idx as i32; struct_def_id = Some(type_def.ast_definition); break; @@ -2234,7 +2462,7 @@ impl PassTyping { // Apply to struct's type let signature_type: *mut _ = &mut poly_data.embedded[0]; - let subject_type: *mut _ = &mut self.expr_types[subject_expr_idx as usize].expr_type; + let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let (_, progress_subject) = Self::apply_equal2_signature_constraint( ctx, upcast_id, Some(subject_id), poly_data, &mut poly_progress, @@ -2247,7 +2475,7 @@ impl PassTyping { // Apply to field's type let signature_type: *mut _ = &mut poly_data.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, poly_data, &mut poly_progress, @@ -2263,14 +2491,14 @@ impl PassTyping { // Reapply progress in polymorphic variables to struct's type let signature_type: *mut _ = &mut poly_data.embedded[0]; - let subject_type: *mut _ = &mut self.expr_types[subject_expr_idx as usize].expr_type; + let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let progress_subject = Self::apply_equal2_polyvar_constraint( poly_data, &poly_progress, signature_type, subject_type ); let signature_type: *mut _ = &mut poly_data.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let progress_expr = Self::apply_equal2_polyvar_constraint( poly_data, &poly_progress, signature_type, expr_type @@ -2283,7 +2511,7 @@ impl PassTyping { if infer_expr.field_or_monomorph_idx < 0 { // We don't know what kind of tuple we're accessing yet - let subject_type = &self.expr_types[subject_expr_idx as usize].expr_type; + let subject_type = &self.infer_nodes[subject_expr_idx as usize].expr_type; let tuple_size = try_get_tuple_size_from_inference_type(subject_type); match tuple_size { @@ -2301,7 +2529,7 @@ impl PassTyping { // Within bounds, so set the index (such that we // will not perform this lookup again) - let infer_expr = &mut self.expr_types[expr_idx as usize]; + let infer_expr = &mut self.infer_nodes[expr_idx as usize]; infer_expr.field_or_monomorph_idx = member_index as i32; }, Ok(None) => { @@ -2321,7 +2549,7 @@ impl PassTyping { // If here then we know which member we're accessing. So seek // that member in the subject type and apply inference. - let subject_type = &self.expr_types[subject_expr_idx as usize].expr_type; + let subject_type = &self.infer_nodes[subject_expr_idx as usize].expr_type; let mut member_start_idx = 1; for _ in 0..member_index { member_start_idx = InferenceType::find_subtree_end_idx(&subject_type.parts, member_start_idx); @@ -2349,7 +2577,7 @@ impl PassTyping { let upcast_id = id.upcast(); let expr = &ctx.heap[id]; let expr_idx = expr.unique_id_in_definition; - let extra_idx = self.expr_types[expr_idx as usize].extra_data_idx; + let extra_idx = self.infer_nodes[expr_idx as usize].extra_data_idx; debug_log!("Literal expr: {}", upcast_id.index); debug_log!(" * Before:"); @@ -2386,7 +2614,7 @@ impl PassTyping { let field_expr_id = field.value; let field_expr_idx = ctx.heap[field_expr_id].get_unique_id_in_definition(); let signature_type: *mut _ = &mut extra.embedded[field_idx]; - let field_type: *mut _ = &mut self.expr_types[field_expr_idx as usize].expr_type; + let field_type: *mut _ = &mut self.infer_nodes[field_expr_idx as usize].expr_type; let (_, progress_arg) = Self::apply_equal2_signature_constraint( ctx, upcast_id, Some(field_expr_id), extra, &mut poly_progress, signature_type, 0, field_type, 0 @@ -2407,7 +2635,7 @@ impl PassTyping { // Same for the type of the struct itself let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, extra, &mut poly_progress, signature_type, 0, expr_type, 0 @@ -2442,7 +2670,7 @@ impl PassTyping { let signature_type: *mut _ = &mut extra.embedded[field_idx]; let field_expr_id = data.fields[field_idx].value; let field_expr_idx = ctx.heap[field_expr_id].get_unique_id_in_definition(); - let field_type: *mut _ = &mut self.expr_types[field_expr_idx as usize].expr_type; + let field_type: *mut _ = &mut self.infer_nodes[field_expr_idx as usize].expr_type; let progress_arg = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, signature_type, field_type @@ -2460,7 +2688,7 @@ impl PassTyping { // For the return type let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let progress_expr = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, signature_type, expr_type @@ -2478,7 +2706,7 @@ impl PassTyping { debug_log!(" * During (inferring types from return type)"); let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, extra, &mut poly_progress, signature_type, 0, expr_type, 0 @@ -2520,7 +2748,7 @@ impl PassTyping { let value_expr_id = *value_expr_id; let value_expr_idx = ctx.heap[value_expr_id].get_unique_id_in_definition(); let signature_type: *mut _ = &mut extra.embedded[value_idx]; - let value_type: *mut _ = &mut self.expr_types[value_expr_idx as usize].expr_type; + let value_type: *mut _ = &mut self.infer_nodes[value_expr_idx as usize].expr_type; let (_, progress_arg) = Self::apply_equal2_signature_constraint( ctx, upcast_id, Some(value_expr_id), extra, &mut poly_progress, signature_type, 0, value_type, 0 @@ -2541,7 +2769,7 @@ impl PassTyping { // Infer type of union itself let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, extra, &mut poly_progress, signature_type, 0, expr_type, 0 @@ -2569,7 +2797,7 @@ impl PassTyping { let signature_type: *mut _ = &mut extra.embedded[value_idx]; let value_expr_id = data.values[value_idx]; let value_expr_idx = ctx.heap[value_expr_id].get_unique_id_in_definition(); - let value_type: *mut _ = &mut self.expr_types[value_expr_idx as usize].expr_type; + let value_type: *mut _ = &mut self.infer_nodes[value_expr_idx as usize].expr_type; let progress_arg = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, signature_type, value_type @@ -2587,7 +2815,7 @@ impl PassTyping { // And for the union type itself let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let progress_expr = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, signature_type, expr_type @@ -2656,7 +2884,7 @@ impl PassTyping { let mut start_index = 1; // first element is Tuple type, second is the first child for _ in 0..member_expr_index { let tuple_expr_index = ctx.heap[id].unique_id_in_definition; - let tuple_type = &self.expr_types[tuple_expr_index as usize].expr_type; + let tuple_type = &self.infer_nodes[tuple_expr_index as usize].expr_type; start_index = InferenceType::find_subtree_end_idx(&tuple_type.parts, start_index); debug_assert_ne!(start_index, tuple_type.parts.len()); // would imply less tuple type children than member expressions } @@ -2716,8 +2944,8 @@ impl PassTyping { debug_log!(" * Decision:"); let subject_idx = ctx.heap[expr.subject].get_unique_id_in_definition(); - let expr_type = &self.expr_types[expr_idx as usize].expr_type; - let subject_type = &self.expr_types[subject_idx as usize].expr_type; + let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; + let subject_type = &self.infer_nodes[subject_idx as usize].expr_type; if !expr_type.is_done || !subject_type.is_done { // Not yet done debug_log!(" - Casting is valid: unknown as the types are not yet complete"); @@ -2768,7 +2996,7 @@ impl PassTyping { let upcast_id = id.upcast(); let expr = &ctx.heap[id]; let expr_idx = expr.unique_id_in_definition; - let extra_idx = self.expr_types[expr_idx as usize].extra_data_idx; + let extra_idx = self.infer_nodes[expr_idx as usize].extra_data_idx; debug_log!("Call expr '{}': {}", ctx.heap[expr.definition].identifier().value.as_str(), upcast_id.index); debug_log!(" * Before:"); @@ -2785,7 +3013,7 @@ impl PassTyping { for (call_arg_idx, arg_id) in expr.arguments.clone().into_iter().enumerate() { let arg_expr_idx = ctx.heap[arg_id].get_unique_id_in_definition(); let signature_type: *mut _ = &mut extra.embedded[call_arg_idx]; - let argument_type: *mut _ = &mut self.expr_types[arg_expr_idx as usize].expr_type; + let argument_type: *mut _ = &mut self.infer_nodes[arg_expr_idx as usize].expr_type; let (_, progress_arg) = Self::apply_equal2_signature_constraint( ctx, upcast_id, Some(arg_id), extra, &mut poly_progress, signature_type, 0, argument_type, 0 @@ -2804,7 +3032,7 @@ impl PassTyping { // Do the same for the return type let signature_type: *mut _ = &mut extra.returned; - let expr_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, extra, &mut poly_progress, signature_type, 0, expr_type, 0 @@ -2838,7 +3066,7 @@ impl PassTyping { let signature_type: *mut _ = &mut extra.embedded[arg_idx]; let arg_expr_id = expr.arguments[arg_idx]; let arg_expr_idx = ctx.heap[arg_expr_id].get_unique_id_in_definition(); - let arg_type: *mut _ = &mut self.expr_types[arg_expr_idx as usize].expr_type; + let arg_type: *mut _ = &mut self.infer_nodes[arg_expr_idx as usize].expr_type; let progress_arg = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, @@ -2857,7 +3085,7 @@ impl PassTyping { // Once more for the return type let signature_type: *mut _ = &mut extra.returned; - let ret_type: *mut _ = &mut self.expr_types[expr_idx as usize].expr_type; + let ret_type: *mut _ = &mut self.infer_nodes[expr_idx as usize].expr_type; let progress_ret = Self::apply_equal2_polyvar_constraint( extra, &poly_progress, signature_type, ret_type @@ -2890,7 +3118,7 @@ impl PassTyping { // Retrieve shared variable type and expression type and apply inference let var_data = self.var_types.get_mut(&var_id).unwrap(); - let expr_type = &mut self.expr_types[var_expr_idx as usize].expr_type; + let expr_type = &mut self.infer_nodes[var_expr_idx as usize].expr_type; let infer_res = unsafe{ InferenceType::infer_subtrees_for_both_types( &mut var_data.var_type as *mut _, 0, expr_type, 0 @@ -2993,7 +3221,7 @@ impl PassTyping { // first returned is certainly string, second is certainly not fn type_is_certainly_or_certainly_not_string(&self, ctx: &Ctx, expr_id: ExpressionId) -> (bool, bool) { let expr_idx = ctx.heap[expr_id].get_unique_id_in_definition(); - let expr_type = &self.expr_types[expr_idx as usize].expr_type; + let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; if expr_type.is_done { if expr_type.parts[0] == InferenceTypePart::String { return (true, false); @@ -3014,7 +3242,7 @@ impl PassTyping { &mut self, ctx: &Ctx, expr_id: ExpressionId, template: &[InferenceTypePart] ) -> Result { let expr_idx = ctx.heap[expr_id].get_unique_id_in_definition(); // TODO: @Temp - let expr_type = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type = &mut self.infer_nodes[expr_idx as usize].expr_type; match InferenceType::infer_subtree_for_single_type(expr_type, 0, template, 0, false) { SingleInferenceResult::Modified => Ok(true), SingleInferenceResult::Unmodified => Ok(false), @@ -3044,7 +3272,7 @@ impl PassTyping { &mut self, ctx: &Ctx, expr_id: ExpressionId, template: &[InferenceTypePart] ) -> Result { let expr_idx = ctx.heap[expr_id].get_unique_id_in_definition(); - let expr_type = &mut self.expr_types[expr_idx as usize].expr_type; + let expr_type = &mut self.infer_nodes[expr_idx as usize].expr_type; match InferenceType::infer_subtree_for_single_type(expr_type, 0, template, 0, true) { SingleInferenceResult::Modified => Ok(true), SingleInferenceResult::Unmodified => Ok(false), @@ -3065,8 +3293,8 @@ impl PassTyping { ) -> Result<(bool, bool), ParseError> { let arg1_expr_idx = ctx.heap[arg1_id].get_unique_id_in_definition(); // TODO: @Temp let arg2_expr_idx = ctx.heap[arg2_id].get_unique_id_in_definition(); - let arg1_type: *mut _ = &mut self.expr_types[arg1_expr_idx as usize].expr_type; - let arg2_type: *mut _ = &mut self.expr_types[arg2_expr_idx as usize].expr_type; + let arg1_type: *mut _ = &mut self.infer_nodes[arg1_expr_idx as usize].expr_type; + let arg2_type: *mut _ = &mut self.infer_nodes[arg2_expr_idx as usize].expr_type; let infer_res = unsafe{ InferenceType::infer_subtrees_for_both_types( arg1_type, arg1_start_idx, @@ -3222,9 +3450,9 @@ impl PassTyping { let arg1_expr_idx = ctx.heap[arg1_id].get_unique_id_in_definition(); let arg2_expr_idx = ctx.heap[arg2_id].get_unique_id_in_definition(); - let expr_type: *mut _ = &mut self.expr_types[expr_expr_idx as usize].expr_type; - let arg1_type: *mut _ = &mut self.expr_types[arg1_expr_idx as usize].expr_type; - let arg2_type: *mut _ = &mut self.expr_types[arg2_expr_idx as usize].expr_type; + let expr_type: *mut _ = &mut self.infer_nodes[expr_expr_idx as usize].expr_type; + let arg1_type: *mut _ = &mut self.infer_nodes[arg1_expr_idx as usize].expr_type; + let arg2_type: *mut _ = &mut self.infer_nodes[arg2_expr_idx as usize].expr_type; let expr_res = unsafe{ InferenceType::infer_subtrees_for_both_types(expr_type, start_idx, arg1_type, start_idx) @@ -3295,8 +3523,8 @@ impl PassTyping { while let Some(next_arg_id) = arg_iter.next() { let last_expr_idx = ctx.heap[last_arg_id].get_unique_id_in_definition(); // TODO: @Temp let next_expr_idx = ctx.heap[next_arg_id].get_unique_id_in_definition(); - let last_type: *mut _ = &mut self.expr_types[last_expr_idx as usize].expr_type; - let next_type: *mut _ = &mut self.expr_types[next_expr_idx as usize].expr_type; + let last_type: *mut _ = &mut self.infer_nodes[last_expr_idx as usize].expr_type; + let next_type: *mut _ = &mut self.infer_nodes[next_expr_idx as usize].expr_type; let res = unsafe { InferenceType::infer_subtrees_for_both_types(last_type, 0, next_type, 0) @@ -3321,10 +3549,10 @@ impl PassTyping { // Re-infer everything. Note that we do not need to re-infer the type // exactly at `last_lhs_progressed`, but only everything up to it. let last_arg_expr_idx = ctx.heap[last_arg_id].get_unique_id_in_definition(); - let last_type: *mut _ = &mut self.expr_types[last_arg_expr_idx as usize].expr_type; + let last_type: *mut _ = &mut self.infer_nodes[last_arg_expr_idx as usize].expr_type; for arg_idx in 0..last_lhs_progressed { let other_arg_expr_idx = ctx.heap[args[arg_idx]].get_unique_id_in_definition(); - let arg_type: *mut _ = &mut self.expr_types[other_arg_expr_idx as usize].expr_type; + let arg_type: *mut _ = &mut self.infer_nodes[other_arg_expr_idx as usize].expr_type; unsafe{ (*arg_type).replace_subtree(0, &(*last_type).parts); } @@ -3340,10 +3568,11 @@ impl PassTyping { /// of subexpressions before they have a chance to call this function. fn insert_initial_expr_inference_type( &mut self, ctx: &mut Ctx, expr_id: ExpressionId - ) -> Result<(), ParseError> { + ) -> Result { use ExpressionParent as EP; use InferenceTypePart as ITP; + // Set the initial inference type based on the expression parent. let expr = &ctx.heap[expr_id]; let inference_type = match expr.parent() { EP::None => @@ -3386,47 +3615,21 @@ impl PassTyping { InferenceType::new(false, true, vec![ITP::Void]), }; - let infer_expr = &mut self.expr_types[expr.get_unique_id_in_definition() as usize]; - let needs_extra_data = match expr { - Expression::Call(_) => true, - Expression::Literal(expr) => match expr.value { - Literal::Enum(_) | Literal::Union(_) | Literal::Struct(_) => true, - _ => false, - }, - Expression::Select(expr) => match expr.kind { - SelectKind::StructField(_) => true, - SelectKind::TupleMember(_) => false, - }, - _ => false, - }; - - if infer_expr.expr_id.is_invalid() { - // Nothing is set yet - infer_expr.expr_type = inference_type; - infer_expr.expr_id = expr_id; - if needs_extra_data { - let extra_idx = self.extra_data.len() as i32; - self.extra_data.push(ExtraData::default()); - infer_expr.extra_data_idx = extra_idx; - } - } else { - // We already have an entry - debug_assert!(false, "does this ever happen?"); - if let SingleInferenceResult::Incompatible = InferenceType::infer_subtree_for_single_type( - &mut infer_expr.expr_type, 0, &inference_type.parts, 0, false - ) { - return Err(self.construct_expr_type_error(ctx, expr_id, expr_id)); - } - - debug_assert!((infer_expr.extra_data_idx != -1) == needs_extra_data); - } + let infer_index = self.infer_nodes.len() as InferIndex; + self.infer_nodes.push(InferenceNode { + expr_type: inference_type, + expr_id, + field_or_monomorph_idx: -1, + extra_data_idx: -1, + type_id: TypeId::new_invalid(), + }); - Ok(()) + return Ok(infer_index); } fn insert_initial_call_polymorph_data( &mut self, ctx: &mut Ctx, call_id: CallExpressionId - ) { + ) -> ExtraIndex { // Note: the polymorph variables may be partially specified and may // contain references to the wrapping definition's (i.e. the proctype // we are currently visiting) polymorphic arguments. @@ -3437,8 +3640,6 @@ impl PassTyping { // map them back and forth to the polymorphic arguments of the function // we are calling. let call = &ctx.heap[call_id]; - let extra_data_idx = self.expr_types[call.unique_id_in_definition as usize].extra_data_idx; // TODO: @Temp - debug_assert!(extra_data_idx != -1, "insert initial call polymorph data, no preallocated ExtraData"); // Handle the polymorphic arguments (if there are any) let num_poly_args = call.parser_type.elements[0].variant.num_embedded(); @@ -3479,22 +3680,21 @@ impl PassTyping { } }; - self.extra_data[extra_data_idx as usize] = ExtraData{ + let extra_data_idx = self.extra_data.len() as ExtraIndex; + self.extra_data.push(ExtraData{ expr_id: call_id.upcast(), definition_id: call.definition, poly_vars: poly_args, embedded: parameter_types, returned: return_type - }; + }); + return extra_data_idx } fn insert_initial_struct_polymorph_data( &mut self, ctx: &mut Ctx, lit_id: LiteralExpressionId, - ) { + ) -> ExtraIndex { use InferenceTypePart as ITP; - let literal = &ctx.heap[lit_id]; - let extra_data_idx = self.expr_types[literal.unique_id_in_definition as usize].extra_data_idx; // TODO: @Temp - debug_assert!(extra_data_idx != -1, "initial struct polymorph data, but no preallocated ExtraData"); let literal = ctx.heap[lit_id].value.as_struct(); // Handle polymorphic arguments @@ -3542,13 +3742,16 @@ impl PassTyping { debug_assert_eq!(parts.len(), parts_reserved); let return_type = InferenceType::new(!poly_args.is_empty(), return_type_done, parts); - self.extra_data[extra_data_idx as usize] = ExtraData{ + let extra_data_index = self.extra_data.len() as ExtraIndex; + self.extra_data.push(ExtraData{ expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, embedded: embedded_types, returned: return_type, - }; + }); + + return extra_data_index } /// Inserts the extra polymorphic data struct for enum expressions. These @@ -3556,11 +3759,8 @@ impl PassTyping { /// the use of the enum. fn insert_initial_enum_polymorph_data( &mut self, ctx: &Ctx, lit_id: LiteralExpressionId - ) { + ) -> ExtraIndex { use InferenceTypePart as ITP; - let literal = &ctx.heap[lit_id]; - let extra_data_idx = self.expr_types[literal.unique_id_in_definition as usize].extra_data_idx; // TODO: @Temp - debug_assert!(extra_data_idx != -1, "initial enum polymorph data, but no preallocated ExtraData"); let literal = ctx.heap[lit_id].value.as_enum(); // Handle polymorphic arguments to the enum @@ -3589,13 +3789,16 @@ impl PassTyping { debug_assert_eq!(parts.len(), parts_reserved); let enum_type = InferenceType::new(!poly_args.is_empty(), enum_type_done, parts); - self.extra_data[extra_data_idx as usize] = ExtraData{ + let extra_data_index = self.extra_data.len() as ExtraIndex; + self.extra_data.push(ExtraData{ expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, embedded: Vec::new(), returned: enum_type, - }; + }); + + return extra_data_index; } /// Inserts the extra polymorphic data struct for unions. The polymorphic @@ -3604,9 +3807,6 @@ impl PassTyping { &mut self, ctx: &Ctx, lit_id: LiteralExpressionId ) { use InferenceTypePart as ITP; - let literal = &ctx.heap[lit_id]; - let extra_data_idx = self.expr_types[literal.unique_id_in_definition as usize].extra_data_idx; // TODO: @Temp - debug_assert!(extra_data_idx != -1, "initial union polymorph data, but no preallocated ExtraData"); let literal = ctx.heap[lit_id].value.as_union(); // Construct the polymorphic variables @@ -3650,28 +3850,27 @@ impl PassTyping { debug_assert_eq!(parts_reserved, parts.len()); let union_type = InferenceType::new(!poly_args.is_empty(), union_type_done, parts); - self.extra_data[extra_data_idx as usize] = ExtraData{ + let extra_data_index = self.extra_data.len(); + self.extra_data.push(ExtraData{ expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, embedded, returned: union_type - }; + }); } /// Inserts the extra polymorphic data struct. Assumes that the select /// expression's referenced (definition_id, field_idx) has been resolved. fn insert_initial_select_polymorph_data( &mut self, ctx: &Ctx, select_id: SelectExpressionId, struct_def_id: DefinitionId - ) { + ) -> ExtraIndex { use InferenceTypePart as ITP; // Retrieve relevant data let expr = &ctx.heap[select_id]; - let expr_type = &self.expr_types[expr.unique_id_in_definition as usize]; + let expr_type = &self.infer_nodes[expr.unique_id_in_definition as usize]; let field_idx = expr_type.field_or_monomorph_idx as usize; - let extra_data_idx = expr_type.extra_data_idx; // TODO: @Temp - debug_assert!(extra_data_idx != -1, "initial select polymorph data, but no preallocated ExtraData"); let definition = ctx.heap[struct_def_id].as_struct(); @@ -3694,13 +3893,17 @@ impl PassTyping { // Generate initial field type let field_type = self.determine_inference_type_from_parser_type_elements(&definition.fields[field_idx].parser_type.elements, false); - self.extra_data[extra_data_idx as usize] = ExtraData{ + + let extra_data_index = self.extra_data.len() as ExtraIndex; + self.extra_data.push(ExtraData{ expr_id: select_id.upcast(), definition_id: struct_def_id, poly_vars, embedded: vec![InferenceType::new(num_poly_vars != 0, num_poly_vars == 0, struct_parts)], returned: field_type - }; + }); + + return extra_data_index; } /// Determines the initial InferenceType from the provided ParserType. This @@ -3845,8 +4048,8 @@ impl PassTyping { let arg_expr = &ctx.heap[arg_id]; let expr_idx = expr.get_unique_id_in_definition(); let arg_expr_idx = arg_expr.get_unique_id_in_definition(); - let expr_type = &self.expr_types[expr_idx as usize].expr_type; - let arg_type = &self.expr_types[arg_expr_idx as usize].expr_type; + let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; + let arg_type = &self.infer_nodes[arg_expr_idx as usize].expr_type; return ParseError::new_error_at_span( &ctx.module().source, expr.operation_span(), format!( @@ -3870,9 +4073,9 @@ impl PassTyping { let arg2 = &ctx.heap[arg2_id]; let arg1_idx = arg1.get_unique_id_in_definition(); - let arg1_type = &self.expr_types[arg1_idx as usize].expr_type; + let arg1_type = &self.infer_nodes[arg1_idx as usize].expr_type; let arg2_idx = arg2.get_unique_id_in_definition(); - let arg2_type = &self.expr_types[arg2_idx as usize].expr_type; + let arg2_type = &self.infer_nodes[arg2_idx as usize].expr_type; return ParseError::new_error_str_at_span( &ctx.module().source, expr.operation_span(), @@ -3895,7 +4098,7 @@ impl PassTyping { ) -> ParseError { let expr = &ctx.heap[expr_id]; let expr_idx = expr.get_unique_id_in_definition(); - let expr_type = &self.expr_types[expr_idx as usize].expr_type; + let expr_type = &self.infer_nodes[expr_idx as usize].expr_type; return ParseError::new_error_at_span( &ctx.module().source, expr.full_span(), format!(