From f582741df4923ffa29b8a1735e0a1add3e7de425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Inf=C3=BChr?= Date: Wed, 12 Feb 2025 22:49:43 +0100 Subject: [PATCH] boots: Support fct type params for generic methods --- dora-bytecode/src/data.rs | 4 +- dora-bytecode/src/dumper.rs | 18 ++-- dora-frontend/src/generator.rs | 85 ++++++++++++------- dora-frontend/src/generator/bytecode.rs | 10 --- dora-frontend/src/generator/tests.rs | 2 + dora-frontend/src/sema/src.rs | 24 ++++-- dora-frontend/src/typeck/call.rs | 11 ++- dora-frontend/src/typeck/expr.rs | 2 + dora-runtime/src/boots/serializer.rs | 10 ++- dora-runtime/src/cannon/codegen.rs | 44 ++++++---- dora-runtime/src/compiler/aot.rs | 27 +++--- .../src/compiler/trait_object_thunk.rs | 1 + pkgs/boots/bytecode/data.dora | 26 +++++- pkgs/boots/deserializer.dora | 10 ++- pkgs/boots/graph_builder.dora | 26 ++++-- 15 files changed, 194 insertions(+), 106 deletions(-) diff --git a/dora-bytecode/src/data.rs b/dora-bytecode/src/data.rs index 516acfe04..179c8c989 100644 --- a/dora-bytecode/src/data.rs +++ b/dora-bytecode/src/data.rs @@ -705,8 +705,8 @@ pub enum ConstPoolEntry { Field(ClassId, BytecodeTypeArray, u32), Fct(FunctionId, BytecodeTypeArray), TraitObjectMethod(BytecodeType, FunctionId), - Generic(u32, FunctionId, BytecodeTypeArray), - GenericSelf(FunctionId, BytecodeTypeArray), + Generic(u32, FunctionId, BytecodeTypeArray, BytecodeTypeArray), + GenericSelf(FunctionId, BytecodeTypeArray, BytecodeTypeArray), Enum(EnumId, BytecodeTypeArray), EnumVariant(EnumId, BytecodeTypeArray, u32), EnumElement(EnumId, BytecodeTypeArray, u32, u32), diff --git a/dora-bytecode/src/dumper.rs b/dora-bytecode/src/dumper.rs index c4fdf0180..d8b7807e1 100644 --- a/dora-bytecode/src/dumper.rs +++ b/dora-bytecode/src/dumper.rs @@ -162,23 +162,31 @@ pub fn dump(w: &mut dyn io::Write, prog: &Program, bc: &BytecodeFunction) -> std &display_fct(prog, *fct_id) )?; } - ConstPoolEntry::Generic(id, fct_id, type_params) => { + ConstPoolEntry::Generic(id, fct_id, trait_type_params, fct_type_params) => { writeln!( w, "{}{} => TypeParam({}) Method {}", align, idx, id, - fmt_name(prog, &display_fct(prog, *fct_id), &type_params) + fmt_name( + prog, + &display_fct(prog, *fct_id), + &trait_type_params.connect(fct_type_params) + ) )?; } - ConstPoolEntry::GenericSelf(fct_id, type_params) => { + ConstPoolEntry::GenericSelf(fct_id, trait_type_params, fct_type_params) => { writeln!( w, "{}{} => Self::Method {}", align, idx, - fmt_name(prog, &display_fct(prog, *fct_id), &type_params) + fmt_name( + prog, + &display_fct(prog, *fct_id), + &trait_type_params.connect(fct_type_params) + ) )?; } ConstPoolEntry::TraitObject { @@ -528,7 +536,7 @@ impl<'a> BytecodeDumper<'a> { fn get_fct_name(&mut self, idx: ConstPoolIdx) -> String { let fct_id = match self.bc.const_pool(idx) { ConstPoolEntry::Fct(fct_id, _) - | ConstPoolEntry::Generic(_, fct_id, _) + | ConstPoolEntry::Generic(_, fct_id, _, _) | ConstPoolEntry::GenericSelf(fct_id, ..) | ConstPoolEntry::TraitObjectMethod(_, fct_id) => fct_id, ConstPoolEntry::Lambda(_, _) => return "lambda".into(), diff --git a/dora-frontend/src/generator.rs b/dora-frontend/src/generator.rs index 60bfab119..74446b980 100644 --- a/dora-frontend/src/generator.rs +++ b/dora-frontend/src/generator.rs @@ -1097,11 +1097,12 @@ impl<'a> AstBytecodeGen<'a> { .get_method(name, false) .expect("Stringable::toString() not found"); - let fct_idx = self.builder.add_const_generic( + let fct_idx = self.builder.add_const(ConstPoolEntry::Generic( type_list_id.index() as u32, FunctionId(to_string_id.index().try_into().expect("overflow")), BytecodeTypeArray::empty(), - ); + BytecodeTypeArray::empty(), + )); self.builder.emit_invoke_generic_direct( part_register, @@ -3189,25 +3190,26 @@ impl<'a> AstBytecodeGen<'a> { call_type: &CallType, ) -> ConstPoolIdx { match call_type { - CallType::GenericStaticMethod(id, .., ref type_params) - | CallType::GenericMethod(id, .., ref type_params) => { - assert_eq!( - fct.type_param_definition().type_param_count(), - type_params.len() - ); - self.builder.add_const_generic( + CallType::GenericStaticMethod(id, .., ref trait_type_params, ref fct_type_params) + | CallType::GenericMethod(id, .., ref trait_type_params, ref fct_type_params) => { + self.builder.add_const(ConstPoolEntry::Generic( id.index() as u32, FunctionId(fct.id().index().try_into().expect("overflow")), - bty_array_from_ty(&type_params), - ) - } - CallType::GenericMethodSelf(_, fct_id, type_params) - | CallType::GenericStaticMethodSelf(_, fct_id, type_params) => { - self.builder.add_const(ConstPoolEntry::GenericSelf( - FunctionId(fct_id.index().try_into().expect("overflow")), - bty_array_from_ty(&type_params), + bty_array_from_ty(&trait_type_params), + bty_array_from_ty(&fct_type_params), )) } + CallType::GenericMethodSelf(_, fct_id, ref trait_type_params, ref fct_type_params) + | CallType::GenericStaticMethodSelf( + _, + fct_id, + ref trait_type_params, + ref fct_type_params, + ) => self.builder.add_const(ConstPoolEntry::GenericSelf( + FunctionId(fct_id.index().try_into().expect("overflow")), + bty_array_from_ty(&trait_type_params), + bty_array_from_ty(&fct_type_params), + )), CallType::TraitObjectMethod(ref trait_object_ty, _) => { self.builder.add_const(ConstPoolEntry::TraitObjectMethod( bty_from_ty(trait_object_ty.clone()), @@ -3247,20 +3249,43 @@ impl<'a> AstBytecodeGen<'a> { }; specialize_ty_for_trait_object(self.sa, ty, trait_id, type_params, assoc_types) } - CallType::GenericMethod(id, _trait_id, _method_id, type_params) - | CallType::GenericStaticMethod(id, _trait_id, _method_id, type_params) => { - replace_type( - self.sa, - ty, - Some(type_params), - Some(SourceType::TypeParam(*id)), - ) - } + CallType::GenericMethod( + id, + _trait_id, + _method_id, + ref trait_type_params, + ref fct_type_params, + ) + | CallType::GenericStaticMethod( + id, + _trait_id, + _method_id, + ref trait_type_params, + ref fct_type_params, + ) => replace_type( + self.sa, + ty, + Some(&trait_type_params.connect(fct_type_params)), + Some(SourceType::TypeParam(*id)), + ), - CallType::GenericMethodSelf(_trait_id, _fct_id, type_params) - | CallType::GenericStaticMethodSelf(_trait_id, _fct_id, type_params) => { - replace_type(self.sa, ty, Some(type_params), None) - } + CallType::GenericMethodSelf( + _trait_id, + _fct_id, + ref trait_type_params, + ref fct_type_params, + ) + | CallType::GenericStaticMethodSelf( + _trait_id, + _fct_id, + ref trait_type_params, + ref fct_type_params, + ) => replace_type( + self.sa, + ty, + Some(&trait_type_params.connect(fct_type_params)), + None, + ), CallType::Lambda(..) | CallType::NewClass(..) diff --git a/dora-frontend/src/generator/bytecode.rs b/dora-frontend/src/generator/bytecode.rs index 024bbc67b..90fd3d951 100644 --- a/dora-frontend/src/generator/bytecode.rs +++ b/dora-frontend/src/generator/bytecode.rs @@ -113,16 +113,6 @@ impl BytecodeBuilder { self.writer.add_const(ConstPoolEntry::Fct(id, type_params)) } - pub fn add_const_generic( - &mut self, - id: u32, - fct_id: FunctionId, - type_params: BytecodeTypeArray, - ) -> ConstPoolIdx { - self.writer - .add_const(ConstPoolEntry::Generic(id, fct_id, type_params)) - } - pub fn add_const_field_types( &mut self, cls_id: ClassId, diff --git a/dora-frontend/src/generator/tests.rs b/dora-frontend/src/generator/tests.rs index dbde60e03..698b32658 100644 --- a/dora-frontend/src/generator/tests.rs +++ b/dora-frontend/src/generator/tests.rs @@ -301,6 +301,7 @@ fn gen_generic_not() { &ConstPoolEntry::Generic( 0, FunctionId(fct_id.index().try_into().expect("overflow")), + BytecodeTypeArray::empty(), BytecodeTypeArray::empty() ) ); @@ -4391,6 +4392,7 @@ fn gen_comparable_trait_generic() { &ConstPoolEntry::Generic( 0, FunctionId(cmp_fct_id.index().try_into().expect("overflow")), + BytecodeTypeArray::empty(), BytecodeTypeArray::empty() ) ); diff --git a/dora-frontend/src/sema/src.rs b/dora-frontend/src/sema/src.rs index 2dc2fbf46..7760b50e4 100644 --- a/dora-frontend/src/sema/src.rs +++ b/dora-frontend/src/sema/src.rs @@ -353,10 +353,16 @@ pub enum CallType { TraitDefinitionId, FctDefinitionId, SourceTypeArray, + SourceTypeArray, ), // Invoke trait method from a default trait method, e.g. self.method(). - GenericMethodSelf(TraitDefinitionId, FctDefinitionId, SourceTypeArray), + GenericMethodSelf( + TraitDefinitionId, + FctDefinitionId, + SourceTypeArray, + SourceTypeArray, + ), // Invoke static trait method on type param, e.g. T::method() GenericStaticMethod( @@ -364,10 +370,16 @@ pub enum CallType { TraitDefinitionId, FctDefinitionId, SourceTypeArray, + SourceTypeArray, ), // Invoke static trait method from a default trait method, e.g. Self::method(). - GenericStaticMethodSelf(TraitDefinitionId, FctDefinitionId, SourceTypeArray), + GenericStaticMethodSelf( + TraitDefinitionId, + FctDefinitionId, + SourceTypeArray, + SourceTypeArray, + ), // Class constructor of new class syntax, i.e. ClassName(). NewClass(ClassDefinitionId, SourceTypeArray), @@ -420,10 +432,10 @@ impl CallType { | CallType::Method(_, fct_id, _) | CallType::Expr(_, fct_id, _) | CallType::TraitObjectMethod(_, fct_id) - | CallType::GenericMethod(_, _, fct_id, _) - | CallType::GenericStaticMethod(_, _, fct_id, _) - | CallType::GenericMethodSelf(_, fct_id, _) - | CallType::GenericStaticMethodSelf(_, fct_id, _) => Some(fct_id), + | CallType::GenericMethod(_, _, fct_id, ..) + | CallType::GenericStaticMethod(_, _, fct_id, ..) + | CallType::GenericMethodSelf(_, fct_id, ..) + | CallType::GenericStaticMethodSelf(_, fct_id, ..) => Some(fct_id), CallType::NewClass(..) | CallType::NewStruct(..) diff --git a/dora-frontend/src/typeck/call.rs b/dora-frontend/src/typeck/call.rs index 8700cbd56..e08bad9c2 100644 --- a/dora-frontend/src/typeck/call.rs +++ b/dora-frontend/src/typeck/call.rs @@ -149,7 +149,8 @@ fn check_expr_call_generic_static_method( tp_id, trait_ty.trait_id, trait_method_id, - combined_fct_type_params.clone(), + trait_ty.type_params.clone(), + pure_fct_type_params, ); ck.analysis.map_calls.insert(e.id, Arc::new(call_type)); @@ -903,6 +904,7 @@ fn check_expr_call_self( trait_method.trait_id(), trait_method_id, trait_type_params.clone(), + SourceTypeArray::empty(), )), ); @@ -953,7 +955,7 @@ fn check_expr_call_generic_type_param( object_type: SourceType, id: TypeParamId, name: String, - _pure_fct_type_params: SourceTypeArray, + pure_fct_type_params: SourceTypeArray, arguments: CallArguments, ) -> SourceType { assert!(object_type.is_type_param()); @@ -974,7 +976,7 @@ fn check_expr_call_generic_type_param( let (trait_method_id, trait_ty) = matched_methods.pop().expect("missing element"); let trait_method = ck.sa.fct(trait_method_id); - let combined_fct_type_params = trait_ty.type_params.connect(&_pure_fct_type_params); + let combined_fct_type_params = trait_ty.type_params.connect(&pure_fct_type_params); if check_type_params( ck.sa, @@ -1010,7 +1012,8 @@ fn check_expr_call_generic_type_param( id, trait_method.trait_id(), trait_method_id, - combined_fct_type_params.clone(), + trait_ty.type_params.clone(), + pure_fct_type_params, ); ck.analysis.map_calls.insert(e.id, Arc::new(call_type)); diff --git a/dora-frontend/src/typeck/expr.rs b/dora-frontend/src/typeck/expr.rs index e8b1b0510..d3bd79903 100644 --- a/dora-frontend/src/typeck/expr.rs +++ b/dora-frontend/src/typeck/expr.rs @@ -1394,6 +1394,7 @@ fn check_expr_un_trait( trait_id, method_id, SourceTypeArray::empty(), + SourceTypeArray::empty(), ); ck.analysis .map_calls @@ -1710,6 +1711,7 @@ fn check_expr_bin_trait( trait_id, method_id, SourceTypeArray::empty(), + SourceTypeArray::empty(), ); ck.analysis .map_calls diff --git a/dora-runtime/src/boots/serializer.rs b/dora-runtime/src/boots/serializer.rs index 7b69cc27d..c7a10ee29 100644 --- a/dora-runtime/src/boots/serializer.rs +++ b/dora-runtime/src/boots/serializer.rs @@ -373,16 +373,18 @@ fn encode_constpool_entry(vm: &VM, const_entry: &ConstPoolEntry, buffer: &mut By encode_bytecode_type(vm, trait_object_ty, buffer); buffer.emit_id(fct_id.0 as usize); } - &ConstPoolEntry::Generic(tp_id, fct_id, ref source_type_array) => { + &ConstPoolEntry::Generic(tp_id, fct_id, ref trait_type_params, ref fct_type_params) => { buffer.emit_u8(ConstPoolOpcode::Generic.into()); buffer.emit_id(tp_id as usize); buffer.emit_id(fct_id.0 as usize); - encode_bytecode_type_array(vm, source_type_array, buffer); + encode_bytecode_type_array(vm, trait_type_params, buffer); + encode_bytecode_type_array(vm, fct_type_params, buffer); } - &ConstPoolEntry::GenericSelf(fct_id, ref source_type_array) => { + &ConstPoolEntry::GenericSelf(fct_id, ref trait_type_params, ref fct_type_params) => { buffer.emit_u8(ConstPoolOpcode::GenericSelf.into()); buffer.emit_id(fct_id.0 as usize); - encode_bytecode_type_array(vm, source_type_array, buffer); + encode_bytecode_type_array(vm, trait_type_params, buffer); + encode_bytecode_type_array(vm, fct_type_params, buffer); } &ConstPoolEntry::Class(cls_id, ref source_type_array) => { buffer.emit_u8(ConstPoolOpcode::Class.into()); diff --git a/dora-runtime/src/cannon/codegen.rs b/dora-runtime/src/cannon/codegen.rs index fbff00ef2..fb4828f5e 100644 --- a/dora-runtime/src/cannon/codegen.rs +++ b/dora-runtime/src/cannon/codegen.rs @@ -2635,20 +2635,27 @@ impl<'a> CannonCodeGen<'a> { } fn emit_invoke_generic(&mut self, dest: Register, fct_idx: ConstPoolIdx, is_static: bool) { - let (ty, trait_fct_id, type_params) = match self.bytecode.const_pool(fct_idx) { - ConstPoolEntry::Generic(id, fct_id, type_params) => ( - self.type_params[*id as usize].clone(), - *fct_id, - type_params.clone(), - ), - ConstPoolEntry::GenericSelf(fct_id, type_params) => { - let specialize_self = self.specialize_self.as_ref().expect("missing Self type"); - let extended_ty = self.specialize_ty(specialize_self.extended_ty.clone()); - - (extended_ty, *fct_id, type_params.clone()) - } - _ => unreachable!(), - }; + let (ty, trait_fct_id, trait_type_params, pure_fct_type_params) = + match self.bytecode.const_pool(fct_idx) { + ConstPoolEntry::Generic(id, fct_id, trait_type_params, fct_type_params) => ( + self.type_params[*id as usize].clone(), + *fct_id, + trait_type_params.clone(), + fct_type_params.clone(), + ), + ConstPoolEntry::GenericSelf(fct_id, trait_type_params, fct_type_params) => { + let specialize_self = self.specialize_self.as_ref().expect("missing Self type"); + let extended_ty = self.specialize_ty(specialize_self.extended_ty.clone()); + + ( + extended_ty, + *fct_id, + trait_type_params.clone(), + fct_type_params.clone(), + ) + } + _ => unreachable!(), + }; assert!(ty.is_concrete_type()); @@ -2658,10 +2665,11 @@ impl<'a> CannonCodeGen<'a> { _ => unreachable!(), }; - let type_params = self.specialize_ty_array(&type_params); - assert!(type_params.is_concrete_type()); - let (trait_type_params, pure_fct_type_params) = - type_params.split(fct.type_params.container_count); + let trait_type_params = self.specialize_ty_array(&trait_type_params); + assert!(trait_type_params.is_concrete_type()); + + let pure_fct_type_params = self.specialize_ty_array(&pure_fct_type_params); + assert!(pure_fct_type_params.is_concrete_type()); let trait_ty = BytecodeTraitType { trait_id, diff --git a/dora-runtime/src/compiler/aot.rs b/dora-runtime/src/compiler/aot.rs index 21917ad58..a139ce14e 100644 --- a/dora-runtime/src/compiler/aot.rs +++ b/dora-runtime/src/compiler/aot.rs @@ -280,23 +280,26 @@ impl<'a> TransitiveClosureComputation<'a> { | BytecodeInstruction::InvokeGenericStatic { fct, .. } => { let generic_ty; let callee_trait_fct_id; - let callee_type_params; + let callee_trait_type_params; + let callee_fct_type_params; match bytecode_function.const_pool(fct) { - ConstPoolEntry::Generic(id, fct_id, fct_type_params) => { + ConstPoolEntry::Generic(id, fct_id, trait_type_params, fct_type_params) => { generic_ty = type_params[*id as usize].clone(); callee_trait_fct_id = *fct_id; - callee_type_params = fct_type_params.clone(); + callee_trait_type_params = trait_type_params.clone(); + callee_fct_type_params = fct_type_params.clone(); } - ConstPoolEntry::GenericSelf(fct_id, fct_type_params) => { + ConstPoolEntry::GenericSelf(fct_id, trait_type_params, fct_type_params) => { generic_ty = specialize_self .as_ref() .expect("missing Self type") .extended_ty .clone(); callee_trait_fct_id = *fct_id; - callee_type_params = fct_type_params.clone(); + callee_trait_type_params = trait_type_params.clone(); + callee_fct_type_params = fct_type_params.clone(); } _ => unreachable!(), @@ -308,18 +311,22 @@ impl<'a> TransitiveClosureComputation<'a> { FunctionKind::Trait(trait_id) => trait_id, _ => unreachable!(), }; + + let callee_trait_type_params = + specialize_bty_array(&callee_trait_type_params, &type_params); + let trait_ty = BytecodeTraitType { trait_id, - type_params: callee_type_params.clone(), + type_params: callee_trait_type_params.clone(), bindings: Vec::new(), }; - let (callee_id, callee_type_params) = + let (callee_id, callee_container_bindings) = find_trait_impl(self.vm, callee_trait_fct_id, trait_ty, generic_ty); - let callee_type_params = - specialize_bty_array(&callee_type_params, &type_params); - self.push(callee_id, callee_type_params); + let combined_type_params = + callee_container_bindings.connect(&callee_fct_type_params); + self.push(callee_id, combined_type_params); } BytecodeInstruction::NewLambda { idx, .. } => { diff --git a/dora-runtime/src/compiler/trait_object_thunk.rs b/dora-runtime/src/compiler/trait_object_thunk.rs index 526d486cb..aa0a58d09 100644 --- a/dora-runtime/src/compiler/trait_object_thunk.rs +++ b/dora-runtime/src/compiler/trait_object_thunk.rs @@ -190,6 +190,7 @@ fn generate_bytecode_for_thunk( trait_object_type_param_id.try_into().expect("does not fit"), fct_id, trait_object_ty.type_params(), + BytecodeTypeArray::empty(), )); let return_ty = specialize_bty_for_trait_object( diff --git a/pkgs/boots/bytecode/data.dora b/pkgs/boots/bytecode/data.dora index af6b0441d..2a5d5947c 100644 --- a/pkgs/boots/bytecode/data.dora +++ b/pkgs/boots/bytecode/data.dora @@ -78,8 +78,8 @@ pub enum ConstPoolEntry { Field(ClassId, Array[BytecodeType], ClassFieldId), Fct(FunctionId, Array[BytecodeType]), TraitObjectMethod(BytecodeType, FunctionId), - Generic(Int32, FunctionId, Array[BytecodeType]), - GenericSelf(FunctionId, Array[BytecodeType]), + Generic(Int32, FunctionId, Array[BytecodeType], Array[BytecodeType]), + GenericSelf(FunctionId, Array[BytecodeType], Array[BytecodeType]), Enum(EnumId, Array[BytecodeType]), EnumVariant(EnumId, Array[BytecodeType], Int32), EnumElement(EnumId, Array[BytecodeType], Int32, Int32), @@ -149,8 +149,8 @@ impl Stringable for ConstPoolEntry { ConstPoolEntry::Field(id, typeParams, fieldId) => "Field ${id}${typeParams}.${fieldId}", ConstPoolEntry::Fct(id, typeParams) => "Fct ${id}${typeParams}", ConstPoolEntry::TraitObjectMethod(ty, id) => "TraitObjectMethod ${ty} ${id}", - ConstPoolEntry::Generic(tp, id, typeParams) => "Generic ${tp} ${id}${typeParams}", - ConstPoolEntry::GenericSelf(id, typeParams) => "GenericSelf ${id}${typeParams}", + ConstPoolEntry::Generic(tp, id, traitTypeParams, fctTypeParams) => "Generic ${tp} ${id}${traitTypeParams}${fctTypeParams}", + ConstPoolEntry::GenericSelf(id, traitTypeParams, fctTypeParams) => "GenericSelf ${id}${traitTypeParams}${fctTypeParams}", ConstPoolEntry::Enum(id, typeParams) => "Enum ${id}${typeParams}", ConstPoolEntry::EnumVariant(id, typeParams, variant) => "EnumVariant ${id}${typeParams}::${variant}", ConstPoolEntry::EnumElement(id, typeParams, variant, element) => "EnumVariant ${id}${typeParams}::${variant}.${element}", @@ -481,6 +481,7 @@ impl Stringable for BytecodeType { pub trait BytecodeTypeArrayExt { fn isGeneric(): Bool; + fn append(other: Array[BytecodeType]): Array[BytecodeType]; } impl BytecodeTypeArrayExt for Array[BytecodeType] { @@ -493,6 +494,23 @@ impl BytecodeTypeArrayExt for Array[BytecodeType] { false } + + fn append(other: Array[BytecodeType]): Array[BytecodeType] { + let result = Array[BytecodeType]::fill(self.size() + other.size(), BytecodeType::Unit); + let mut target = 0; + + for value in self { + result(target) = value; + target += 1; + } + + for value in other { + result(target) = value; + target += 1; + } + + result + } } pub struct Location { diff --git a/pkgs/boots/deserializer.dora b/pkgs/boots/deserializer.dora index 6594fd9af..9c826b294 100644 --- a/pkgs/boots/deserializer.dora +++ b/pkgs/boots/deserializer.dora @@ -286,12 +286,14 @@ fn decodeConstPoolEntry(reader: ByteReader): ConstPoolEntry { } else if opcode == opc::CONSTPOOL_OPCODE_GENERIC { let idx = reader.readInt32(); let fct_id = FunctionId(reader.readInt32()); - let type_params = decodeBytecodeTypeArray(reader); - ConstPoolEntry::Generic(idx, fct_id, type_params) + let trait_type_params = decodeBytecodeTypeArray(reader); + let fct_type_params = decodeBytecodeTypeArray(reader); + ConstPoolEntry::Generic(idx, fct_id, trait_type_params, fct_type_params) } else if opcode == opc::CONSTPOOL_OPCODE_GENERIC_SELF { let fct_id = FunctionId(reader.readInt32()); - let type_params = decodeBytecodeTypeArray(reader); - ConstPoolEntry::GenericSelf(fct_id, type_params) + let trait_type_params = decodeBytecodeTypeArray(reader); + let fct_type_params = decodeBytecodeTypeArray(reader); + ConstPoolEntry::GenericSelf(fct_id, trait_type_params, fct_type_params) } else if opcode == opc::CONSTPOOL_OPCODE_ENUM { let enum_id = EnumId(reader.readInt32()); let type_params = decodeBytecodeTypeArray(reader); diff --git a/pkgs/boots/graph_builder.dora b/pkgs/boots/graph_builder.dora index 99afcb953..75a8bf50b 100644 --- a/pkgs/boots/graph_builder.dora +++ b/pkgs/boots/graph_builder.dora @@ -1467,32 +1467,40 @@ impl SsaGen { fn emitInvokeGeneric(dest: BytecodeRegister, idx: ConstPoolId, kind: CallKind): Bool { let ty = self.regGraphTy(dest); - let (object_ty, trait_fct_id, trait_type_params) = match self.bc.constPool(idx) { - ConstPoolEntry::Generic(type_param_idx, trait_fct_id, trait_type_params) => { - (self.typeParams(type_param_idx.toInt64()), trait_fct_id, trait_type_params) + let (object_ty, trait_fct_id, trait_type_params, fct_type_params) = match self.bc.constPool(idx) { + ConstPoolEntry::Generic(type_param_idx, trait_fct_id, trait_type_params, fct_type_params) => { + (self.typeParams(type_param_idx.toInt64()), trait_fct_id, trait_type_params, fct_type_params) } - ConstPoolEntry::GenericSelf(trait_fct_id, trait_type_params) => { + ConstPoolEntry::GenericSelf(trait_fct_id, trait_type_params, fct_type_params) => { let extended_ty = self.specializeSelf.getOrPanic().extended_ty; let extended_ty = self.specializeTy(extended_ty); - (extended_ty, trait_fct_id, trait_type_params) + (extended_ty, trait_fct_id, trait_type_params, fct_type_params) } - _ => unreachable[(BytecodeType, FunctionId, Array[BytecodeType])](), + _ => unreachable[(BytecodeType, FunctionId, Array[BytecodeType], Array[BytecodeType])](), }; assert(!object_ty.isGeneric()); - let (callee_id, type_params) = iface::findTraitImpl(self.ci, trait_fct_id, trait_type_params, object_ty); + let trait_type_params = self.specializeArray(trait_type_params); + assert(!trait_type_params.isGeneric()); + + let fct_type_params = self.specializeArray(fct_type_params); + assert(!fct_type_params.isGeneric()); + + let (callee_id, container_bindings) = iface::findTraitImpl(self.ci, trait_fct_id, trait_type_params, object_ty); + let combined_type_params = container_bindings.append(fct_type_params); + assert(!combined_type_params.isGeneric()); let intrinsic = iface::getIntrinsicForFunction(callee_id); if self.isIntrinsic(intrinsic) { let args = self.pushed_registers.toArray(); self.pushed_registers.clear(); - self.emitIntrinsic(intrinsic, dest, args, idx, type_params) + self.emitIntrinsic(intrinsic, dest, args, idx, combined_type_params) } else { - self.emitCall(dest, kind, callee_id, type_params); + self.emitCall(dest, kind, callee_id, combined_type_params); false } }