Skip to content

Commit

Permalink
boots: Support fct type params for generic methods
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Feb 12, 2025
1 parent ed95902 commit f582741
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 106 deletions.
4 changes: 2 additions & 2 deletions dora-bytecode/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
18 changes: 13 additions & 5 deletions dora-bytecode/src/dumper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(),
Expand Down
85 changes: 55 additions & 30 deletions dora-frontend/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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(..)
Expand Down
10 changes: 0 additions & 10 deletions dora-frontend/src/generator/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions dora-frontend/src/generator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ fn gen_generic_not() {
&ConstPoolEntry::Generic(
0,
FunctionId(fct_id.index().try_into().expect("overflow")),
BytecodeTypeArray::empty(),
BytecodeTypeArray::empty()
)
);
Expand Down Expand Up @@ -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()
)
);
Expand Down
24 changes: 18 additions & 6 deletions dora-frontend/src/sema/src.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,21 +353,33 @@ 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(
TypeParamId,
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(<args>).
NewClass(ClassDefinitionId, SourceTypeArray),
Expand Down Expand Up @@ -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(..)
Expand Down
11 changes: 7 additions & 4 deletions dora-frontend/src/typeck/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down Expand Up @@ -903,6 +904,7 @@ fn check_expr_call_self(
trait_method.trait_id(),
trait_method_id,
trait_type_params.clone(),
SourceTypeArray::empty(),
)),
);

Expand Down Expand Up @@ -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());
Expand All @@ -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,
Expand Down Expand Up @@ -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));

Expand Down
2 changes: 2 additions & 0 deletions dora-frontend/src/typeck/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,7 @@ fn check_expr_un_trait(
trait_id,
method_id,
SourceTypeArray::empty(),
SourceTypeArray::empty(),
);
ck.analysis
.map_calls
Expand Down Expand Up @@ -1710,6 +1711,7 @@ fn check_expr_bin_trait(
trait_id,
method_id,
SourceTypeArray::empty(),
SourceTypeArray::empty(),
);
ck.analysis
.map_calls
Expand Down
10 changes: 6 additions & 4 deletions dora-runtime/src/boots/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
44 changes: 26 additions & 18 deletions dora-runtime/src/cannon/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand All @@ -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,
Expand Down
Loading

0 comments on commit f582741

Please sign in to comment.