diff options
-rw-r--r-- | gcc/rust/typecheck/rust-hir-path-probe.h | 11 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.cc | 2 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.cc | 50 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 6 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/trait6.rs | 41 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/trait7.rs | 41 |
6 files changed, 145 insertions, 6 deletions
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index dd51f83..d2b5f5b 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -276,7 +276,16 @@ protected: TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty (); - if (impl != nullptr) + // we cannot auto setup associated type mappings when our receiver is a + // generic type bound + const TyTy::BaseType *root = receiver->get_root (); + bool receiver_is_type_param + = root->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC; + bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn; + + if (impl != nullptr && !receiver_is_generic) + { HirId impl_block_id = impl->get_mappings ().get_hirid (); AssociatedImplTrait *lookup_associated = nullptr; diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index a479581..ed21d53 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -445,7 +445,7 @@ TypeCheckType::resolve_segments ( // lookup the associated-impl-trait HIR::ImplBlock *impl = candidate.item.trait.impl; - if (impl != nullptr) + if (impl != nullptr && !reciever_is_generic) { AssociatedImplTrait *lookup_associated = nullptr; bool found_impl_trait = context->lookup_associated_trait_impl ( diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index f2216f9..1e7c87e 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -331,9 +331,11 @@ StructFieldType::clone () const get_field_type ()->clone ()); } -void +bool SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus) { + auto context = Resolver::TypeCheckContext::get (); + if (type.get_kind () == TyTy::TypeKind::INFER) { type.inherit_bounds (*param); @@ -341,7 +343,7 @@ SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus) else { if (!param->bounds_compatible (type, locus, true)) - return; + return false; } if (type.get_kind () == TypeKind::PARAM) @@ -351,8 +353,52 @@ SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus) } else { + // check the substitution is compatible with bounds + if (!param->bounds_compatible (type, locus, true)) + return false; + + // setup any associated type mappings for the specified bonds and this + // type + auto candidates = Resolver::TypeBoundsProbe::Probe (&type); + for (auto &specified_bound : param->get_specified_bounds ()) + { + const Resolver::TraitReference *specified_bound_ref + = specified_bound.get (); + + // since the bounds_compatible check has occurred we should be able to + // assert on finding the trait references + HirId associated_impl_block_id = UNKNOWN_HIRID; + bool found = false; + for (auto &bound : candidates) + { + const Resolver::TraitReference *bound_trait_ref = bound.first; + const HIR::ImplBlock *associated_impl = bound.second; + + found = specified_bound_ref->is_equal (*bound_trait_ref); + if (found) + { + rust_assert (associated_impl != nullptr); + associated_impl_block_id + = associated_impl->get_mappings ().get_hirid (); + break; + } + } + + if (found && associated_impl_block_id != UNKNOWN_HIRID) + { + Resolver::AssociatedImplTrait *lookup_associated = nullptr; + bool found_impl_trait = context->lookup_associated_trait_impl ( + associated_impl_block_id, &lookup_associated); + + if (found_impl_trait) + lookup_associated->setup_associated_types (); + } + } + param->set_ty_ref (type.get_ref ()); } + + return true; } void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 054e327..f6a2797 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -626,7 +626,7 @@ public: std::string as_string () const { return param->as_string (); } - void fill_param_ty (BaseType &type, Location locus); + bool fill_param_ty (BaseType &type, Location locus); SubstitutionParamMapping clone () const { @@ -1812,7 +1812,9 @@ public: bool contains_type_parameters () const override { - rust_assert (can_resolve ()); + if (!can_resolve ()) + return false; + return resolve ()->contains_type_parameters (); } diff --git a/gcc/testsuite/rust/execute/torture/trait6.rs b/gcc/testsuite/rust/execute/torture/trait6.rs new file mode 100644 index 0000000..54023d2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait6.rs @@ -0,0 +1,41 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +pub trait Foo { + type A; + + fn bar(self) -> Self::A; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +struct S(i32); +impl Foo for S { + type A = i32; + + fn bar(self) -> Self::A { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + self.0 + } +} + +fn test_bar<T: Foo>(x: T) -> T::A { + x.bar() +} + +fn main() -> i32 { + let a; + a = S(123); + + let bar: i32 = test_bar::<S>(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait7.rs b/gcc/testsuite/rust/execute/torture/trait7.rs new file mode 100644 index 0000000..059ba15 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait7.rs @@ -0,0 +1,41 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +pub trait Foo { + type A; + + fn bar(self) -> Self::A; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +struct S(i32); +impl Foo for S { + type A = i32; + + fn bar(self) -> Self::A { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + self.0 + } +} + +fn test_bar<T: Foo>(x: T) -> T::A { + x.bar() +} + +fn main() -> i32 { + let a; + a = S(123); + + let bar: i32 = test_bar(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} |