From 6c13962edb01add83c500e3dd5c0147c3549dfba 2022-02-18 18:05:05 From: MH Date: 2022-02-18 18:05:05 Subject: [PATCH] WIP: More refactoring of type inference --- diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 2d474cdfb635abbf1282012b32e6e218445862f0..2373bfe14c4e0f4fe9614d12aa949eb1eef46a39 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -809,7 +809,7 @@ enum SingleInferenceResult { // ----------------------------------------------------------------------------- type InferNodeIndex = usize; -type ExtraIndex = usize; +type PolyDataIndex = usize; enum DefinitionType{ Component(ComponentDefinitionId), @@ -843,7 +843,7 @@ struct InferenceNode { inference_rule: InferenceRule, parent_index: Option, field_or_monomorph_index: i32, // index of field - extra_index: ExtraIndex, // index of extra data needed for inference + poly_data_index: PolyDataIndex, // index of extra data needed for inference type_id: TypeId, // when applicable indexes into type table } @@ -1018,7 +1018,7 @@ pub(crate) struct PassTyping { reserved_type_id: TypeId, definition_type: DefinitionType, poly_vars: Vec, - // Temporary variables during construction of inference rules + // Temporary variables during construction of inference rulesr parent_index: Option, // Buffers for iteration over various types var_buffer: ScopedBuffer, @@ -1030,35 +1030,61 @@ pub(crate) struct PassTyping { // specify these types until we're stuck or we've fully determined the type. var_types: HashMap, // types of variables infer_nodes: Vec, // will be transferred to type table at end - extra_data: Vec, // data for polymorph inference + poly_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 expr_queued: DequeSet, } -// TODO: @Rename, this is used for a lot of type inferencing. It seems like -// there is a different underlying architecture waiting to surface. -struct ExtraData { +/// Generic struct that is used to store inferred types associated with +/// polymorphic types. +struct PolyData { definition_id: DefinitionId, // the definition, only used for user feedback - /// Progression of polymorphic variables (if any) + /// Inferred types of the polymorphic variables as they are written down + /// at the type's definition. poly_vars: Vec, - /// Progression of types of call arguments or struct members - embedded: Vec, + /// Inferred types of associated types (e.g. struct fields, tuple members, + /// function arguments). These types may depend on the polymorphic variables + /// defined above. + associated: Vec, + /// Inferred "returned" type (e.g. if a struct field is selected, then this + /// contains the type of the selected field, for a function call it contains + /// the return type). May depend on the polymorphic variables defined above. returned: InferenceType, } -impl Default for ExtraData { +impl Default for PolyData { fn default() -> Self { - Self{ - expr_id: ExpressionId::new_invalid(), + Self { definition_id: DefinitionId::new_invalid(), poly_vars: Vec::new(), - embedded: Vec::new(), + associated: Vec::new(), returned: InferenceType::default(), } } } +enum PolyDataTypeIndex { + Associated(usize), // indexes into `PolyData.associated` + Returned, +} + +impl PolyData { + fn get_type(&self, index: PolyDataTypeIndex) -> &InferenceType { + match index { + PolyDataTypeIndex::Associated(index) => return &self.associated[index], + PolyDataTypeIndex::Returned => return &self.returned, + } + } + + fn get_type_mut(&mut self, index: PolyDataTypeIndex) -> &mut InferenceType { + match index { + PolyDataTypeIndex::Associated(index) => return &mut self.associated[index], + PolyDataTypeIndex::Returned => return &mut self.returned, + } + } +} + struct VarData { /// Type of the variable var_type: InferenceType, @@ -1091,7 +1117,7 @@ impl PassTyping { bool_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAP_SMALL), var_types: HashMap::new(), infer_nodes: Vec::new(), - extra_data: Vec::new(), + poly_data: Vec::new(), expr_queued: DequeSet::new(), } } @@ -1164,7 +1190,7 @@ impl PassTyping { self.poly_vars.clear(); self.var_types.clear(); self.infer_nodes.clear(); - self.extra_data.clear(); + self.poly_data.clear(); self.expr_queued.clear(); } } @@ -1718,7 +1744,7 @@ impl PassTyping { // Assign rule and extra data index to inference node let extra_index = self.insert_initial_struct_polymorph_data(ctx, id); let node = &mut self.infer_nodes[self_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; node.inference_rule = InferenceRule::LiteralStruct(InferenceRuleLiteralStruct{ element_indices, }); @@ -1730,7 +1756,7 @@ impl PassTyping { // polymorphic variable let extra_index = self.insert_initial_enum_polymorph_data(ctx, id); let node = &mut self.infer_nodes[self_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; node.inference_rule = InferenceRule::LiteralEnum(InferenceRuleLiteralEnum{ }); @@ -1749,7 +1775,7 @@ impl PassTyping { let element_indices = expr_indices.into_vec(); let node = &mut self.infer_nodes[self_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; node.inference_rule = InferenceRule::LiteralUnion(InferenceRuleLiteralUnion{ element_indices, }); @@ -1766,7 +1792,7 @@ impl PassTyping { let element_indices = expr_indices.into_vec(); let node = &mut self.infer_nodes[self_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; node.inference_rule = InferenceRule::LiteralArray(InferenceRuleLiteralArray{ element_indices, }) @@ -1821,7 +1847,7 @@ impl PassTyping { let argument_indices = expr_indices.into_vec(); let node = &mut self.infer_nodes[self_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; node.inference_rule = InferenceRule::CallExpr(InferenceRuleCallExpr{ argument_indices, }); @@ -1967,7 +1993,7 @@ impl PassTyping { // Extra data is attached, perform typechecking and transfer // resolved information to the expression - let extra_data = &self.extra_data[infer_expr.extra_data_idx as usize]; + let extra_data = &self.poly_data[infer_expr.extra_data_idx as usize]; // Note that only call and literal expressions need full inference. // Select expressions also use `extra_data`, but only for temporary @@ -2309,7 +2335,7 @@ impl PassTyping { // fields let extra_index = self.insert_initial_select_polymorph_data(ctx, node_index, definition_id); let node = &mut self.infer_nodes[node_index]; - node.extra_index = extra_index; + node.poly_data_index = extra_index; }, Ok(None) => { // We don't know what to do yet, because we don't know the @@ -2330,11 +2356,11 @@ impl PassTyping { // If here then the field index is known, hence we can start inferring // the type of the selected field let node = &self.infer_nodes[node_index]; - let poly_data = &mut self.extra_data[node.extra_index as usize]; + let poly_data = &mut self.poly_data[node.poly_data_index as usize]; let mut poly_progress = HashSet::new(); // TODO: @Performance // Apply to struct's type - let signature_type: *mut _ = &mut poly_data.embedded[0]; + let signature_type: *mut _ = &mut poly_data.associated[0]; let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let (_, progress_subject) = Self::apply_equal2_signature_constraint( @@ -2353,7 +2379,7 @@ impl PassTyping { let (_, progress_expr) = Self::apply_equal2_signature_constraint( ctx, upcast_id, None, poly_data, &mut poly_progress, signature_type, 0, expr_type, 0 - )?; + )?; if progress_expr { if let Some(parent_id) = ctx.heap[upcast_id].parent_expr_id() { @@ -2363,7 +2389,7 @@ impl PassTyping { } // Reapply progress in polymorphic variables to struct's type - let signature_type: *mut _ = &mut poly_data.embedded[0]; + let signature_type: *mut _ = &mut poly_data.associated[0]; let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let progress_subject = Self::apply_equal2_polyvar_constraint( @@ -2917,11 +2943,11 @@ impl PassTyping { // If here then field index is known, and the referenced struct type // information is inserted into `extra_data`. Check to see if we can // do some mutual inference. - let poly_data = &mut self.extra_data[extra_idx as usize]; + let poly_data = &mut self.poly_data[extra_idx as usize]; let mut poly_progress = HashSet::new(); // TODO: @Performance // Apply to struct's type - let signature_type: *mut _ = &mut poly_data.embedded[0]; + let signature_type: *mut _ = &mut poly_data.associated[0]; let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let (_, progress_subject) = Self::apply_equal2_signature_constraint( @@ -2950,7 +2976,7 @@ impl PassTyping { } // Reapply progress in polymorphic variables to struct's type - let signature_type: *mut _ = &mut poly_data.embedded[0]; + let signature_type: *mut _ = &mut poly_data.associated[0]; let subject_type: *mut _ = &mut self.infer_nodes[subject_expr_idx as usize].expr_type; let progress_subject = Self::apply_equal2_polyvar_constraint( @@ -3060,12 +3086,12 @@ impl PassTyping { self.apply_forced_constraint(ctx, upcast_id, &STRING_TEMPLATE)? }, Literal::Struct(data) => { - let extra = &mut self.extra_data[extra_idx as usize]; + let extra = &mut self.poly_data[extra_idx as usize]; for _poly in &extra.poly_vars { debug_log!(" * Poly: {}", _poly.display_name(&ctx.heap)); } let mut poly_progress = HashSet::new(); - debug_assert_eq!(extra.embedded.len(), data.fields.len()); + debug_assert_eq!(extra.associated.len(), data.fields.len()); debug_log!(" * During (inferring types from fields and struct type):"); @@ -3073,7 +3099,7 @@ impl PassTyping { for (field_idx, field) in data.fields.iter().enumerate() { 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 signature_type: *mut _ = &mut extra.associated[field_idx]; 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, @@ -3122,12 +3148,12 @@ impl PassTyping { debug_log!(" * During (reinferring from progressed polyvars):"); // For all field expressions - for field_idx in 0..extra.embedded.len() { + for field_idx in 0..extra.associated.len() { // Note: fields in extra.embedded are in the same order as // they are specified in the literal. Whereas // `data.fields[...].field_idx` points to the field in the // struct definition. - let signature_type: *mut _ = &mut extra.embedded[field_idx]; + let signature_type: *mut _ = &mut extra.associated[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.infer_nodes[field_expr_idx as usize].expr_type; @@ -3157,7 +3183,7 @@ impl PassTyping { progress_expr }, Literal::Enum(_) => { - let extra = &mut self.extra_data[extra_idx as usize]; + let extra = &mut self.poly_data[extra_idx as usize]; for _poly in &extra.poly_vars { debug_log!(" * Poly: {}", _poly.display_name(&ctx.heap)); } @@ -3194,12 +3220,12 @@ impl PassTyping { progress_expr }, Literal::Union(data) => { - let extra = &mut self.extra_data[extra_idx as usize]; + let extra = &mut self.poly_data[extra_idx as usize]; for _poly in &extra.poly_vars { debug_log!(" * Poly: {}", _poly.display_name(&ctx.heap)); } let mut poly_progress = HashSet::new(); - debug_assert_eq!(extra.embedded.len(), data.values.len()); + debug_assert_eq!(extra.associated.len(), data.values.len()); debug_log!(" * During (inferring types from variant values and union type):"); @@ -3207,7 +3233,7 @@ impl PassTyping { for (value_idx, value_expr_id) in data.values.iter().enumerate() { 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 signature_type: *mut _ = &mut extra.associated[value_idx]; 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, @@ -3253,8 +3279,8 @@ impl PassTyping { debug_log!(" * During (reinferring from progress polyvars):"); // For all embedded values of the union variant - for value_idx in 0..extra.embedded.len() { - let signature_type: *mut _ = &mut extra.embedded[value_idx]; + for value_idx in 0..extra.associated.len() { + let signature_type: *mut _ = &mut extra.associated[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.infer_nodes[value_expr_idx as usize].expr_type; @@ -3463,16 +3489,16 @@ impl PassTyping { debug_log!(" - Expr type: {}", self.debug_get_display_name(ctx, upcast_id)); debug_log!(" * During (inferring types from arguments and return type):"); - let extra = &mut self.extra_data[extra_idx as usize]; + let extra = &mut self.poly_data[extra_idx as usize]; // Check if we can make progress using the arguments and/or return types // while keeping track of the polyvars we've extended let mut poly_progress = HashSet::new(); - debug_assert_eq!(extra.embedded.len(), expr.arguments.len()); + debug_assert_eq!(extra.associated.len(), expr.arguments.len()); 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 signature_type: *mut _ = &mut extra.associated[call_arg_idx]; 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, @@ -3522,8 +3548,8 @@ impl PassTyping { // TODO: @performance If the algorithm is changed to be more "on demand // argument re-evaluation", instead of "all-argument re-evaluation", // then this is no longer true - for arg_idx in 0..extra.embedded.len() { - let signature_type: *mut _ = &mut extra.embedded[arg_idx]; + for arg_idx in 0..extra.associated.len() { + let signature_type: *mut _ = &mut extra.associated[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.infer_nodes[arg_expr_idx as usize].expr_type; @@ -3763,6 +3789,53 @@ impl PassTyping { Ok((infer_res.modified_lhs(), infer_res.modified_rhs())) } + /// Applies an equal2 constraint between a member of the `PolyData` struct, + /// and another inferred type. If any progress is made in the `PolyData` + /// struct then the affected polymorphic variables are updated as well. + /// + /// Because a lot of types/expressions are involved in polymorphic type + /// inference, some explanation: "outer_node" refers to the main expression + /// that is the root cause of type inference (e.g. a struct literal + /// expression, or a tuple member select expression). Associated with that + /// outer node is `PolyData`, so that is what the "poly_data" variables + /// are referring to. We are applying equality between a "poly_data" type + /// and an associated expression (not necessarily the "outer_node", e.g. + /// the expression that constructs the value of a struct field). Hence the + /// "associated" variables. + /// + /// Again a special case: the `associated_expr_id` is only used + fn apply_polydata_equal2_constraint( + &mut self, ctx: &Ctx, + outer_node_index: InferNodeIndex, error_location_expr_id: ExpressionId, error_location_name: &str + poly_data_type: PolyDataTypeIndex, poly_data_start_index: usize, + associated_node_index: InferNodeIndex, associated_node_start_index: usize + ) -> Result<(bool, bool), ParseError> { + let poly_index = self.infer_nodes[outer_node_index].poly_data_index; + let poly_data_type: *mut _ = self.poly_data[poly_index].get_type_mut(poly_data_type); + let associated_type: *mut _ = &mut self.infer_nodes[associated_node_index].expr_type; + + let inference_result = unsafe{ + // Safety: pointers originate from different vectors, so cannot + // alias. + InferenceType::infer_subtrees_for_both_types( + poly_data_type, poly_data_start_index, + associated_type, associated_node_start_index + ) + }; + + let modified_poly_data = inference_result.modified_lhs(); + let modified_associated = inference_result.modified_rhs(); + if inference_result == DualInferenceResult::Incompatible { + let outer_node_expr_id = self.infer_nodes[outer_node_index].expr_id; + let outer_node_span = ctx.heap[outer_node_expr_id].full_span(); + let detailed_span = ctx.heap[error_location_expr_id]. + } + } + + fn apply_polydata_polyvar_constraint() -> bool { + + } + /// Applies an equal2 constraint between a signature type (e.g. a function /// argument or struct field) and an expression whose type should match that /// expression. If we make progress on the signature, then we try to see if @@ -3774,7 +3847,7 @@ impl PassTyping { /// `expression_start_idx` belong to `expr_id`. fn apply_equal2_signature_constraint( ctx: &Ctx, outer_expr_id: ExpressionId, expr_id: Option, - polymorph_data: &mut ExtraData, polymorph_progress: &mut HashSet, + polymorph_data: &mut PolyData, polymorph_progress: &mut HashSet, signature_type: *mut InferenceType, signature_start_idx: usize, expression_type: *mut InferenceType, expression_start_idx: usize ) -> Result<(bool, bool), ParseError> { @@ -3785,7 +3858,7 @@ impl PassTyping { InferenceType::infer_subtrees_for_both_types( signature_type, signature_start_idx, expression_type, expression_start_idx - ) + ) }; if infer_res == DualInferenceResult::Incompatible { @@ -3846,7 +3919,7 @@ impl PassTyping { /// /// This function returns true if the expression's type has been progressed fn apply_equal2_polyvar_constraint( - polymorph_data: &ExtraData, _polymorph_progress: &HashSet, + polymorph_data: &PolyData, _polymorph_progress: &HashSet, signature_type: *mut InferenceType, expr_type: *mut InferenceType ) -> bool { // Safety: all pointers should be distinct @@ -4082,7 +4155,7 @@ impl PassTyping { fn insert_initial_call_polymorph_data( &mut self, ctx: &mut Ctx, call_id: CallExpressionId - ) -> ExtraIndex { + ) -> PolyDataIndex { // 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. @@ -4133,12 +4206,12 @@ impl PassTyping { } }; - let extra_data_idx = self.extra_data.len() as ExtraIndex; - self.extra_data.push(ExtraData{ + let extra_data_idx = self.poly_data.len() as PolyDataIndex; + self.poly_data.push(PolyData { expr_id: call_id.upcast(), definition_id: call.definition, poly_vars: poly_args, - embedded: parameter_types, + associated: parameter_types, returned: return_type }); return extra_data_idx @@ -4146,7 +4219,7 @@ impl PassTyping { fn insert_initial_struct_polymorph_data( &mut self, ctx: &mut Ctx, lit_id: LiteralExpressionId, - ) -> ExtraIndex { + ) -> PolyDataIndex { use InferenceTypePart as ITP; let literal = ctx.heap[lit_id].value.as_struct(); @@ -4195,12 +4268,12 @@ impl PassTyping { debug_assert_eq!(parts.len(), parts_reserved); let return_type = InferenceType::new(!poly_args.is_empty(), return_type_done, parts); - let extra_data_index = self.extra_data.len() as ExtraIndex; - self.extra_data.push(ExtraData{ + let extra_data_index = self.poly_data.len() as PolyDataIndex; + self.poly_data.push(PolyData { expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, - embedded: embedded_types, + associated: embedded_types, returned: return_type, }); @@ -4212,7 +4285,7 @@ impl PassTyping { /// the use of the enum. fn insert_initial_enum_polymorph_data( &mut self, ctx: &Ctx, lit_id: LiteralExpressionId - ) -> ExtraIndex { + ) -> PolyDataIndex { use InferenceTypePart as ITP; let literal = ctx.heap[lit_id].value.as_enum(); @@ -4242,12 +4315,12 @@ impl PassTyping { debug_assert_eq!(parts.len(), parts_reserved); let enum_type = InferenceType::new(!poly_args.is_empty(), enum_type_done, parts); - let extra_data_index = self.extra_data.len() as ExtraIndex; - self.extra_data.push(ExtraData{ + let extra_data_index = self.poly_data.len() as PolyDataIndex; + self.poly_data.push(PolyData { expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, - embedded: Vec::new(), + associated: Vec::new(), returned: enum_type, }); @@ -4258,7 +4331,7 @@ impl PassTyping { /// arguments may be partially determined from embedded values in the union. fn insert_initial_union_polymorph_data( &mut self, ctx: &Ctx, lit_id: LiteralExpressionId - ) -> ExtraIndex { + ) -> PolyDataIndex { use InferenceTypePart as ITP; let literal = ctx.heap[lit_id].value.as_union(); @@ -4303,12 +4376,12 @@ impl PassTyping { debug_assert_eq!(parts_reserved, parts.len()); let union_type = InferenceType::new(!poly_args.is_empty(), union_type_done, parts); - let extra_data_index = self.extra_data.len(); - self.extra_data.push(ExtraData{ + let extra_data_index = self.poly_data.len(); + self.poly_data.push(PolyData { expr_id: lit_id.upcast(), definition_id: literal.definition, poly_vars: poly_args, - embedded, + associated: embedded, returned: union_type }); @@ -4319,7 +4392,7 @@ impl PassTyping { /// expression's referenced (definition_id, field_idx) has been resolved. fn insert_initial_select_polymorph_data( &mut self, ctx: &Ctx, node_index: InferNodeIndex, struct_def_id: DefinitionId - ) -> ExtraIndex { + ) -> PolyDataIndex { use InferenceTypePart as ITP; let definition = ctx.heap[struct_def_id].as_struct(); @@ -4346,11 +4419,11 @@ impl PassTyping { // Generate initial field type let field_type = self.determine_inference_type_from_parser_type_elements(&definition.fields[field_index].parser_type.elements, false); - let extra_data_index = self.extra_data.len() as ExtraIndex; - self.extra_data.push(ExtraData{ + let extra_data_index = self.poly_data.len() as PolyDataIndex; + self.poly_data.push(PolyData { definition_id: struct_def_id, poly_vars, - embedded: vec![InferenceType::new(num_poly_vars != 0, num_poly_vars == 0, struct_parts)], + associated: vec![InferenceType::new(num_poly_vars != 0, num_poly_vars == 0, struct_parts)], returned: field_type }); @@ -4569,7 +4642,7 @@ impl PassTyping { /// We assume that the expression is a function call or a struct literal, /// and that an actual error has occurred. fn construct_poly_arg_error( - ctx: &Ctx, poly_data: &ExtraData, expr_id: ExpressionId + ctx: &Ctx, poly_data: &PolyData, expr_id: ExpressionId ) -> ParseError { // Helper function to check for polymorph mismatch between two inference // types. @@ -4621,7 +4694,7 @@ impl PassTyping { } // Helper function to construct initial error - fn construct_main_error(ctx: &Ctx, poly_data: &ExtraData, poly_var_idx: u32, expr: &Expression) -> ParseError { + fn construct_main_error(ctx: &Ctx, poly_data: &PolyData, poly_var_idx: u32, expr: &Expression) -> ParseError { match expr { Expression::Call(expr) => { let (poly_var, func_name) = get_poly_var_and_definition_name(ctx, poly_var_idx, poly_data.definition_id); @@ -4704,8 +4777,8 @@ impl PassTyping { } // - check arguments with each other argument and with return type - for (arg_a_idx, arg_a) in poly_data.embedded.iter().enumerate() { - for (arg_b_idx, arg_b) in poly_data.embedded.iter().enumerate() { + for (arg_a_idx, arg_a) in poly_data.associated.iter().enumerate() { + for (arg_b_idx, arg_b) in poly_data.associated.iter().enumerate() { if arg_b_idx > arg_a_idx { break; } @@ -4762,7 +4835,7 @@ impl PassTyping { // Now check against the explicitly specified polymorphic variables (if // any). - for (arg_idx, arg) in poly_data.embedded.iter().enumerate() { + for (arg_idx, arg) in poly_data.associated.iter().enumerate() { if let Some((poly_idx, poly_section, arg_section)) = has_explicit_poly_mismatch(&poly_data.poly_vars, arg) { let arg = &ctx.heap[expr_args[arg_idx]]; return construct_main_error(ctx, poly_data, poly_idx, expr)