Skip to content

Commit

Permalink
frontend: Start supporting super traits and calls
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Oct 15, 2024
1 parent 414f132 commit a7dfade
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 10 deletions.
22 changes: 17 additions & 5 deletions dora-frontend/src/parsety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -868,8 +868,9 @@ fn check_type_trait_object(
new_bindings.push((alias_id, ty));
}

let result = if check_trait_type_params(
let result = if check_trait_type_param_definition(
sa,
element,
trait_,
&new_type_params,
&new_bindings,
Expand Down Expand Up @@ -945,8 +946,9 @@ fn check_trait_type_inner(
new_bindings.push((*alias_id, ty));
}

if check_trait_type_params(
if check_trait_type_param_definition(
sa,
element,
trait_,
&new_type_params,
&new_bindings,
Expand All @@ -956,7 +958,7 @@ fn check_trait_type_inner(
) {
Some(TraitType {
trait_id: trait_ty.trait_id,
type_params: SourceTypeArray::with(new_type_params),
type_params: new_type_params.into(),
bindings: new_bindings,
})
} else {
Expand Down Expand Up @@ -1005,8 +1007,9 @@ fn check_type_params(
success
}

fn check_trait_type_params(
fn check_trait_type_param_definition(
sa: &Sema,
element: &dyn Element,
trait_: &TraitDefinition,
generic_arguments: &[SourceType],
type_bindings: &[(AliasDefinitionId, SourceType)],
Expand All @@ -1020,7 +1023,16 @@ fn check_trait_type_params(
let mut success = true;

for bound in type_param_definition.bounds() {
let tp_ty = bound.ty();
let mut tp_ty = bound.ty();

if tp_ty.is_self() {
if element.is_impl() {
let impl_ = element.to_impl().expect("impl expected");
tp_ty = impl_.extended_ty();
} else {
continue;
}
}

if let Some(trait_ty) = bound.trait_ty() {
let tp_ty = specialize_type(sa, tp_ty, &type_arguments);
Expand Down
21 changes: 20 additions & 1 deletion dora-frontend/src/program_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
Some(&node.bounds),
self.file_id,
);

Expand Down Expand Up @@ -552,6 +553,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -644,6 +646,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -703,6 +706,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -745,6 +749,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -823,6 +828,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -863,6 +869,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
None,
node.type_params.as_ref(),
node.pre_where_bounds.as_ref(),
None,
self.file_id,
);

Expand Down Expand Up @@ -934,6 +941,7 @@ fn find_elements_in_trait(
Some(container_type_param_definition),
method_node.type_params.as_ref(),
method_node.where_bounds.as_ref(),
None,
file_id,
);

Expand Down Expand Up @@ -1017,6 +1025,7 @@ fn find_elements_in_trait(
Some(container_type_param_definition),
node.type_params.as_ref(),
where_bounds,
None,
file_id,
);

Expand Down Expand Up @@ -1101,6 +1110,7 @@ fn find_elements_in_impl(
Some(container_type_param_definition),
method_node.type_params.as_ref(),
method_node.where_bounds.as_ref(),
None,
file_id,
);

Expand Down Expand Up @@ -1158,6 +1168,7 @@ fn find_elements_in_impl(
Some(container_type_param_definition),
node.type_params.as_ref(),
where_bounds,
None,
file_id,
);

Expand Down Expand Up @@ -1231,6 +1242,7 @@ fn find_elements_in_extension(
Some(container_type_param_definition),
method_node.type_params.as_ref(),
method_node.where_bounds.as_ref(),
None,
extension.file_id,
);

Expand Down Expand Up @@ -1498,6 +1510,7 @@ fn parse_type_param_definition(
parent: Option<Rc<TypeParamDefinition>>,
ast_type_params: Option<&ast::TypeParams>,
where_bounds: Option<&ast::WhereBounds>,
trait_bounds: Option<&Vec<ast::Type>>,
file_id: SourceFileId,
) -> Rc<TypeParamDefinition> {
let mut type_param_definition = TypeParamDefinition::new(parent);
Expand Down Expand Up @@ -1527,7 +1540,7 @@ fn parse_type_param_definition(
};

for bound in &type_param.bounds {
type_param_definition.add_bound(id, bound.clone());
type_param_definition.add_type_param_bound(id, bound.clone());
}
}
}
Expand All @@ -1540,6 +1553,12 @@ fn parse_type_param_definition(
}
}

if let Some(trait_bounds) = trait_bounds {
for bound in trait_bounds {
type_param_definition.add_self_bound(bound.clone());
}
}

Rc::new(type_param_definition)
}

Expand Down
11 changes: 10 additions & 1 deletion dora-frontend/src/sema/type_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl TypeParamDefinition {
TypeParamId(id)
}

pub fn add_bound(&mut self, id: TypeParamId, ast_trait_ty: ast::Type) {
pub fn add_type_param_bound(&mut self, id: TypeParamId, ast_trait_ty: ast::Type) {
let bound = Bound::new(
ParsedType::new_ty(SourceType::TypeParam(id)),
ParsedTraitType::new_ast(ast_trait_ty.clone()),
Expand All @@ -90,6 +90,15 @@ impl TypeParamDefinition {
self.bounds.push(bound);
}

pub fn add_self_bound(&mut self, ast_trait_ty: ast::Type) {
let bound = Bound::new(
ParsedType::new_ty(SourceType::This),
ParsedTraitType::new_ast(ast_trait_ty.clone()),
);

self.bounds.push(bound);
}

pub fn add_where_bound(&mut self, ast_ty: ast::Type, ast_trait_ty: ast::Type) {
let bound = Bound::new(
ParsedType::new_ast(ast_ty.clone()),
Expand Down
115 changes: 115 additions & 0 deletions dora-frontend/src/traitdefck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,119 @@ mod tests {
ErrorMessage::TraitNotObjectSafe,
);
}

#[test]
fn super_trait() {
ok("
trait Bar {}
trait Foo: Bar {}
");
}

#[test]
fn super_trait_unknown() {
err(
"
trait Foo: Unknown {}
",
(2, 24),
ErrorMessage::UnknownIdentifier("Unknown".into()),
);
}

#[test]
fn super_trait_call() {
ok("
trait Bar {
fn g();
}
trait Foo: Bar {
fn f() { self.g(); }
}
");
}

#[test]
fn super_trait_unsatisfied_in_impl() {
err(
"
trait A {}
trait B: A {}
impl B for Int64 {}
",
(4, 18),
ErrorMessage::TypeNotImplementingTrait("Int64".into(), "A".into()),
);

errors(
"
trait A {}
trait B: A {}
trait C: B {}
impl B for Int64 {}
impl C for Int64 {}
",
&[
(
(5, 18),
ErrorMessage::TypeNotImplementingTrait("Int64".into(), "A".into()),
),
(
(6, 18),
ErrorMessage::TypeNotImplementingTrait("Int64".into(), "B".into()),
),
],
);
}

#[test]
fn super_trait_in_impl() {
ok("
trait A {}
trait B: A {}
impl B for Int64 {}
impl A for Int64 {}
");
}

#[test]
fn super_trait_generic_call_in_super_trait() {
ok("
trait A { fn f(); }
trait B: A { fn g(); }
fn f[T: B](value: T) {
value.f();
}
");

ok("
trait A { fn f(); }
trait B: A { fn g(); }
trait C: B { fn h(); }
fn f[T: C](value: T) {
value.f();
}
");
}

#[test]
fn super_trait_call_in_default_implementation() {
ok("
trait A { fn f(); }
trait B: A { fn g(); }
trait C: B { fn h() { self.f(); } }
");
}

#[test]
fn super_trait_call_on_trait_object() {
ok("
trait A { fn f(); }
trait B: A { fn g(); }
trait C: B { fn h() { self.f(); } }
fn f(c: C) {
c.f();
}
");
}
}
Loading

0 comments on commit a7dfade

Please sign in to comment.