Skip to content

Commit

Permalink
frontend: Check super traits for operator overloading
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Oct 16, 2024
1 parent a7dfade commit 936a3f1
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 21 deletions.
2 changes: 1 addition & 1 deletion dora-frontend/src/sema/impl_matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn implements_trait(
find_impl(sa, check_ty, check_type_param_defs, trait_ty).is_some()
}

SourceType::TypeParam(tp_id) => check_type_param_defs.implements_trait(tp_id, trait_ty),
SourceType::TypeParam(tp_id) => check_type_param_defs.implements_trait(sa, tp_id, trait_ty),

SourceType::Alias(..) | SourceType::Assoc(..) | SourceType::GenericAssoc(..) => {
unreachable!()
Expand Down
4 changes: 2 additions & 2 deletions dora-frontend/src/sema/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn match_types(
}

fn match_type_params(
_sa: &Sema,
sa: &Sema,
check_ty: SourceType,
check_type_param_defs: &TypeParamDefinition,
ext_ty: SourceType,
Expand All @@ -154,7 +154,7 @@ fn match_type_params(
let check_tp_id = check_ty.type_param_id().expect("expected type param");

for trait_ty in ext_type_param_defs.bounds_for_type_param(ext_tp_id) {
if !check_type_param_defs.implements_trait(check_tp_id, trait_ty) {
if !check_type_param_defs.implements_trait(sa, check_tp_id, trait_ty) {
return false;
}
}
Expand Down
12 changes: 6 additions & 6 deletions dora-frontend/src/sema/type_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::rc::Rc;

use dora_parser::ast;

use crate::sema::Sema;
use crate::{Name, ParsedTraitType, ParsedType, SourceType, SourceTypeArray, TraitType};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -108,14 +109,13 @@ impl TypeParamDefinition {
self.bounds.push(bound);
}

pub fn implements_trait(&self, id: TypeParamId, trait_ty: TraitType) -> bool {
for bound in self.bounds() {
if let Some(bound_trait_ty) = bound.trait_ty() {
if bound.ty() == SourceType::TypeParam(id) && bound_trait_ty == trait_ty {
return true;
}
pub fn implements_trait(&self, sa: &Sema, id: TypeParamId, trait_ty: TraitType) -> bool {
for bound_trait_ty in self.bounds_for_type_param(id) {
if bound_trait_ty.implements_trait(sa, &trait_ty) {
return true;
}
}

false
}

Expand Down
25 changes: 25 additions & 0 deletions dora-frontend/src/traitdefck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,4 +449,29 @@ mod tests {
}
");
}

#[test]
fn check_super_trait_on_generic() {
ok("
trait A {}
trait B: A {}
class Data[T: B]
impl A for Int64 {}
impl B for Int64 {}
fn f() {
let _ = Data[Int64]();
}
")
}

#[test]
fn check_super_trait_operator_overloading() {
ok("
trait A: std::Equals {}
impl A for Int64 {}
fn f[T: A](lhs: T, rhs: T): Bool {
lhs == rhs
}
")
}
}
16 changes: 16 additions & 0 deletions dora-frontend/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,22 @@ impl TraitType {
SourceType::TraitObject(self.trait_id, self.type_params.clone(), ().into())
}

pub fn implements_trait(&self, sa: &Sema, check_trait_ty: &TraitType) -> bool {
if check_trait_ty == self {
return true;
}

let trait_ = sa.trait_(self.trait_id);

for super_trait_ty in trait_.type_param_definition().bounds_for_self() {
if super_trait_ty.implements_trait(sa, check_trait_ty) {
return true;
}
}

false
}

pub fn name_with_type_params(
&self,
sa: &Sema,
Expand Down
14 changes: 7 additions & 7 deletions dora-frontend/src/typeck/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,13 @@ pub fn find_method_call_candidates(
let trait_ = &sa.trait_(trait_ty.trait_id);

if let Some(trait_method_id) = trait_.get_method(name, is_static) {
candidates.push(Candidate {
object_type: object_type.clone(),
container_type_params: bindings.clone(),
fct_id: impl_
.get_method_for_trait_method_id(trait_method_id)
.expect("missing fct"),
});
if let Some(fct_id) = impl_.get_method_for_trait_method_id(trait_method_id) {
candidates.push(Candidate {
object_type: object_type.clone(),
container_type_params: bindings.clone(),
fct_id,
});
}
}
}
}
Expand Down
37 changes: 37 additions & 0 deletions dora-frontend/src/typeck/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4634,3 +4634,40 @@ fn type_param_failure_in_container() {
ErrorMessage::UnknownIdentifier("Unknown".into()),
);
}

#[test]
fn impl_method_lookup_on_missing_trait_method() {
errors(
"
trait A { fn f(): Int64; }
trait B: A { fn g(): Int64; }
trait C: B { fn h(): Int64; }
impl A for Int64 {
fn f(): Int64 { 100 }
}
impl B for Int64 {
fn g(): Int64 { 200 }
}
impl C for Int64 {
fn g(): Int64 { 300 }
}
fn f(x: Int64) {
x.f();
x.g();
x.h();
}
",
&[
((15, 13), ErrorMessage::ElementNotInTrait),
((14, 9), ErrorMessage::ElementNotInImpl("h".into())),
(
(21, 13),
ErrorMessage::UnknownMethod("Int64".into(), "h".into(), Vec::new()),
),
],
);
}
11 changes: 11 additions & 0 deletions tests/trait/super-trait-operator-overloading1.dora
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
trait A: std::Equals {}

impl A for Int64 {}

fn f[T: A](lhs: T, rhs: T): Bool {
lhs == rhs
}

fn main() {
assert(f[Int64](2, 2));
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
//= ignore

trait A { fn f(): Int64; }
trait B: A { fn g(): Int64; }
trait C: B { fn h(): Int64; }

impl A for Int64 {
fn f() { 100 }
fn f(): Int64 { 100 }
}

impl B for Int64 {
fn g() { 200 }
fn g(): Int64 { self.f() + 100 }
}

impl C for Int64 {
fn g() { 300 }
fn h(): Int64 { self.g() + 100 }
}

fn main() {
Expand Down

0 comments on commit 936a3f1

Please sign in to comment.