diff --git a/dora-frontend/src/sema/impl_matching.rs b/dora-frontend/src/sema/impl_matching.rs index 18194451b..2a92c1182 100644 --- a/dora-frontend/src/sema/impl_matching.rs +++ b/dora-frontend/src/sema/impl_matching.rs @@ -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!() diff --git a/dora-frontend/src/sema/matching.rs b/dora-frontend/src/sema/matching.rs index 7b7de3b06..5d13c156d 100644 --- a/dora-frontend/src/sema/matching.rs +++ b/dora-frontend/src/sema/matching.rs @@ -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, @@ -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; } } diff --git a/dora-frontend/src/sema/type_params.rs b/dora-frontend/src/sema/type_params.rs index 885ada64c..14b3745a7 100644 --- a/dora-frontend/src/sema/type_params.rs +++ b/dora-frontend/src/sema/type_params.rs @@ -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)] @@ -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 } diff --git a/dora-frontend/src/traitdefck.rs b/dora-frontend/src/traitdefck.rs index b8e8a33f4..c5a0272c6 100644 --- a/dora-frontend/src/traitdefck.rs +++ b/dora-frontend/src/traitdefck.rs @@ -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 + } + ") + } } diff --git a/dora-frontend/src/ty.rs b/dora-frontend/src/ty.rs index 99906e39e..28ef15838 100644 --- a/dora-frontend/src/ty.rs +++ b/dora-frontend/src/ty.rs @@ -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, diff --git a/dora-frontend/src/typeck/lookup.rs b/dora-frontend/src/typeck/lookup.rs index 7e897c063..0c0d09b56 100644 --- a/dora-frontend/src/typeck/lookup.rs +++ b/dora-frontend/src/typeck/lookup.rs @@ -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, + }); + } } } } diff --git a/dora-frontend/src/typeck/tests.rs b/dora-frontend/src/typeck/tests.rs index 494e94dad..cd34e5998 100644 --- a/dora-frontend/src/typeck/tests.rs +++ b/dora-frontend/src/typeck/tests.rs @@ -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()), + ), + ], + ); +} diff --git a/tests/trait/super-trait-operator-overloading1.dora b/tests/trait/super-trait-operator-overloading1.dora new file mode 100644 index 000000000..accd6fe72 --- /dev/null +++ b/tests/trait/super-trait-operator-overloading1.dora @@ -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)); +} diff --git a/tests/trait/super-trait-trait-object1.dora b/tests/trait/super-trait-regular-call.dora similarity index 72% rename from tests/trait/super-trait-trait-object1.dora rename to tests/trait/super-trait-regular-call.dora index 2dc7910d6..36352c172 100644 --- a/tests/trait/super-trait-trait-object1.dora +++ b/tests/trait/super-trait-regular-call.dora @@ -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() {