Skip to content

Commit

Permalink
frontend: Initial implementation of TraitObjectIgnore
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Feb 7, 2025
1 parent 9f1f2cf commit dd15a29
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 18 deletions.
1 change: 1 addition & 0 deletions dora-bytecode/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub struct FunctionData {
pub is_variadic: bool,
pub is_force_inline: bool,
pub is_never_inline: bool,
pub is_trait_object_ignore: bool,
pub bytecode: Option<BytecodeFunction>,
pub trait_method_impl: Option<FunctionId>,
}
Expand Down
4 changes: 2 additions & 2 deletions dora-frontend/src/parsety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};

use crate::access::{sym_accessible_from, trait_accessible_from};
use crate::sema::{
implements_trait, is_object_safe, parent_element_or_self, AliasDefinitionId, Element,
implements_trait, is_trait_object_safe, parent_element_or_self, AliasDefinitionId, Element,
SourceFileId, TraitDefinition, TraitDefinitionId, TypeParamDefinition,
};
use crate::sym::{ModuleSymTable, SymbolKind};
Expand Down Expand Up @@ -867,7 +867,7 @@ fn check_type_trait_object(
sa.report(ctxt_element.file_id(), parsed_ty.span, msg);
}

if !is_object_safe(sa, trait_id) {
if !is_trait_object_safe(sa, trait_id) {
sa.report(
ctxt_element.file_id(),
parsed_ty.span,
Expand Down
2 changes: 2 additions & 0 deletions dora-frontend/src/program_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ fn create_functions(sa: &Sema, e: &mut Emitter) -> Vec<FunctionData> {
is_variadic: fct.params.is_variadic(),
is_force_inline: fct.is_force_inline,
is_never_inline: fct.is_never_inline,
is_trait_object_ignore: fct.is_trait_object_ignore,
bytecode: fct.bytecode.get().cloned(),
trait_method_impl: fct
.trait_method_impl
Expand Down Expand Up @@ -245,6 +246,7 @@ fn create_functions(sa: &Sema, e: &mut Emitter) -> Vec<FunctionData> {
is_variadic: false,
is_force_inline: false,
is_never_inline: false,
is_trait_object_ignore: false,
bytecode: Some(global.bytecode().clone()),
trait_method_impl: None,
});
Expand Down
24 changes: 18 additions & 6 deletions dora-frontend/src/program_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
&node.modifiers,
&[
Annotation::Internal,
Annotation::OptimizeImmediately,
Annotation::Optimize,
Annotation::Test,
Annotation::Pub,
Annotation::ForceInline,
Expand Down Expand Up @@ -919,7 +919,11 @@ fn find_elements_in_trait(
sa,
trait_.file_id,
&method_node.modifiers,
&[Annotation::Static, Annotation::OptimizeImmediately],
&[
Annotation::Static,
Annotation::Optimize,
Annotation::TraitObjectIgnore,
],
);

let container_type_param_definition = trait_.type_param_definition().clone();
Expand Down Expand Up @@ -1226,7 +1230,7 @@ fn find_elements_in_extension(
Annotation::Internal,
Annotation::Static,
Annotation::Pub,
Annotation::OptimizeImmediately,
Annotation::Optimize,
],
);

Expand Down Expand Up @@ -1296,6 +1300,7 @@ pub struct ParsedModifierList {
pub is_internal: bool,
pub is_force_inline: bool,
pub is_never_inline: bool,
pub is_trait_object_ignore: bool,
}

impl ParsedModifierList {
Expand All @@ -1314,10 +1319,11 @@ enum Annotation {
Pub,
Static,
Test,
OptimizeImmediately,
Optimize,
ForceInline,
NeverInline,
Error,
TraitObjectIgnore,
}

impl Annotation {
Expand All @@ -1331,9 +1337,10 @@ impl Annotation {
Annotation::Pub => "pub",
Annotation::Static => "static",
Annotation::Test => "test",
Annotation::OptimizeImmediately => "Optimize",
Annotation::Optimize => "Optimize",
Annotation::ForceInline => "ForceInline",
Annotation::NeverInline => "NeverInline",
Annotation::TraitObjectIgnore => "TraitObjectIgnore",
Annotation::Error => "<error>",
}
}
Expand Down Expand Up @@ -1398,7 +1405,7 @@ fn check_modifier(

"Optimize" => {
parsed_modifiers.is_optimize_immediately = true;
Annotation::OptimizeImmediately
Annotation::Optimize
}

"internal" => {
Expand All @@ -1416,6 +1423,11 @@ fn check_modifier(
Annotation::NeverInline
}

"TraitObjectIgnore" => {
parsed_modifiers.is_trait_object_ignore = true;
Annotation::TraitObjectIgnore
}

_ => {
sa.report(
file_id,
Expand Down
2 changes: 1 addition & 1 deletion dora-frontend/src/sema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub use self::src::{
pub use self::structs::{
StructDefinition, StructDefinitionField, StructDefinitionFieldId, StructDefinitionId,
};
pub use self::traits::{is_object_safe, TraitDefinition, TraitDefinitionId};
pub use self::traits::{is_trait_object_safe, TraitDefinition, TraitDefinitionId};
pub use self::tuples::create_tuple;
pub use self::type_params::{new_identity_type_params, Bound, TypeParamDefinition, TypeParamId};
pub use self::uses::{UseDefinition, UseDefinitionId};
Expand Down
3 changes: 3 additions & 0 deletions dora-frontend/src/sema/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct FctDefinition {
pub is_internal: bool,
pub is_force_inline: bool,
pub is_never_inline: bool,
pub is_trait_object_ignore: bool,
pub params: Params,
pub return_type: ParsedType,

Expand Down Expand Up @@ -86,6 +87,7 @@ impl FctDefinition {
is_internal: modifiers.is_internal,
is_force_inline: modifiers.is_force_inline,
is_never_inline: modifiers.is_never_inline,
is_trait_object_ignore: modifiers.is_trait_object_ignore,
analysis: OnceCell::new(),
type_param_definition: type_params,
container_type_params: OnceCell::new(),
Expand Down Expand Up @@ -128,6 +130,7 @@ impl FctDefinition {
is_internal: modifiers.is_internal,
is_force_inline: modifiers.is_force_inline,
is_never_inline: modifiers.is_never_inline,
is_trait_object_ignore: modifiers.is_trait_object_ignore,
analysis: OnceCell::new(),
type_param_definition: type_params,
container_type_params: OnceCell::new(),
Expand Down
8 changes: 6 additions & 2 deletions dora-frontend/src/sema/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl ElementAccess for TraitDefinition {
}
}

pub fn is_object_safe(sa: &Sema, trait_id: TraitDefinitionId) -> bool {
pub fn is_trait_object_safe(sa: &Sema, trait_id: TraitDefinitionId) -> bool {
let trait_ = sa.trait_(trait_id);

for &alias_id in trait_.aliases() {
Expand All @@ -183,6 +183,10 @@ pub fn is_object_safe(sa: &Sema, trait_id: TraitDefinitionId) -> bool {
for method_id in trait_.methods() {
let method = sa.fct(*method_id);

if method.is_trait_object_ignore {
continue;
}

if method.type_param_definition().has_own_type_params() {
return false;
}
Expand All @@ -204,7 +208,7 @@ pub fn is_object_safe(sa: &Sema, trait_id: TraitDefinitionId) -> bool {

let type_param_definition = trait_.type_param_definition();
for bound in type_param_definition.bounds_for_self() {
if !is_object_safe(sa, bound.trait_id) {
if !is_trait_object_safe(sa, bound.trait_id) {
return false;
}
}
Expand Down
16 changes: 10 additions & 6 deletions dora-frontend/src/typeck/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ pub fn find_method_call_candidates(
if let SourceType::TraitObject(trait_id, trait_type_params, _bindings) = object_type.clone() {
let trait_ = sa.trait_(trait_id);
if let Some(fct_id) = trait_.get_method(name, false) {
candidates.push(Candidate {
object_type: object_type.clone(),
container_type_params: trait_type_params,
fct_id,
});
return candidates;
let method = sa.fct(fct_id);

if !method.is_trait_object_ignore {
candidates.push(Candidate {
object_type: object_type.clone(),
container_type_params: trait_type_params,
fct_id,
});
return candidates;
}
}

find_super_trait_methods_on_trait_object(
Expand Down
14 changes: 14 additions & 0 deletions dora-frontend/src/typeck/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3548,6 +3548,20 @@ fn trait_object_method_call() {
");
}

#[test]
fn trait_object_method_call_with_ignore() {
err(
"
trait Foo { @TraitObjectIgnore fn bar(): Int32; }
fn f(x: Foo): Int32 {
x.bar()
}
",
(4, 13),
ErrorMessage::UnknownMethod("Foo".into(), "bar".into()),
);
}

#[test]
fn trait_object_cast() {
ok("
Expand Down
20 changes: 19 additions & 1 deletion dora-runtime/src/vm/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::vm::{
use crate::{Shape, SpecializeSelf};
use dora_bytecode::{
BytecodeType, BytecodeTypeArray, ClassData, ClassId, EnumData, EnumId, FunctionId, Program,
StructData, StructId, TraitId, TypeParamData,
StructData, StructId, TraitData, TraitId, TypeParamData,
};

pub fn create_struct_instance(
Expand Down Expand Up @@ -467,6 +467,10 @@ pub fn compute_vtable_index(vm: &VM, trait_id: TraitId, trait_fct_id: FunctionId
let vtable_index = trait_
.methods
.iter()
.filter(|id| {
let method = vm.fct(**id);
!method.is_trait_object_ignore
})
.position(|m| *m == trait_fct_id)
.expect("missing trait function");
vtable_index.try_into().expect("overflow")
Expand Down Expand Up @@ -542,6 +546,20 @@ fn create_shape_for_trait_object(
shape
}

fn count_virtual_methods(vm: &VM, trait_: TraitData) -> usize {
let mut count = 0;

for method_id in &trait_.methods {
let method = vm.program.fct(*method_id);

if !method.is_trait_object_ignore {
count += 1;
}
}

count
}

pub fn specialize_bty_array(
types: &BytecodeTypeArray,
type_params: &BytecodeTypeArray,
Expand Down
6 changes: 6 additions & 0 deletions tests/trait/trait-default-count.dora
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,10 @@ impl MyIterator for Range {
fn main() {
assert(Range(2).count() == 2);
assert(Range(7).count() == 7);

let it = Range(3) as MyIterator[Item = Int];
assert(it.count() == 3);

let it = Range(7) as MyIterator[Item = Int];
assert(it.count() == 7);
}
6 changes: 6 additions & 0 deletions tests/trait/trait-default-enumerate.dora
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ trait MyIterator {
type Item;
fn next(): Option[Self::Item];

@TraitObjectIgnore
fn enumerate(): Enumerate[Self] {
Enumerate[Self](it = self, idx = 0)
}
Expand Down Expand Up @@ -50,4 +51,9 @@ fn main() {
assert(Some[(Int, Int)]((0, 2)) == r.next());
assert(Some[(Int, Int)]((1, 1)) == r.next());
assert(r.next().isNone());

let it = Range(2) as MyIterator[Item = Int];
assert(Some[Int](2) == it.next());
assert(Some[Int](1) == it.next());
assert(it.next().isNone());
}
16 changes: 16 additions & 0 deletions tests/trait/trait-object-ignore1.dora
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//= ignore

trait Foo {
fn one(): Int { 1 }
@TraitObjectIgnore
fn two(): Int { 2 }
fn three(): Int { 3 }
}

impl Foo for Int {}

fn main() {
let x = 1 as Foo;
assert(x.one() == 1);
assert(x.three() == 3);
}

0 comments on commit dd15a29

Please sign in to comment.