From c434e5fffc00ea1681e23f4e0cbc1dc2e28e8a6d Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 6 Aug 2021 19:30:52 +0100 Subject: Add check for TypeBounds on argument substitutions TypeParameters contain specified bounds, when we substitute them we need to ensure that the argument satisfies those bounds otherwise... it fails the contract. This change only checks this specific case as a nice isolated PR to demonstrate the mechanism's we require. Specified bounds are checked but we must also probe for what bounds are available for the type. Addreses #440 --- gcc/rust/typecheck/rust-tyty.cc | 34 +++++++++++++++++++-- gcc/rust/typecheck/rust-tyty.h | 57 ++++++++++++++++++++++++++++++++++- gcc/testsuite/rust/compile/traits6.rs | 15 +++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/rust/compile/traits6.rs (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index a2ae4fa..3238631 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -27,6 +27,8 @@ #include "rust-tyty-cast.h" #include "rust-hir-map.h" #include "rust-substitution-mapper.h" +#include "rust-hir-trait-ref.h" +#include "rust-hir-type-bounds.h" extern ::Backend * rust_get_backend (); @@ -34,6 +36,32 @@ rust_get_backend (); namespace Rust { namespace TyTy { +bool +BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const +{ + const Resolver::TraitReference *query = predicate.get (); + for (auto &bound : specified_bounds) + { + const Resolver::TraitReference *item = bound.get (); + bool found = item->get_mappings ().get_defid () + == query->get_mappings ().get_defid (); + if (found) + return true; + } + + std::vector> probed + = Resolver::TypeBoundsProbe::Probe (this); + for (const Resolver::TraitReference &bound : probed) + { + bool found = bound.get_mappings ().get_defid () + == query->get_mappings ().get_defid (); + if (found) + return true; + } + + return false; +} + TyVar::TyVar (HirId ref) : ref (ref) { // ensure this reference is defined within the context @@ -556,7 +584,7 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok) - sub.fill_param_ty (arg.get_tyty ()); + sub.fill_param_ty (arg.get_tyty (), subst_mappings.get_locus ()); } adt->iterate_fields ([&] (StructFieldType *field) mutable -> bool { @@ -811,7 +839,7 @@ FnType::is_equal (const BaseType &other) const BaseType * FnType::clone () const { - std::vector > cloned_params; + std::vector> cloned_params; for (auto &p : params) cloned_params.push_back ( std::pair (p.first, p.second->clone ())); @@ -836,7 +864,7 @@ FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok) - sub.fill_param_ty (arg.get_tyty ()); + sub.fill_param_ty (arg.get_tyty (), subst_mappings.get_locus ()); } auto fty = fn->get_return_type (); diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 13bab90..6fe67c7 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -172,7 +172,21 @@ public: return specified_bounds; } + std::string bounds_as_string () const + { + std::string buf; + for (auto &b : specified_bounds) + buf += b.as_string () + ", "; + + return "bounds:[" + buf + "]"; + } + protected: + void add_bound (TypeBoundPredicate predicate) + { + specified_bounds.push_back (predicate); + } + std::vector specified_bounds; }; @@ -237,6 +251,37 @@ public: return get_kind () == other.get_kind (); } + bool satisfies_bound (const TypeBoundPredicate &predicate) const; + + bool bounds_compatible (const BaseType &other, Location locus) const + { + std::vector> + unsatisfied_bounds; + for (auto &bound : get_specified_bounds ()) + { + if (!other.satisfies_bound (bound)) + unsatisfied_bounds.push_back (bound); + } + + if (unsatisfied_bounds.size () > 0) + { + RichLocation r (locus); + rust_error_at (r, "bounds not satisfied for %s", + other.as_string ().c_str ()); + return false; + } + + return unsatisfied_bounds.size () == 0; + } + + void inherit_bounds (const BaseType &other) + { + for (auto &bound : other.get_specified_bounds ()) + { + add_bound (bound); + } + } + virtual bool is_unit () const { return false; } virtual bool is_concrete () const { return true; } @@ -575,8 +620,18 @@ public: std::string as_string () const { return param->as_string (); } - void fill_param_ty (BaseType *type) + void fill_param_ty (BaseType *type, Location locus) { + if (type->get_kind () == TyTy::TypeKind::INFER) + { + type->inherit_bounds (*param); + } + else + { + if (!param->bounds_compatible (*type, locus)) + return; + } + if (type->get_kind () == TypeKind::PARAM) { delete param; diff --git a/gcc/testsuite/rust/compile/traits6.rs b/gcc/testsuite/rust/compile/traits6.rs new file mode 100644 index 0000000..3579b5a --- /dev/null +++ b/gcc/testsuite/rust/compile/traits6.rs @@ -0,0 +1,15 @@ +trait Foo { + fn default() -> i32; +} + +struct Bar(i32); + +fn type_bound_test() -> i32 { + T::default() +} + +fn main() { + let a; + a = type_bound_test::(); + // { dg-error "bounds not satisfied for Bar" "" { target *-*-* } .-1 } +} -- cgit v1.1 From 43c1ab08f070994a934d90ff4e6457eaee12c493 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 8 Aug 2021 19:48:55 +0100 Subject: add missing copy constructors and equality interfaces --- gcc/rust/util/rust-hir-map.cc | 7 ------- gcc/rust/util/rust-hir-map.h | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 4ffbff0..0f8f902 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -23,13 +23,6 @@ namespace Rust { namespace Analysis { -NodeMapping::NodeMapping (CrateNum crateNum, NodeId nodeId, HirId hirId, - LocalDefId localDefId) - : crateNum (crateNum), nodeId (nodeId), hirId (hirId), localDefId (localDefId) -{} - -NodeMapping::~NodeMapping () {} - NodeMapping NodeMapping::get_error () { diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index ccc873b..f689abf 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -53,8 +53,10 @@ class NodeMapping { public: NodeMapping (CrateNum crateNum, NodeId nodeId, HirId hirId, - LocalDefId localDefId); - ~NodeMapping (); + LocalDefId localDefId) + : crateNum (crateNum), nodeId (nodeId), hirId (hirId), + localDefId (localDefId) + {} static NodeMapping get_error (); @@ -68,6 +70,14 @@ public: std::string as_string () const; + bool is_equal (const NodeMapping &other) const + { + return get_crate_num () == other.get_crate_num () + && get_nodeid () == other.get_nodeid () + && get_hirid () == other.get_hirid () + && get_local_defid () == other.get_local_defid (); + } + private: CrateNum crateNum; NodeId nodeId; -- cgit v1.1 From 49a498f28be6cf5ced4a2a88aef86a5a75092334 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 8 Aug 2021 20:00:43 +0100 Subject: refactor error_node to be part of the type not the resolver --- gcc/rust/backend/rust-compile-resolve-path.cc | 2 +- gcc/rust/backend/rust-compile.cc | 2 +- gcc/rust/typecheck/rust-hir-trait-ref.h | 6 ++++++ gcc/rust/typecheck/rust-hir-trait-resolve.h | 14 ++++---------- gcc/rust/typecheck/rust-hir-type-check-item.h | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index c87b477..52bdbb0 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -108,7 +108,7 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) trait_item->get_mappings ().get_hirid ()); Resolver::TraitReference &trait_ref - = Resolver::TraitResolver::error_node (); + = Resolver::TraitReference::error_node (); bool ok = ctx->get_tyctx ()->lookup_trait_reference ( trait->get_mappings ().get_defid (), trait_ref); rust_assert (ok); diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index f422572..c93f08c 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -151,7 +151,7 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) trait_item->get_mappings ().get_hirid ()); Resolver::TraitReference &trait_ref - = Resolver::TraitResolver::error_node (); + = Resolver::TraitReference::error_node (); bool ok = ctx->get_tyctx ()->lookup_trait_reference ( trait->get_mappings ().get_defid (), trait_ref); rust_assert (ok); diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index b19c38a..dd77dfd 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -199,6 +199,12 @@ public: bool is_error () const { return hir_trait_ref == nullptr; } + static TraitReference &error_node () + { + static TraitReference trait_error_node = TraitReference::error (); + return trait_error_node; + } + Location get_locus () const { return hir_trait_ref->get_locus (); } std::string get_name () const diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 6d7c864..1e69caa 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -106,12 +106,6 @@ public: return resolver.go (path); } - static TraitReference &error_node () - { - static TraitReference trait_error_node = TraitReference::error (); - return trait_error_node; - } - private: TraitResolver () : TypeCheckBase () {} @@ -122,7 +116,7 @@ private: &ref)) { rust_error_at (path.get_locus (), "Failed to resolve path to node-id"); - return error_node (); + return TraitReference::error_node (); } HirId hir_node = UNKNOWN_HIRID; @@ -130,7 +124,7 @@ private: &hir_node)) { rust_error_at (path.get_locus (), "Failed to resolve path to hir-id"); - return error_node (); + return TraitReference::error_node (); } HIR::Item *resolved_item @@ -140,7 +134,7 @@ private: resolved_item->accept_vis (*this); rust_assert (trait_reference != nullptr); - TraitReference &tref = error_node (); + TraitReference &tref = TraitReference::error_node (); if (context->lookup_trait_reference ( trait_reference->get_mappings ().get_defid (), tref)) { @@ -189,7 +183,7 @@ private: context->insert_trait_reference ( trait_reference->get_mappings ().get_defid (), std::move (tref)); - tref = error_node (); + tref = TraitReference::error_node (); bool ok = context->lookup_trait_reference ( trait_reference->get_mappings ().get_defid (), tref); rust_assert (ok); diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 8d770f0..493e91a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -43,7 +43,7 @@ public: void visit (HIR::ImplBlock &impl_block) override { - TraitReference &trait_reference = TraitResolver::error_node (); + TraitReference &trait_reference = TraitReference::error_node (); if (impl_block.has_trait_ref ()) { std::unique_ptr &ref = impl_block.get_trait_ref (); -- cgit v1.1 From 3f544652b42f9c9330e87ceb6df517d675aa5300 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 8 Aug 2021 21:10:35 +0100 Subject: Fix memory issues with multiple type-bounds --- gcc/rust/backend/rust-compile-resolve-path.cc | 6 ++-- gcc/rust/backend/rust-compile.cc | 6 ++-- gcc/rust/typecheck/rust-hir-path-probe.h | 50 +++++++++++++-------------- gcc/rust/typecheck/rust-hir-trait-ref.h | 10 ++++-- gcc/rust/typecheck/rust-hir-trait-resolve.h | 20 +++++------ gcc/rust/typecheck/rust-hir-type-bounds.h | 5 ++- gcc/rust/typecheck/rust-hir-type-check-base.h | 2 +- gcc/rust/typecheck/rust-hir-type-check-expr.h | 4 +-- gcc/rust/typecheck/rust-hir-type-check-item.h | 14 ++++---- gcc/rust/typecheck/rust-hir-type-check-type.h | 5 ++- gcc/rust/typecheck/rust-hir-type-check.h | 4 +-- gcc/rust/typecheck/rust-tyty-bounds.cc | 20 ++++++++--- gcc/rust/typecheck/rust-tyty.cc | 6 ++-- gcc/rust/typecheck/rust-tyty.h | 18 ++-------- gcc/testsuite/rust/compile/traits7.rs | 24 +++++++++++++ 15 files changed, 112 insertions(+), 82 deletions(-) create mode 100644 gcc/testsuite/rust/compile/traits7.rs (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 52bdbb0..5f07a2a 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -107,10 +107,10 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) = ctx->get_mappings ()->lookup_trait_item_mapping ( trait_item->get_mappings ().get_hirid ()); - Resolver::TraitReference &trait_ref - = Resolver::TraitReference::error_node (); + Resolver::TraitReference *trait_ref + = &Resolver::TraitReference::error_node (); bool ok = ctx->get_tyctx ()->lookup_trait_reference ( - trait->get_mappings ().get_defid (), trait_ref); + trait->get_mappings ().get_defid (), &trait_ref); rust_assert (ok); TyTy::BaseType *receiver = nullptr; diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index c93f08c..3c6a188 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -150,10 +150,10 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping ( trait_item->get_mappings ().get_hirid ()); - Resolver::TraitReference &trait_ref - = Resolver::TraitReference::error_node (); + Resolver::TraitReference *trait_ref + = &Resolver::TraitReference::error_node (); bool ok = ctx->get_tyctx ()->lookup_trait_reference ( - trait->get_mappings ().get_defid (), trait_ref); + trait->get_mappings ().get_defid (), &trait_ref); rust_assert (ok); TyTy::BaseType *receiver = nullptr; diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 8e3ca31..87c9662 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -49,8 +49,8 @@ struct PathProbeCandidate struct TraitItemCandidate { - const TraitReference &trait_ref; - const TraitItemReference &item_ref; + const TraitReference *trait_ref; + const TraitItemReference *item_ref; }; CandidateType type; @@ -128,18 +128,18 @@ public: if (!probe_bounds) return probe.candidates; - std::vector> probed_bounds + std::vector probed_bounds = TypeBoundsProbe::Probe (receiver); - std::vector> specified_bounds; + std::vector specified_bounds; for (const TyTy::TypeBoundPredicate &predicate : receiver->get_specified_bounds ()) { const TraitReference *trait_item = predicate.get (); - specified_bounds.push_back (*trait_item); + specified_bounds.push_back (trait_item); } - std::vector> union_type_bounds + std::vector union_type_bounds = probe.union_bounds (probed_bounds, specified_bounds); probe.process_traits_for_candidates (union_type_bounds, ignore_mandatory_trait_items); @@ -230,22 +230,22 @@ private: } void process_traits_for_candidates ( - const std::vector> traits, + const std::vector traits, bool ignore_mandatory_trait_items) { - for (const TraitReference &trait_ref : traits) + for (const TraitReference *trait_ref : traits) { - const TraitItemReference &trait_item_ref - = trait_ref.lookup_trait_item (search.as_string ()); - if (trait_item_ref.is_error ()) + const TraitItemReference *trait_item_ref = nullptr; + if (!trait_ref->lookup_trait_item (search.as_string (), + &trait_item_ref)) continue; - bool trait_item_needs_implementation = !trait_item_ref.is_optional (); + bool trait_item_needs_implementation = !trait_item_ref->is_optional (); if (ignore_mandatory_trait_items && trait_item_needs_implementation) continue; PathProbeCandidate::CandidateType candidate_type; - switch (trait_item_ref.get_trait_item_type ()) + switch (trait_item_ref->get_trait_item_type ()) { case TraitItemReference::TraitItemType::FN: candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; @@ -264,7 +264,7 @@ private: break; } - TyTy::BaseType *trait_item_tyty = trait_item_ref.get_tyty (); + TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty (); // we can substitute the Self with the receiver here if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) @@ -298,7 +298,7 @@ private: trait_ref, trait_item_ref}; PathProbeCandidate candidate{candidate_type, trait_item_tyty, - trait_ref.get_locus (), + trait_ref->get_locus (), {trait_item_candidate}}; candidates.push_back (std::move (candidate)); } @@ -311,21 +311,21 @@ private: current_impl (nullptr) {} - std::vector> union_bounds ( - const std::vector> a, - const std::vector> b) const + std::vector + union_bounds (const std::vector a, + const std::vector b) const { - std::map> mapper; - for (const TraitReference &ref : a) + std::map mapper; + for (const TraitReference *ref : a) { - mapper.insert ({ref.get_mappings ().get_defid (), ref}); + mapper.insert ({ref->get_mappings ().get_defid (), ref}); } - for (const TraitReference &ref : b) + for (const TraitReference *ref : b) { - mapper.insert ({ref.get_mappings ().get_defid (), ref}); + mapper.insert ({ref->get_mappings ().get_defid (), ref}); } - std::vector> union_set; + std::vector union_set; for (auto it = mapper.begin (); it != mapper.end (); it++) { union_set.push_back (it->second); @@ -362,7 +362,7 @@ public: case PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST: case PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS: case PathProbeCandidate::CandidateType::TRAIT_FUNC: - r.add_range (c.item.trait.item_ref.get_locus ()); + r.add_range (c.item.trait.item_ref->get_locus ()); break; } } diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index dd77dfd..21a8beb 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -233,14 +233,18 @@ public: return hir_trait_ref->get_mappings (); } - const TraitItemReference &lookup_trait_item (const std::string &ident) const + bool lookup_trait_item (const std::string &ident, + const TraitItemReference **ref) const { for (auto &item : item_refs) { if (ident.compare (item.get_identifier ()) == 0) - return item; + { + *ref = &item; + return true; + } } - return TraitItemReference::error_node (); + return false; } const TraitItemReference & diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 1e69caa..1669a37 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -100,7 +100,7 @@ class TraitResolver : public TypeCheckBase using Rust::Resolver::TypeCheckBase::visit; public: - static TraitReference &Resolve (HIR::TypePath &path) + static TraitReference *Resolve (HIR::TypePath &path) { TraitResolver resolver; return resolver.go (path); @@ -109,14 +109,14 @@ public: private: TraitResolver () : TypeCheckBase () {} - TraitReference &go (HIR::TypePath &path) + TraitReference *go (HIR::TypePath &path) { NodeId ref; if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (), &ref)) { rust_error_at (path.get_locus (), "Failed to resolve path to node-id"); - return TraitReference::error_node (); + return &TraitReference::error_node (); } HirId hir_node = UNKNOWN_HIRID; @@ -124,7 +124,7 @@ private: &hir_node)) { rust_error_at (path.get_locus (), "Failed to resolve path to hir-id"); - return TraitReference::error_node (); + return &TraitReference::error_node (); } HIR::Item *resolved_item @@ -134,9 +134,9 @@ private: resolved_item->accept_vis (*this); rust_assert (trait_reference != nullptr); - TraitReference &tref = TraitReference::error_node (); + TraitReference *tref = &TraitReference::error_node (); if (context->lookup_trait_reference ( - trait_reference->get_mappings ().get_defid (), tref)) + trait_reference->get_mappings ().get_defid (), &tref)) { return tref; } @@ -179,13 +179,13 @@ private: item_refs.push_back (std::move (trait_item_ref)); } - tref = TraitReference (trait_reference, item_refs); + TraitReference trait_object (trait_reference, item_refs); context->insert_trait_reference ( - trait_reference->get_mappings ().get_defid (), std::move (tref)); + trait_reference->get_mappings ().get_defid (), std::move (trait_object)); - tref = TraitReference::error_node (); + tref = &TraitReference::error_node (); bool ok = context->lookup_trait_reference ( - trait_reference->get_mappings ().get_defid (), tref); + trait_reference->get_mappings ().get_defid (), &tref); rust_assert (ok); return tref; diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index d97c0f5..ce694da 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -31,8 +31,7 @@ class TypeBoundsProbe : public TypeCheckBase using Rust::Resolver::TypeCheckBase::visit; public: - static std::vector> - Probe (const TyTy::BaseType *receiver) + static std::vector Probe (const TyTy::BaseType *receiver) { TypeBoundsProbe probe (receiver); probe.scan (); @@ -48,7 +47,7 @@ private: {} const TyTy::BaseType *receiver; - std::vector> trait_references; + std::vector trait_references; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index f05ab86..3dd0a19 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -202,7 +202,7 @@ protected: context (TypeCheckContext::get ()) {} - TraitReference &resolve_trait_path (HIR::TypePath &); + TraitReference *resolve_trait_path (HIR::TypePath &); Analysis::Mappings *mappings; Resolver *resolver; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 7f1a83d..6743c8b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -244,7 +244,7 @@ public: = resolved_candidate.is_impl_candidate () ? resolved_candidate.item.impl.impl_item->get_impl_mappings () .get_nodeid () - : resolved_candidate.item.trait.item_ref.get_mappings () + : resolved_candidate.item.trait.item_ref->get_mappings () .get_nodeid (); if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF) @@ -994,7 +994,7 @@ public: else { resolved_node_id - = candidate.item.trait.item_ref.get_mappings ().get_nodeid (); + = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); } if (seg.has_generic_args ()) diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 493e91a..8775502 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -43,12 +43,12 @@ public: void visit (HIR::ImplBlock &impl_block) override { - TraitReference &trait_reference = TraitReference::error_node (); + TraitReference *trait_reference = &TraitReference::error_node (); if (impl_block.has_trait_ref ()) { std::unique_ptr &ref = impl_block.get_trait_ref (); trait_reference = TraitResolver::Resolve (*ref.get ()); - rust_assert (!trait_reference.is_error ()); + rust_assert (!trait_reference->is_error ()); } TyTy::BaseType *self = nullptr; @@ -60,7 +60,7 @@ public: return; } - bool is_trait_impl_block = !trait_reference.is_error (); + bool is_trait_impl_block = !trait_reference->is_error (); std::vector> trait_item_refs; @@ -72,20 +72,20 @@ public: { auto &trait_item_ref = TypeCheckImplItemWithTrait::Resolve (impl_item.get (), self, - trait_reference); + *trait_reference); trait_item_refs.push_back (trait_item_ref); } } bool impl_block_missing_trait_items = is_trait_impl_block - && trait_reference.size () != trait_item_refs.size (); + && trait_reference->size () != trait_item_refs.size (); if (impl_block_missing_trait_items) { // filter the missing impl_items std::vector> missing_trait_items; - for (auto &trait_item_ref : trait_reference.get_trait_items ()) + for (auto &trait_item_ref : trait_reference->get_trait_items ()) { bool found = false; for (const TraitItemReference &implemented_trait_item : @@ -120,7 +120,7 @@ public: rust_error_at (r, "missing %s in implementation of trait %<%s%>", missing_items_buf.c_str (), - trait_reference.get_name ().c_str ()); + trait_reference->get_name ().c_str ()); } } } diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 91d9c53..ef1510e 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -280,8 +280,11 @@ public: case HIR::TypeParamBound::BoundType::TRAITBOUND: { HIR::TraitBound *b = static_cast (bound.get ()); + + TraitReference *trait = resolve_trait_path (b->get_path ()); TyTy::TypeBoundPredicate predicate ( - &resolve_trait_path (b->get_path ())); + trait->get_mappings ().get_defid ()); + specified_bounds.push_back (std::move (predicate)); } break; diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index b171123..d834ad8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -92,13 +92,13 @@ public: trait_context.emplace (id, std::move (ref)); } - bool lookup_trait_reference (DefId id, TraitReference &ref) + bool lookup_trait_reference (DefId id, TraitReference **ref) { auto it = trait_context.find (id); if (it == trait_context.end ()) return false; - ref = it->second; + *ref = &it->second; return true; } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index a480155..3562e85 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -48,14 +48,14 @@ TypeBoundsProbe::scan () for (auto &trait_path : possible_trait_paths) { - TraitReference &trait_ref = TraitResolver::Resolve (*trait_path); + TraitReference *trait_ref = TraitResolver::Resolve (*trait_path); - if (!trait_ref.is_error ()) + if (!trait_ref->is_error ()) trait_references.push_back (trait_ref); } } -TraitReference & +TraitReference * TypeCheckBase::resolve_trait_path (HIR::TypePath &path) { return TraitResolver::Resolve (path); @@ -68,7 +68,19 @@ namespace TyTy { std::string TypeBoundPredicate::as_string () const { - return reference->as_string (); + return get ()->as_string (); +} + +const Resolver::TraitReference * +TypeBoundPredicate::get () const +{ + auto context = Resolver::TypeCheckContext::get (); + + Resolver::TraitReference *ref = nullptr; + bool ok = context->lookup_trait_reference (reference, &ref); + rust_assert (ok); + + return ref; } } // namespace TyTy diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 3238631..88b6c35 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -49,11 +49,11 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const return true; } - std::vector> probed + std::vector probed = Resolver::TypeBoundsProbe::Probe (this); - for (const Resolver::TraitReference &bound : probed) + for (const Resolver::TraitReference *bound : probed) { - bool found = bound.get_mappings ().get_defid () + bool found = bound->get_mappings ().get_defid () == query->get_mappings ().get_defid (); if (found) return true; diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 6fe67c7..f6f9579 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -132,26 +132,14 @@ public: class TypeBoundPredicate { public: - TypeBoundPredicate (Resolver::TraitReference *reference) - : reference (reference) - {} - - TypeBoundPredicate (const TypeBoundPredicate &other) - : reference (other.reference) - {} - - TypeBoundPredicate &operator= (const TypeBoundPredicate &other) - { - reference = other.reference; - return *this; - } + TypeBoundPredicate (DefId reference) : reference (reference) {} std::string as_string () const; - const Resolver::TraitReference *get () const { return reference; } + const Resolver::TraitReference *get () const; private: - Resolver::TraitReference *reference; + DefId reference; }; class TypeBoundsMappings diff --git a/gcc/testsuite/rust/compile/traits7.rs b/gcc/testsuite/rust/compile/traits7.rs new file mode 100644 index 0000000..825553c --- /dev/null +++ b/gcc/testsuite/rust/compile/traits7.rs @@ -0,0 +1,24 @@ +trait Foo { + fn default() -> i32; +} + +trait Bar { + fn not_default() -> i32; +} + +struct Test(i32); + +impl Foo for Test { + fn default() -> i32 { + 1234 + } +} + +fn type_bound_test() -> i32 { + T::default() +} + +fn main() { + let a = type_bound_test::(); + // { dg-error "bounds not satisfied for Test" "" { target *-*-* } .-1 } +} -- cgit v1.1 From 72483b1ca912dca78543f5cc2a7e9d1380ef5784 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 8 Aug 2021 22:29:55 +0100 Subject: Improve the error message for bad type bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We emit one error for all unsatisfied bounds such as: test.rs:26:31: error: bounds not satisfied for Test ‘Bar, Baz’ is not satisfied 21 | fn type_bound_test() -> i32 { | ~ ~ ...... 26 | let a = type_bound_test::(); | ^ --- gcc/rust/typecheck/rust-hir-type-check-type.h | 2 +- gcc/rust/typecheck/rust-tyty-bounds.cc | 6 ++++ gcc/rust/typecheck/rust-tyty.cc | 43 +++++++++++++++++++++++++++ gcc/rust/typecheck/rust-tyty.h | 38 +++++++---------------- 4 files changed, 60 insertions(+), 29 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index ef1510e..fff86be 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -283,7 +283,7 @@ public: TraitReference *trait = resolve_trait_path (b->get_path ()); TyTy::TypeBoundPredicate predicate ( - trait->get_mappings ().get_defid ()); + trait->get_mappings ().get_defid (), b->get_locus ()); specified_bounds.push_back (std::move (predicate)); } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 3562e85..008dc19 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -83,5 +83,11 @@ TypeBoundPredicate::get () const return ref; } +std::string +TypeBoundPredicate::get_name () const +{ + return get ()->get_name (); +} + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 88b6c35..2d165c3 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -62,6 +62,49 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const return false; } +bool +BaseType::bounds_compatible (const BaseType &other, Location locus) const +{ + std::vector> + unsatisfied_bounds; + for (auto &bound : get_specified_bounds ()) + { + if (!other.satisfies_bound (bound)) + unsatisfied_bounds.push_back (bound); + } + + // lets emit a single error for this + if (unsatisfied_bounds.size () > 0) + { + RichLocation r (locus); + std::string missing_preds; + for (size_t i = 0; i < unsatisfied_bounds.size (); i++) + { + const TypeBoundPredicate &pred = unsatisfied_bounds.at (i); + r.add_range (pred.get_locus ()); + missing_preds += pred.get_name (); + + bool have_next = (i + 1) < unsatisfied_bounds.size (); + if (have_next) + missing_preds += ", "; + } + + rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied", + other.get_name ().c_str (), missing_preds.c_str ()); + } + + return unsatisfied_bounds.size () == 0; +} + +void +BaseType::inherit_bounds (const BaseType &other) +{ + for (auto &bound : other.get_specified_bounds ()) + { + add_bound (bound); + } +} + TyVar::TyVar (HirId ref) : ref (ref) { // ensure this reference is defined within the context diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index f6f9579..c1afa14 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -132,14 +132,21 @@ public: class TypeBoundPredicate { public: - TypeBoundPredicate (DefId reference) : reference (reference) {} + TypeBoundPredicate (DefId reference, Location locus) + : reference (reference), locus (locus) + {} std::string as_string () const; const Resolver::TraitReference *get () const; + Location get_locus () const { return locus; } + + std::string get_name () const; + private: DefId reference; + Location locus; }; class TypeBoundsMappings @@ -241,34 +248,9 @@ public: bool satisfies_bound (const TypeBoundPredicate &predicate) const; - bool bounds_compatible (const BaseType &other, Location locus) const - { - std::vector> - unsatisfied_bounds; - for (auto &bound : get_specified_bounds ()) - { - if (!other.satisfies_bound (bound)) - unsatisfied_bounds.push_back (bound); - } - - if (unsatisfied_bounds.size () > 0) - { - RichLocation r (locus); - rust_error_at (r, "bounds not satisfied for %s", - other.as_string ().c_str ()); - return false; - } - - return unsatisfied_bounds.size () == 0; - } + bool bounds_compatible (const BaseType &other, Location locus) const; - void inherit_bounds (const BaseType &other) - { - for (auto &bound : other.get_specified_bounds ()) - { - add_bound (bound); - } - } + void inherit_bounds (const BaseType &other); virtual bool is_unit () const { return false; } -- cgit v1.1