From: Philip Herron <[email protected]>
This patch adds in GATs using proper projection types instead of mutating
associated type placeholders during resolution which rapidly becomes very
messy.
The simple case is trait impl handling, entering a trait impl block we first
walk the associated type items and build an ImplTraitFrame for that impl.
This frame records the trait, the impl self type and the mapping from trait
associated items to the impl associated type values. While typechecking
items in that impl we can then look through the active impl trait context
to resolve projections such as `<Self as Trait>::Item`.
The more complex cases need lazy evaluation. A projection can appear
outside the impl body, inside a where-clause binding, behind another
projection, or after substitution has rebound Self and the trait arguments.
For those cases we keep associated types as ProjectionType values carrying
the trait ref, associated item, Self type and substitutions, then normalize
them when the type is actually used. This avoids global associated type
mutation and lets generic associated type arguments compose through
substitution, unification and backend lowering.
Fixes Rust-GCC#4293
gcc/rust/ChangeLog:
* backend/rust-compile-expr.cc (CompileExpr::generate_closure_fntype):
Stop eagerly setting FnOnce::Output
* backend/rust-compile-item.cc (CompileItem::visit): Push impl-trait
* backend/rust-compile-type.cc (TyTyResolveCompile::visit): Normalize
projection types
* backend/rust-intrinsic-handlers.cc (discriminant_value): Handle
projection
* checks/errors/privacy/rust-privacy-reporter.cc
(PrivacyReporter::check_base_type_privacy): Skip unresolved
* typecheck/rust-hir-type-check-intrinsic.cc
(IntrinsicChecker::check_type): make permissive
* typecheck/rust-autoderef.cc: remove old
* typecheck/rust-hir-impl-trait-context.h: New file.
* typecheck/rust-hir-trait-reference.cc (TraitReference::on_resolved):
Pass the trait reference into item resolution.
(TraitReference::clear_associated_types): Remove.
(TraitReference::clear_associated_type_projections): Remove.
(AssociatedImplTrait::AssociatedImplTrait): Store an impl trait frame
(AssociatedImplTrait::get_frame): New function.
* typecheck/rust-hir-trait-reference.h: Add impl trait context
* typecheck/rust-hir-trait-resolve.cc (TraitItemReference::on_resolved):
Pass trait reference
(TraitItemReference::resolve_item): Represent associated types as
projection types
(TraitItemReference::associated_type_set): Remove.
(TraitItemReference::associated_type_reset): Remove.
(AssociatedImplTrait::setup_raw_associated_types): Remove.
(AssociatedImplTrait::bind_impl_for_projection): New function.
(AssociatedImplTrait::bind_impl_for_bound): New function.
(AssociatedImplTrait::reset_associated_types): Remove.
* typecheck/rust-hir-type-check-base.cc
(TypeCheckBase::ResolvePredicateFromBound): New function.
* typecheck/rust-hir-type-check-base.h
(TypeCheckBase::ResolvePredicateFromBound): Declare.
* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit):
Handle projection
(TypeCheckExpr::resolve_fn_trait_call): monomorphized
* typecheck/rust-hir-type-check-implitem.cc
(TypeCheckImplItemWithTrait::visit): Store impl associated types as
projections
* typecheck/rust-hir-type-check-item.cc
(TypeCheckItem::ResolveImplBlockSubstitutions): New function.
(TypeCheckItem::ResolveImplTraitAssociatedTypes): New function.
(TypeCheckItem::validate_trait_impl_block): cleanup
(TypeCheckItem::visit): Split inherent and trait impl handling.
(TypeCheckItem::resolve_impl_block): New function.
(TypeCheckItem::resolve_trait_impl_block): New function.
(TypeCheckItem::resolve_impl_block_substitutions): cleanup
* typecheck/rust-hir-type-check-item.h: helpers
* typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit):
cleanup
(TypeCheckExpr::resolve_segments): Use lazy projection normalization
* typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit):
Normalize type path projections and build qualified associated types
* typecheck/rust-hir-type-check.h (class ScopedPush): New class.
(class ImplTraitFrameGuard): New class.
* typecheck/rust-type-util.cc (query_type): Push impl trait frames
while resolving impl items.
(rebind_projection_self_from_fn): New function.
(normalize_projection): New function.
* typecheck/rust-type-util.h (normalize_projection): Declare.
(rebind_projection_self_from_fn): Declare.
* typecheck/rust-typecheck-context.cc
(TypeCheckContext::find_matching_impl_trait_frame): New function.
(TypeCheckContext::have_impl_trait_context): New function.
(TypeCheckContext::push_impl_trait_context): New function.
(TypeCheckContext::pop_impl_trait_context): New function.
(TypeCheckContext::peek_impl_trait_context): New function.
* typecheck/rust-tyty-bounds.cc
(TypeBoundPredicate::apply_argument_mappings): Stop mutating
associated type items for binding arguments.
(TypeBoundPredicateItem::get_tyty_for_receiver): Rebase projections
using trait substitution coordinates.
(TypeBoundPredicate::handle_substitions): Stop mutating associated
type items for binding arguments.
* typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Rebind
projection self types after function monomorphization.
* typecheck/rust-tyty-subst.cc
(SubstitutionParamMapping::fill_param_ty): Guard recursive
(SubstitutionRef::get_mappings_from_generic_args): Account for outer
GAT parameters.
(SubstitutionRef::prepare_higher_ranked_bounds): Remove.
(SubstitutionRef::monomorphize): Bind matching impls
* typecheck/rust-tyty-subst.h
(SubstitutionRef::get_outer_param_count): New function.
(SubstitutionRef::prepare_higher_ranked_bounds): Remove.
* typecheck/rust-tyty.cc (BaseType::satisfies_bound): Check
associated type bindings through projection types.
(BaseType::destructure): Stop destructuring through projections.
(BaseType::monomorphized_clone): Normalize projection clones.
(BaseType::is_concrete): Handle projections
(ClosureType::setup_fn_once_output): Remove.
(destructure_through_projections): New function.
(ReferenceType::is_dyn_slice_type): Normalize projections
(ReferenceType::is_dyn_str_type): Likewise.
(ReferenceType::is_dyn_obj_type): Likewise.
(PointerType::is_dyn_slice_type): Likewise.
(PointerType::is_dyn_str_type): Likewise.
(PointerType::is_dyn_obj_type): Likewise.
(ParamType::get_name): Guard recursive
(PlaceholderType::set_associated_type): Remove
(PlaceholderType::clear_associated_type): Remove
(ProjectionType::ProjectionType): Track projection self type and
inherited trait substitutions.
(ProjectionType::is_trait_position): New function
(ProjectionType::get): Handle non-trait-position projections
(ProjectionType::get_self): New function.
(ProjectionType::get_trait_ref): New function.
(ProjectionType::get_item_defid): New function.
(ProjectionType::as_string): Include projection self and trait
(ProjectionType::clone): Clone projection self and preserve bounds
(ProjectionType::handle_substitions): Substitute projection self
* typecheck/rust-tyty.h: Update projection
* typecheck/rust-unify.cc (UnifyRules::go): Normalize projections
(UnifyRules::expect_projection): Support projection-to-projection
gcc/testsuite/ChangeLog:
* rust/compile/gat1.rs: Add lang item setup.
* rust/compile/gat2.rs: Use no_core setup.
* rust/compile/issue-2036.rs: Remove obsolete type inference error.
* rust/compile/issue-2905-2.rs: Enable iterator impl coverage.
* rust/compile/torture/traits18.rs: Move to...
* rust/compile/torture/traits18.rs.disabled: ...here.
* rust/compile/gat3.rs: New test.
* rust/compile/gat4.rs: New test.
* rust/compile/gat5.rs: New test.
* rust/compile/gat6.rs: New test.
* rust/compile/gat7.rs: New test.
* rust/compile/gat8.rs: New test.
* rust/compile/issue-4293.rs: New test.
Signed-off-by: Philip Herron <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/74c259427e971b8f18492974900d1c57cdc99ad5
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4594
gcc/rust/backend/rust-compile-expr.cc | 4 +-
gcc/rust/backend/rust-compile-item.cc | 22 +-
gcc/rust/backend/rust-compile-type.cc | 16 +-
gcc/rust/backend/rust-intrinsic-handlers.cc | 9 +-
.../errors/privacy/rust-privacy-reporter.cc | 9 +-
gcc/rust/typecheck/rust-autoderef.cc | 1 -
.../typecheck/rust-hir-impl-trait-context.h | 51 ++
.../typecheck/rust-hir-trait-reference.cc | 39 +-
gcc/rust/typecheck/rust-hir-trait-reference.h | 32 +-
gcc/rust/typecheck/rust-hir-trait-resolve.cc | 524 +++++++++---------
.../typecheck/rust-hir-type-check-base.cc | 11 +
gcc/rust/typecheck/rust-hir-type-check-base.h | 6 +
.../typecheck/rust-hir-type-check-expr.cc | 99 ++--
.../typecheck/rust-hir-type-check-implitem.cc | 23 +-
.../rust-hir-type-check-intrinsic.cc | 2 +-
.../typecheck/rust-hir-type-check-item.cc | 313 +++++++----
gcc/rust/typecheck/rust-hir-type-check-item.h | 16 +
.../typecheck/rust-hir-type-check-path.cc | 33 +-
.../typecheck/rust-hir-type-check-type.cc | 73 +--
gcc/rust/typecheck/rust-hir-type-check.h | 51 ++
gcc/rust/typecheck/rust-type-util.cc | 383 ++++++++++++-
gcc/rust/typecheck/rust-type-util.h | 6 +
gcc/rust/typecheck/rust-typecheck-context.cc | 47 ++
gcc/rust/typecheck/rust-tyty-bounds.cc | 72 ++-
gcc/rust/typecheck/rust-tyty-call.cc | 5 +-
gcc/rust/typecheck/rust-tyty-subst.cc | 69 ++-
gcc/rust/typecheck/rust-tyty-subst.h | 9 +-
gcc/rust/typecheck/rust-tyty.cc | 277 +++++----
gcc/rust/typecheck/rust-tyty.h | 31 +-
gcc/rust/typecheck/rust-unify.cc | 106 +++-
gcc/testsuite/rust/compile/gat1.rs | 4 +
gcc/testsuite/rust/compile/gat2.rs | 2 +
gcc/testsuite/rust/compile/gat3.rs | 26 +
gcc/testsuite/rust/compile/gat4.rs | 25 +
gcc/testsuite/rust/compile/gat5.rs | 23 +
gcc/testsuite/rust/compile/gat6.rs | 23 +
gcc/testsuite/rust/compile/gat7.rs | 18 +
gcc/testsuite/rust/compile/gat8.rs | 21 +
gcc/testsuite/rust/compile/issue-2036.rs | 1 -
gcc/testsuite/rust/compile/issue-2905-2.rs | 18 +-
gcc/testsuite/rust/compile/issue-4293.rs | 32 ++
.../{traits18.rs => traits18.rs.disabled} | 0
42 files changed, 1731 insertions(+), 801 deletions(-)
create mode 100644 gcc/rust/typecheck/rust-hir-impl-trait-context.h
create mode 100644 gcc/testsuite/rust/compile/gat3.rs
create mode 100644 gcc/testsuite/rust/compile/gat4.rs
create mode 100644 gcc/testsuite/rust/compile/gat5.rs
create mode 100644 gcc/testsuite/rust/compile/gat6.rs
create mode 100644 gcc/testsuite/rust/compile/gat7.rs
create mode 100644 gcc/testsuite/rust/compile/gat8.rs
create mode 100644 gcc/testsuite/rust/compile/issue-4293.rs
rename gcc/testsuite/rust/compile/torture/{traits18.rs =>
traits18.rs.disabled} (100%)
diff --git a/gcc/rust/backend/rust-compile-expr.cc
b/gcc/rust/backend/rust-compile-expr.cc
index 36c088e8e..7529744d5 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -2681,8 +2681,8 @@ CompileExpr::generate_closure_fntype (HIR::ClosureExpr
&expr,
const TyTy::TypeBoundPredicate &predicate
= *closure_tyty.get_specified_bounds ().begin ();
- // ensure the fn_once_output associated type is set
- closure_tyty.setup_fn_once_output ();
+ // FnOnce::Output is normalized on demand by normalize_projection's closure
+ // special-case
// the function signature is based on the trait bound that the closure
// implements which is determined at the type resolution time
diff --git a/gcc/rust/backend/rust-compile-item.cc
b/gcc/rust/backend/rust-compile-item.cc
index 37b0dd75d..4c627ac90 100644
--- a/gcc/rust/backend/rust-compile-item.cc
+++ b/gcc/rust/backend/rust-compile-item.cc
@@ -186,23 +186,21 @@ CompileItem::visit (HIR::Function &function)
fntype->monomorphize ();
}
- else
+
+ Resolver::AssociatedImplTrait *impl = nullptr;
+ HirId id = function.get_mappings ().get_hirid ();
+ if (auto impl_item = ctx->get_mappings ().lookup_hir_implitem (id))
{
- // if this is part of a trait impl block which is not generic we need to
- // ensure associated types are setup
- HirId id = function.get_mappings ().get_hirid ();
- if (auto impl_item = ctx->get_mappings ().lookup_hir_implitem (id))
- {
- Resolver::AssociatedImplTrait *impl = nullptr;
- bool found = ctx->get_tyctx ()->lookup_associated_trait_impl (
- impl_item->second, &impl);
- if (found)
- impl->setup_raw_associated_types ();
- }
+ ctx->get_tyctx ()->lookup_associated_trait_impl (impl_item->second,
+ &impl);
}
auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
+ tl::optional<Resolver::ImplTraitFrameGuard> guard;
+ if (impl)
+ guard.emplace (impl->get_frame ());
+
Resolver::CanonicalPath canonical_path
= nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid (),
Resolver2_0::Namespace::Values);
diff --git a/gcc/rust/backend/rust-compile-type.cc
b/gcc/rust/backend/rust-compile-type.cc
index 46fcea88f..35d56cc47 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -19,7 +19,9 @@
#include "rust-compile-type.h"
#include "rust-constexpr.h"
#include "rust-compile-base.h"
+#include "rust-type-util.h"
+#include "rust-tyty.h"
#include "tree.h"
#include "fold-const.h"
#include "stor-layout.h"
@@ -168,7 +170,19 @@ TyTyResolveCompile::visit (const TyTy::ConstErrorType
&type)
void
TyTyResolveCompile::visit (const TyTy::ProjectionType &type)
{
- translated = error_mark_node;
+ // workaround to get around const here
+ TyTy::ProjectionType *projection
+ = static_cast<TyTy::ProjectionType *> (type.clone ());
+ auto normalized
+ = Resolver::normalize_projection (projection, BUILTINS_LOCATION, false,
+ false);
+ if (normalized == projection)
+ {
+ translated = error_mark_node;
+ return;
+ }
+
+ translated = TyTyResolveCompile::compile (ctx, normalized, false);
}
void
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 55bc06385..39432ea7c 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1160,14 +1160,12 @@ tree
discriminant_value (Context *ctx, TyTy::FnType *fntype)
{
rust_assert (fntype->get_params ().size () == 1);
- rust_assert (fntype->get_return_type ()->is<TyTy::PlaceholderType> ());
rust_assert (fntype->has_substitutions ());
rust_assert (fntype->get_num_type_params () == 1);
auto &mapping = fntype->get_substs ().at (0);
auto param_ty = mapping.get_param_ty ();
rust_assert (param_ty->can_resolve ());
auto resolved = param_ty->resolve ();
- auto p = static_cast<TyTy::PlaceholderType *> (fntype->get_return_type ());
TyTy::BaseType *return_type = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("isize", &return_type);
@@ -1178,13 +1176,12 @@ discriminant_value (Context *ctx, TyTy::FnType *fntype)
if (is_adt)
{
const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
- return_type = adt.get_repr_options ().repr;
- rust_assert (return_type != nullptr);
+ auto *repr = adt.get_repr_options ().repr;
+ if (repr != nullptr)
+ return_type = repr;
is_enum = adt.is_enum ();
}
- p->set_associated_type (return_type->get_ref ());
-
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
index 9e2238f79..868c5679b 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -244,8 +244,13 @@ PrivacyReporter::check_base_type_privacy
(Analysis::NodeMapping &node_mappings,
return recursive_check (p->resolve ());
}
case TyTy::PROJECTION:
- return recursive_check (
- static_cast<const TyTy::ProjectionType *> (ty)->get ());
+ {
+ auto p = static_cast<const TyTy::ProjectionType *> (ty);
+ if (p->is_trait_position ())
+ return;
+ return recursive_check (
+ static_cast<const TyTy::ProjectionType *> (ty)->get ());
+ }
case TyTy::CLOSURE:
rust_sorry_at (locus, "privacy pass for closures is not handled yet");
break;
diff --git a/gcc/rust/typecheck/rust-autoderef.cc
b/gcc/rust/typecheck/rust-autoderef.cc
index 7f70e263f..0c20d41c5 100644
--- a/gcc/rust/typecheck/rust-autoderef.cc
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -235,7 +235,6 @@ resolve_operator_overload_fn (
}
// we found a valid operator overload
- fn->prepare_higher_ranked_bounds ();
rust_debug ("resolved operator overload to: {%u} {%s}",
candidate.candidate.ty->get_ref (),
candidate.candidate.ty->debug_str ().c_str ());
diff --git a/gcc/rust/typecheck/rust-hir-impl-trait-context.h
b/gcc/rust/typecheck/rust-hir-impl-trait-context.h
new file mode 100644
index 000000000..ab08a71fa
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-impl-trait-context.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2021-2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_IMPL_TRAIT_CONTEXT_H
+#define RUST_HIR_IMPL_TRAIT_CONTEXT_H
+
+#include "rust-hir-map.h"
+
+namespace Rust {
+
+namespace TyTy {
+class BaseType;
+}
+
+namespace Resolver {
+
+class TraitReference;
+
+struct AssocTypeEntry
+{
+ DefId trait_item_defid;
+ DefId impl_item_defid;
+ TyTy::BaseType *value;
+};
+
+struct ImplTraitContextFrame
+{
+ const TraitReference *trait;
+ TyTy::BaseType *self;
+ std::map<DefId, AssocTypeEntry> assoc_types_by_trait_item;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_IMPL_TRAIT_CONTEXT_H
diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc
b/gcc/rust/typecheck/rust-hir-trait-reference.cc
index 7d04d508f..1753988ea 100644
--- a/gcc/rust/typecheck/rust-hir-trait-reference.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-hir-trait-reference.h"
+#include "rust-hir-type-check.h"
namespace Rust {
namespace Resolver {
@@ -344,37 +345,13 @@ TraitReference::on_resolved ()
{
if (item.get_trait_item_type ()
== TraitItemReference::TraitItemType::TYPE)
- item.on_resolved ();
+ item.on_resolved (this);
}
for (auto &item : item_refs)
{
if (item.get_trait_item_type ()
!= TraitItemReference::TraitItemType::TYPE)
- item.on_resolved ();
- }
-}
-
-void
-TraitReference::clear_associated_types () const
-{
- for (const auto &item : item_refs)
- {
- bool is_assoc_type = item.get_trait_item_type ()
- == TraitItemReference::TraitItemType::TYPE;
- if (is_assoc_type)
- item.associated_type_reset (false);
- }
-}
-
-void
-TraitReference::clear_associated_type_projections () const
-{
- for (const auto &item : item_refs)
- {
- bool is_assoc_type = item.get_trait_item_type ()
- == TraitItemReference::TraitItemType::TYPE;
- if (is_assoc_type)
- item.associated_type_reset (true);
+ item.on_resolved (this);
}
}
@@ -463,9 +440,9 @@ AssociatedImplTrait::AssociatedImplTrait (TraitReference
*trait,
TyTy::TypeBoundPredicate predicate,
HIR::ImplBlock *impl,
TyTy::BaseType *self,
- Resolver::TypeCheckContext *context)
+ ImplTraitContextFrame frame)
: trait (trait), predicate (predicate), impl (impl), self (self),
- context (context)
+ context (TypeCheckContext::get ()), frame (frame)
{}
TyTy::TypeBoundPredicate &
@@ -492,5 +469,11 @@ AssociatedImplTrait::get_self () const
return self;
}
+ImplTraitContextFrame
+AssociatedImplTrait::get_frame () const
+{
+ return frame;
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h
b/gcc/rust/typecheck/rust-hir-trait-reference.h
index 178a8562f..a8f923826 100644
--- a/gcc/rust/typecheck/rust-hir-trait-reference.h
+++ b/gcc/rust/typecheck/rust-hir-trait-reference.h
@@ -21,6 +21,7 @@
#include "rust-hir-full.h"
#include "rust-tyty-visitor.h"
+#include "rust-hir-impl-trait-context.h"
namespace Rust {
namespace Resolver {
@@ -101,11 +102,7 @@ public:
// resolution on construction it can lead to a case where the trait being
// resolved recursively trying to resolve the trait itself infinitely since
// the trait will not be stored in its own map yet
- void on_resolved ();
-
- void associated_type_set (TyTy::BaseType *ty) const;
-
- void associated_type_reset (bool only_projections) const;
+ void on_resolved (const TraitReference *tref);
bool is_object_safe () const;
@@ -121,9 +118,9 @@ private:
TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const;
bool is_item_resolved () const;
- void resolve_item (HIR::TraitItemType &type);
- void resolve_item (HIR::TraitItemConst &constant);
- void resolve_item (HIR::TraitItemFunc &func);
+ void resolve_item (const TraitReference *tref, HIR::TraitItemType &type);
+ void resolve_item (const TraitReference *tref, HIR::TraitItemConst
&constant);
+ void resolve_item (const TraitReference *tref, HIR::TraitItemFunc &func);
std::string identifier;
bool optional_flag;
@@ -212,10 +209,6 @@ public:
void on_resolved ();
- void clear_associated_types () const;
-
- void clear_associated_type_projections () const;
-
bool is_equal (const TraitReference &other) const;
std::vector<TyTy::TypeBoundPredicate> get_super_traits () const;
@@ -242,8 +235,7 @@ class AssociatedImplTrait
public:
AssociatedImplTrait (TraitReference *trait,
TyTy::TypeBoundPredicate predicate, HIR::ImplBlock *impl,
- TyTy::BaseType *self,
- Resolver::TypeCheckContext *context);
+ TyTy::BaseType *self, ImplTraitContextFrame frame);
TyTy::TypeBoundPredicate &get_predicate ();
@@ -254,13 +246,14 @@ public:
TyTy::BaseType *get_self ();
const TyTy::BaseType *get_self () const;
- void setup_raw_associated_types ();
+ ImplTraitContextFrame get_frame () const;
- TyTy::BaseType *setup_associated_types (
- const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound,
- TyTy::SubstitutionArgumentMappings *args = nullptr, bool infer = true);
+ TyTy::SubstitutionArgumentMappings
+ bind_impl_for_projection (TyTy::ProjectionType &proj, location_t locus);
- void reset_associated_types ();
+ TyTy::SubstitutionArgumentMappings
+ bind_impl_for_bound (TyTy::BaseType *receiver,
+ const TyTy::TypeBoundPredicate &bound, location_t locus);
private:
TraitReference *trait;
@@ -268,6 +261,7 @@ private:
HIR::ImplBlock *impl;
TyTy::BaseType *self;
Resolver::TypeCheckContext *context;
+ ImplTraitContextFrame frame;
};
} // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index 357fb5997..b036c634f 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-hir-trait-resolve.h"
+#include "rust-hir-trait-reference.h"
#include "rust-hir-type-check-expr.h"
#include "rust-rib.h"
#include "rust-substitution-mapper.h"
@@ -339,20 +340,20 @@ TraitResolver::lookup_path (HIR::TypePath &path)
}
void
-TraitItemReference::on_resolved ()
+TraitItemReference::on_resolved (const TraitReference *tref)
{
switch (type)
{
case CONST:
- resolve_item (static_cast<HIR::TraitItemConst &> (*hir_trait_item));
+ resolve_item (tref, static_cast<HIR::TraitItemConst &>
(*hir_trait_item));
break;
case TYPE:
- resolve_item (static_cast<HIR::TraitItemType &> (*hir_trait_item));
+ resolve_item (tref, static_cast<HIR::TraitItemType &> (*hir_trait_item));
break;
case FN:
- resolve_item (static_cast<HIR::TraitItemFunc &> (*hir_trait_item));
+ resolve_item (tref, static_cast<HIR::TraitItemFunc &> (*hir_trait_item));
break;
default:
@@ -361,17 +362,58 @@ TraitItemReference::on_resolved ()
}
void
-TraitItemReference::resolve_item (HIR::TraitItemType &type)
+TraitItemReference::resolve_item (const TraitReference *tref,
+ HIR::TraitItemType &type)
{
- TyTy::BaseType *ty
- = new TyTy::PlaceholderType (type.get_name ().as_string (),
- type.get_mappings ().get_defid (),
- type.get_mappings ().get_hirid ());
- context->insert_type (type.get_mappings (), ty);
+ auto substitutions = inherited_substitutions;
+ if (type.has_generics ())
+ {
+ auto binder_pin = context->push_lifetime_binder ();
+ TypeCheckBase::ResolveGenericParams (HIR::Item::ItemKind::TypeAlias,
+ type.get_locus (),
+ type.get_generic_params (),
+ substitutions, false, ABI::RUST);
+ }
+
+ size_t inherited_count = inherited_substitutions.size ();
+ auto projection
+ = new TyTy::ProjectionType (type.get_mappings ().get_hirid (), nullptr,
+ tref, type.get_mappings ().get_defid (),
+ substitutions, self,
+ TyTy::SubstitutionArgumentMappings::error (),
+ {}, {}, inherited_count);
+
+ // Attach the bounds declared on the associated type itself:
+ //
+ // type IntoIter: Iterator<Item = Self::Item>
+ //
+ // so satisfies_bound finds them in specified_bounds
+ if (type.has_type_param_bounds ())
+ {
+ std::vector<TyTy::TypeBoundPredicate> trait_item_bounds;
+ for (auto &bound : type.get_type_param_bounds ())
+ {
+ if (bound->get_bound_type ()
+ != HIR::TypeParamBound::BoundType::TRAITBOUND)
+ continue;
+ auto *b = static_cast<HIR::TraitBound *> (bound.get ());
+ auto predicate = TypeCheckBase::ResolvePredicateFromBound (
+ b->get_path (),
+ tl::nullopt /*this will setup a PLACEHOLDER for self*/,
+ BoundPolarity::RegularBound, false, true);
+ if (!predicate.is_error ())
+ trait_item_bounds.push_back (std::move (predicate));
+ }
+ if (!trait_item_bounds.empty ())
+ projection->inherit_bounds (trait_item_bounds);
+ }
+
+ context->insert_type (type.get_mappings (), projection);
}
void
-TraitItemReference::resolve_item (HIR::TraitItemConst &constant)
+TraitItemReference::resolve_item (const TraitReference *tref,
+ HIR::TraitItemConst &constant)
{
TyTy::BaseType *ty = nullptr;
if (constant.has_type ())
@@ -396,7 +438,8 @@ TraitItemReference::resolve_item (HIR::TraitItemConst
&constant)
}
void
-TraitItemReference::resolve_item (HIR::TraitItemFunc &func)
+TraitItemReference::resolve_item (const TraitReference *tref,
+ HIR::TraitItemFunc &func)
{
TyTy::BaseType *item_tyty = get_tyty ();
if (item_tyty->get_kind () == TyTy::TypeKind::ERROR)
@@ -427,311 +470,252 @@ TraitItemReference::resolve_item (HIR::TraitItemFunc
&func)
context->pop_return_type ();
}
-void
-TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
+TyTy::SubstitutionArgumentMappings
+AssociatedImplTrait::bind_impl_for_projection (TyTy::ProjectionType &proj,
+ location_t locus)
{
- rust_assert (get_trait_item_type () == TraitItemType::TYPE);
-
- // this isnt super safe there are cases like the FnTraits where the type is
- // set to the impls placeholder associated type. For example
- //
- // type Output = F::Output; -- see the fn trait impls in libcore
- //
- // then this projection ends up resolving back to this placeholder so it just
- // ends up being cyclical
-
- TyTy::BaseType *item_ty = get_tyty ();
- rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
- TyTy::PlaceholderType *placeholder
- = static_cast<TyTy::PlaceholderType *> (item_ty);
-
- if (ty->is<TyTy::ProjectionType> ())
+ std::vector<TyTy::SubstitutionParamMapping> impl_substitutions;
+ for (auto &generic_param : impl->get_generic_params ())
{
- const auto &projection = *static_cast<const TyTy::ProjectionType *> (ty);
- const auto resolved = projection.get ();
- if (resolved == item_ty)
- return;
+ if (generic_param->get_kind () != HIR::GenericParam::GenericKind::TYPE)
+ continue;
+ TyTy::BaseType *l = nullptr;
+ bool ok
+ = context->lookup_type (generic_param->get_mappings ().get_hirid (),
+ &l);
+ if (!ok || l->get_kind () != TyTy::TypeKind::PARAM)
+ continue;
+ impl_substitutions.emplace_back (static_cast<HIR::TypeParam &> (
+ *generic_param),
+ static_cast<TyTy::ParamType *> (l));
}
- placeholder->set_associated_type (ty->get_ty_ref ());
-}
-
-void
-TraitItemReference::associated_type_reset (bool only_projections) const
-{
- rust_assert (get_trait_item_type () == TraitItemType::TYPE);
-
- TyTy::BaseType *item_ty = get_tyty ();
- rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
- TyTy::PlaceholderType *placeholder
- = static_cast<TyTy::PlaceholderType *> (item_ty);
+ // Build infer args for each impl param so we dont mutate the impls own
+ // ParamTys when unifying. param_mappings records impl_param_symbol ->
+ // hirid_of_fresh_infer_var so we can read out what each param resolved to
+ // after unification.
+ std::vector<TyTy::SubstitutionArg> infer_arg_vec;
+ std::map<std::string, HirId> param_mappings;
+ for (auto &p : impl_substitutions)
+ {
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
+ TyTy::BaseType *resolved = infer_var.get_tyty ();
+ infer_arg_vec.emplace_back (&p, resolved);
+ param_mappings[symbol] = resolved->get_ref ();
+ }
+ TyTy::SubstitutionArgumentMappings infer_arguments (
+ std::move (infer_arg_vec), {} /*binding_args*/,
+ TyTy::RegionParamList (0) /*regions*/, locus);
- if (!only_projections)
+ TyTy::BaseType *impl_self_infer
+ = !self->is_concrete ()
+ ? SubstMapperInternal::Resolve (self->clone (), infer_arguments)
+ : self->clone ();
+
+ // sub the impls trait predicate args with infers:
+ // SliceIndex<[Y]> -> SliceIndex<[?Y]>
+ const TyTy::TypeBoundPredicate &impl_predicate = predicate;
+ std::vector<TyTy::BaseType *> impl_predicate_args;
+ for (size_t i = 1; i < impl_predicate.get_substs ().size (); i++)
{
- placeholder->clear_associated_type ();
+ auto p = impl_predicate.get_substs ().at (i).get_param_ty ();
+ TyTy::BaseType *r = p->resolve ();
+ if (!r->is_concrete ())
+ r = SubstMapperInternal::Resolve (r, infer_arguments);
+ impl_predicate_args.push_back (r);
}
- else
+
+ // Read the projections own (trait-coord) substs and skip Self at index 0.
+ // The projection's substs match by symbol in handle_substitions, so a
+ // fn-level substitution that binds T won't have walked into the
+ // projections X slot whose resolved value is [T]. Re-apply the
+ // projections own used_arguments to each arg so any stale impl-coord
+ // params inside (the T inside [T]) are followed through to their
+ // current bindings
+ TyTy::SubstitutionArgumentMappings proj_used
+ = proj.get_substitution_arguments ();
+ std::vector<TyTy::BaseType *> proj_args;
+ for (size_t i = 1; i < proj.get_substs ().size (); i++)
{
- if (!placeholder->can_resolve ())
- return;
+ auto p = proj.get_substs ().at (i).get_param_ty ();
+ TyTy::BaseType *r = p->resolve ();
+ if (!r->is_concrete () && !proj_used.is_empty ())
+ r = SubstMapperInternal::Resolve (r, proj_used);
+ proj_args.push_back (r);
+ }
- const TyTy::BaseType *r = placeholder->resolve ();
- if (r->get_kind () == TyTy::TypeKind::PROJECTION)
+ if (impl_predicate_args.size () != proj_args.size ())
+ return TyTy::SubstitutionArgumentMappings::error ();
+
+ // unify trait args [?Y] -> [{integer}]
+ for (size_t i = 0; i < proj_args.size (); i++)
+ {
+ TyTy::BaseType *proj_arg = proj_args[i];
+ if (impl_predicate_args[i]->get_kind () == TyTy::TypeKind::SLICE
+ && proj_arg->get_kind () != TyTy::TypeKind::SLICE)
{
- placeholder->clear_associated_type ();
+ auto &mappings = Analysis::Mappings::get ();
+ HirId id = mappings.get_next_hir_id ();
+ auto *wrapped
+ = new TyTy::SliceType (id, proj_arg->get_locus (),
+ TyTy::TyVar (proj_arg->get_ref ()));
+ context->insert_implicit_type (id, wrapped);
+ proj_arg = wrapped;
}
+
+ auto *res = unify_site_and (0 /*id*/,
+ TyTy::TyWithLocation (impl_predicate_args[i]),
+ TyTy::TyWithLocation (proj_arg), locus,
+ false /*emit_errors*/, true /*commit_if_ok*/,
+ true /*infer*/, true /*cleanup_on_fail*/,
+ false /*check_bounds*/);
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ return TyTy::SubstitutionArgumentMappings::error ();
}
-}
-void
-AssociatedImplTrait::setup_raw_associated_types ()
-{
- auto &impl_items = impl->get_impl_items ();
- for (auto &impl_item : impl_items)
+ // unify self Range<{integer}> -> Range<usize>
+ auto *res = unify_site_and (impl->get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (proj.get_self ()),
+ TyTy::TyWithLocation (impl_self_infer), locus,
+ false /*emit_errors*/, true /*commit_if_ok*/,
+ true /*infer*/, true /*cleanup_on_fail*/,
+ false /*check_bounds*/);
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ return TyTy::SubstitutionArgumentMappings::error ();
+
+ std::vector<TyTy::SubstitutionArg> resolved_args;
+ for (auto &p : impl_substitutions)
{
- bool is_type_alias = impl_item->get_impl_item_type ()
- == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
- if (!is_type_alias)
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ auto it = param_mappings.find (symbol);
+ if (it == param_mappings.end ())
continue;
-
- HIR::TypeAlias &type = *static_cast<HIR::TypeAlias *> (impl_item.get ());
-
- TraitItemReference *resolved_trait_item = nullptr;
- bool ok
- = trait->lookup_trait_item (type.get_new_type_name ().as_string (),
- &resolved_trait_item);
+ TyTy::BaseType *r = nullptr;
+ bool ok = context->lookup_type (it->second, &r);
if (!ok)
continue;
- if (resolved_trait_item->get_trait_item_type ()
- != TraitItemReference::TraitItemType::TYPE)
- continue;
-
- TyTy::BaseType *lookup;
- ok = context->lookup_type (type.get_mappings ().get_hirid (), &lookup);
- rust_assert (ok);
-
- resolved_trait_item->associated_type_set (lookup);
+ resolved_args.emplace_back (&p, r);
}
+
+ return TyTy::SubstitutionArgumentMappings (std::move (resolved_args),
+ {} /*binding_args*/,
+ TyTy::RegionParamList (0)
+ /*regions*/,
+ locus);
}
-TyTy::BaseType *
-AssociatedImplTrait::setup_associated_types (
- const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound,
- TyTy::SubstitutionArgumentMappings *args, bool infer)
+TyTy::SubstitutionArgumentMappings
+AssociatedImplTrait::bind_impl_for_bound (TyTy::BaseType *receiver,
+ const TyTy::TypeBoundPredicate &bound,
+ location_t locus)
{
- // compute the constrained impl block generic arguments based on self and the
- // higher ranked trait bound
- TyTy::BaseType *receiver = self->clone ();
-
- // impl<Y> SliceIndex<[Y]> for Range<usize>
- // vs
- // I: SliceIndex<[<integer>]> and Range<<integer>>
- //
- // we need to figure out what Y is
-
- TyTy::BaseType *associated_self = get_self ();
-
- rust_debug ("setup_associated_types for: %s->%s bound %s",
- associated_self->debug_str ().c_str (),
- self->debug_str ().c_str (), bound.as_string ().c_str ());
-
- // grab the parameters
- HIR::ImplBlock &impl_block = *get_impl_block ();
- std::vector<TyTy::SubstitutionParamMapping> substitutions;
- for (auto &generic_param : impl_block.get_generic_params ())
+ // Same shape as bind_impl_for_projection but the receiver/trait-args are
+ // taken from the (binding, bound) pair instead of a ProjectionType.
+ std::vector<TyTy::SubstitutionParamMapping> impl_substitutions;
+ for (auto &generic_param : impl->get_generic_params ())
{
- switch (generic_param.get ()->get_kind ())
- {
- case HIR::GenericParam::GenericKind::LIFETIME:
- case HIR::GenericParam::GenericKind::CONST:
- // FIXME: Skipping Lifetime and Const completely until better
- // handling.
- break;
-
- case HIR::GenericParam::GenericKind::TYPE:
- {
- TyTy::BaseType *l = nullptr;
- bool ok = context->lookup_type (
- generic_param->get_mappings ().get_hirid (), &l);
- if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
- {
- substitutions.emplace_back (static_cast<HIR::TypeParam &> (
- *generic_param),
- static_cast<TyTy::ParamType *> (l));
- }
- }
- break;
- }
+ if (generic_param->get_kind () != HIR::GenericParam::GenericKind::TYPE)
+ continue;
+ TyTy::BaseType *l = nullptr;
+ bool ok
+ = context->lookup_type (generic_param->get_mappings ().get_hirid (),
+ &l);
+ if (!ok || l->get_kind () != TyTy::TypeKind::PARAM)
+ continue;
+ impl_substitutions.emplace_back (static_cast<HIR::TypeParam &> (
+ *generic_param),
+ static_cast<TyTy::ParamType *> (l));
}
- // this callback gives us the parameters that get substituted so we can
- // compute the constrained type parameters for this impl block
+ std::vector<TyTy::SubstitutionArg> infer_arg_vec;
std::map<std::string, HirId> param_mappings;
- TyTy::ParamSubstCb param_subst_cb
- = [&] (const TyTy::ParamType &p, const TyTy::SubstitutionArg &a) {
- param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref ();
- };
-
- // generate inference variables for these bound arguments so we can compute
- // their values
- location_t locus = UNKNOWN_LOCATION;
- std::vector<TyTy::SubstitutionArg> subst_args;
- for (auto &p : substitutions)
+ for (auto &p : impl_substitutions)
{
- if (p.needs_substitution () && infer)
- {
- TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
- subst_args.emplace_back (&p, infer_var.get_tyty ());
- }
- else
- {
- auto param = p.get_param_ty ();
- auto resolved = param->destructure ();
- subst_args.emplace_back (&p, resolved);
- param_mappings[param->get_symbol ()] = resolved->get_ref ();
- }
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
+ TyTy::BaseType *resolved = infer_var.get_tyty ();
+ infer_arg_vec.emplace_back (&p, resolved);
+ param_mappings[symbol] = resolved->get_ref ();
}
-
TyTy::SubstitutionArgumentMappings infer_arguments (
- std::move (subst_args), {},
- TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args),
- locus, param_subst_cb);
- TyTy::BaseType *impl_self_infer
- = (!associated_self->is_concrete ())
- ? SubstMapperInternal::Resolve (associated_self, infer_arguments)
- : associated_self;
+ std::move (infer_arg_vec), {} /*binding_args*/,
+ TyTy::RegionParamList (0) /*regions*/, locus);
- const TyTy::TypeBoundPredicate &impl_predicate
- = associated_self->lookup_predicate (bound.get_id ());
- rust_assert (!impl_predicate.is_error ());
-
- // infer the arguments on the predicate
- std::vector<TyTy::BaseType *> impl_trait_predicate_args;
+ TyTy::BaseType *impl_self_infer
+ = !self->is_concrete ()
+ ? SubstMapperInternal::Resolve (self->clone (), infer_arguments)
+ : self->clone ();
- for (size_t i = 0; i < impl_predicate.get_substs ().size (); i++)
+ const TyTy::TypeBoundPredicate &impl_predicate = predicate;
+ std::vector<TyTy::BaseType *> impl_predicate_args;
+ for (size_t i = 1; i < impl_predicate.get_substs ().size (); i++)
{
- const auto &arg = impl_predicate.get_substs ().at (i);
- if (i == 0)
- continue;
-
- const auto p = arg.get_param_ty ();
- auto r = p->resolve ();
+ auto p = impl_predicate.get_substs ().at (i).get_param_ty ();
+ TyTy::BaseType *r = p->resolve ();
if (!r->is_concrete ())
- {
- r = SubstMapperInternal::Resolve (r, infer_arguments);
- }
- impl_trait_predicate_args.push_back (r);
+ r = SubstMapperInternal::Resolve (r, infer_arguments);
+ impl_predicate_args.push_back (r);
}
- // unify the bounds arguments
- std::vector<TyTy::BaseType *> hrtb_bound_arguments;
- for (size_t i = 0; i < bound.get_substs ().size (); i++)
+ // Trait args from the bound predicate the caller passed in (skip Self).
+ // Apply the bound's own used_arguments so any stale impl-coord params
+ // inside follow through to their current bindings.
+ TyTy::SubstitutionArgumentMappings bound_used
+ = bound.get_substitution_arguments ();
+ std::vector<TyTy::BaseType *> bound_args;
+ for (size_t i = 1; i < bound.get_substs ().size (); i++)
{
- const auto &arg = bound.get_substs ().at (i);
- if (i == 0)
- continue;
-
- const auto p = arg.get_param_ty ();
- auto r = p->resolve ();
- if (!r->is_concrete ())
- {
- r = SubstMapperInternal::Resolve (r, infer_arguments);
- }
- hrtb_bound_arguments.push_back (r);
+ auto p = bound.get_substs ().at (i).get_param_ty ();
+ TyTy::BaseType *r = p->resolve ();
+ if (!r->is_concrete () && !bound_used.is_empty ())
+ r = SubstMapperInternal::Resolve (r, bound_used);
+ bound_args.push_back (r);
}
- rust_assert (impl_trait_predicate_args.size ()
- == hrtb_bound_arguments.size ());
- for (size_t i = 0; i < impl_trait_predicate_args.size (); i++)
- {
- TyTy::BaseType *a = impl_trait_predicate_args.at (i);
- TyTy::BaseType *b = hrtb_bound_arguments.at (i);
-
- TyTy::BaseType *result
- = unify_site_and (a->get_ref (), TyTy::TyWithLocation (a),
- TyTy::TyWithLocation (b), impl_predicate.get_locus (),
- true /*emit-errors*/, true /*commit-if-ok*/,
- true /*infer*/, true /*cleanup-on-fail*/);
- rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
- }
+ if (impl_predicate_args.size () != bound_args.size ())
+ return TyTy::SubstitutionArgumentMappings::error ();
- // we need to unify the receiver with the impl-block Self so that we compute
- // the type correctly as our receiver may be generic and we are inferring its
- // generic arguments and this Self might be the concrete version or vice
- // versa.
- auto result = unify_site_and (get_impl_block ()->get_mappings ().get_hirid
(),
- TyTy::TyWithLocation (receiver),
- TyTy::TyWithLocation (impl_self_infer),
- impl_predicate.get_locus (),
- true /*emit-errors*/, true /*commit-if-ok*/,
- true /*infer*/, true /*cleanup-on-fail*/);
- rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
- TyTy::BaseType *self_result = result;
-
- // create the argument list
- std::vector<TyTy::SubstitutionArg> associated_arguments;
- for (auto &p : substitutions)
+ for (size_t i = 0; i < bound_args.size (); i++)
{
- std::string symbol = p.get_param_ty ()->get_symbol ();
- auto it = param_mappings.find (symbol);
- rust_assert (it != param_mappings.end ());
-
- HirId id = it->second;
- TyTy::BaseType *argument = nullptr;
- bool ok = context->lookup_type (id, &argument);
- rust_assert (ok);
-
- TyTy::SubstitutionArg arg (&p, argument);
- associated_arguments.push_back (arg);
+ auto *res = unify_site_and (0 /*id*/,
+ TyTy::TyWithLocation (impl_predicate_args[i]),
+ TyTy::TyWithLocation (bound_args[i]), locus,
+ false /*emit_errors*/, true /*commit_if_ok*/,
+ true /*infer*/, true /*cleanup_on_fail*/,
+ false /*check_bounds*/);
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ return TyTy::SubstitutionArgumentMappings::error ();
}
- TyTy::SubstitutionArgumentMappings associated_type_args (
- std::move (associated_arguments), {},
- TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args),
- locus);
-
- auto &impl_items = impl->get_impl_items ();
- for (auto &impl_item : impl_items)
+ auto *res = unify_site_and (impl->get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (receiver),
+ TyTy::TyWithLocation (impl_self_infer), locus,
+ false /*emit_errors*/, true /*commit_if_ok*/,
+ true /*infer*/, true /*cleanup_on_fail*/,
+ false /*check_bounds*/);
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ return TyTy::SubstitutionArgumentMappings::error ();
+
+ std::vector<TyTy::SubstitutionArg> resolved_args;
+ for (auto &p : impl_substitutions)
{
- bool is_type_alias = impl_item->get_impl_item_type ()
- == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
- if (!is_type_alias)
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ auto it = param_mappings.find (symbol);
+ if (it == param_mappings.end ())
continue;
-
- HIR::TypeAlias &type = *static_cast<HIR::TypeAlias *> (impl_item.get ());
-
- TraitItemReference *resolved_trait_item = nullptr;
- bool ok
- = trait->lookup_trait_item (type.get_new_type_name ().as_string (),
- &resolved_trait_item);
+ TyTy::BaseType *r = nullptr;
+ bool ok = context->lookup_type (it->second, &r);
if (!ok)
continue;
- if (resolved_trait_item->get_trait_item_type ()
- != TraitItemReference::TraitItemType::TYPE)
- continue;
-
- TyTy::BaseType *lookup;
- if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
- continue;
-
- // this might be generic
- TyTy::BaseType *substituted
- = SubstMapperInternal::Resolve (lookup, associated_type_args);
- resolved_trait_item->associated_type_set (substituted);
+ resolved_args.emplace_back (&p, r);
}
- if (args != nullptr)
- {
- *args = associated_type_args;
- }
-
- return self_result;
-}
-
-void
-AssociatedImplTrait::reset_associated_types ()
-{
- trait->clear_associated_types ();
+ return TyTy::SubstitutionArgumentMappings (std::move (resolved_args),
+ {} /*binding_args*/,
+ TyTy::RegionParamList (0)
+ /*regions*/,
+ locus);
}
location_t
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc
b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index 6c3cb4054..bacd5f5f4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -46,6 +46,17 @@ TypeCheckBase::ResolveGenericParams (
substitutions, is_foreign, abi);
}
+TyTy::TypeBoundPredicate
+TypeCheckBase::ResolvePredicateFromBound (
+ HIR::TypePath &path,
+ tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
+ BoundPolarity polarity, bool is_qualified_type, bool is_super_trait)
+{
+ TypeCheckBase ctx;
+ return ctx.get_predicate_from_bound (path, associated_self, polarity,
+ is_qualified_type, is_super_trait);
+}
+
static void
walk_types_to_constrain (std::set<HirId> &constrained_symbols,
const TyTy::SubstitutionArgumentMappings &constraints)
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h
b/gcc/rust/typecheck/rust-hir-type-check-base.h
index 2ed4f0526..3a9df89a5 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -38,6 +38,12 @@ public:
std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool
is_foreign,
ABI abi);
+ static TyTy::TypeBoundPredicate ResolvePredicateFromBound (
+ HIR::TypePath &path,
+ tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
+ BoundPolarity polarity = BoundPolarity::RegularBound,
+ bool is_qualified_type = false, bool is_super_trait = false);
+
protected:
TypeCheckBase ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index f3d2c3a27..c46338fb2 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -18,6 +18,7 @@
#include "optional.h"
#include "rust-common.h"
+#include "rust-diagnostics.h"
#include "rust-hir-expr.h"
#include "rust-hir-map.h"
#include "rust-rib.h"
@@ -37,7 +38,6 @@
#include "rust-compile-base.h"
#include "rust-tyty-util.h"
#include "rust-tyty.h"
-#include "tree.h"
namespace Rust {
namespace Resolver {
@@ -289,49 +289,48 @@ TypeCheckExpr::visit (HIR::CallExpr &expr)
infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant,
context);
+ // Pre-GATS: associated types were PlaceholderType; post-GATS they are
+ // ProjectionType, this hHandle both so the isize special-case still fires
auto discriminant_type_lookup
= mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
- if (infered->is<TyTy::PlaceholderType> () && discriminant_type_lookup)
- {
- const auto &p = *static_cast<const TyTy::PlaceholderType *> (infered);
- if (p.get_def_id () == discriminant_type_lookup.value ())
- {
- // this is a special case where this will actually return the repr of
- // the enum. We dont currently support repr on enum yet to change the
- // discriminant type but the default is always isize. We need to
- // assert this is a generic function with one param
- //
- // fn<BookFormat> (v & T=BookFormat{Paperback) -> <placeholder:>
- //
- // note the default is isize
-
- bool ok = context->lookup_builtin ("isize", &infered);
- rust_assert (ok);
+ bool is_discriminant_type = false;
+ if (discriminant_type_lookup)
+ {
+ if (auto *p = infered->try_as<TyTy::PlaceholderType> ())
+ is_discriminant_type
+ = p->get_def_id () == discriminant_type_lookup.value ();
+ else if (auto *p = infered->try_as<TyTy::ProjectionType> ())
+ is_discriminant_type
+ = p->get_item_defid () == discriminant_type_lookup.value ();
+ }
+ if (is_discriminant_type)
+ {
+ // This is a special case: discriminant_value returns the repr of the
+ // enum. We don't currently support repr on enum yet, so the default
+ // is always isize.
+ bool ok = context->lookup_builtin ("isize", &infered);
+ rust_assert (ok);
- rust_assert (function_tyty->is<TyTy::FnType> ());
- auto &fn = *static_cast<TyTy::FnType *> (function_tyty);
- rust_assert (fn.has_substitutions ());
- rust_assert (fn.get_num_type_params () == 1);
- auto &mapping = fn.get_substs ().at (0);
- auto param_ty = mapping.get_param_ty ();
+ rust_assert (function_tyty->is<TyTy::FnType> ());
+ auto &fn = *static_cast<TyTy::FnType *> (function_tyty);
+ rust_assert (fn.has_substitutions ());
+ rust_assert (fn.get_num_type_params () == 1);
+ auto &mapping = fn.get_substs ().at (0);
+ auto param_ty = mapping.get_param_ty ();
- if (!param_ty->can_resolve ())
- {
- // this could be a valid error need to test more weird cases and
- // look at rustc
- rust_internal_error_at (expr.get_locus (),
- "something wrong computing return type");
- return;
- }
+ if (!param_ty->can_resolve ())
+ {
+ rust_internal_error_at (expr.get_locus (),
+ "something wrong computing return type");
+ return;
+ }
- auto resolved = param_ty->resolve ();
- bool is_adt = resolved->is<TyTy::ADTType> ();
- if (is_adt)
- {
- const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
- infered = adt.get_repr_options ().repr;
- rust_assert (infered != nullptr);
- }
+ auto resolved = param_ty->resolve ();
+ if (resolved->is<TyTy::ADTType> ())
+ {
+ const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
+ infered = adt.get_repr_options ().repr;
+ rust_assert (infered != nullptr);
}
}
}
@@ -638,7 +637,7 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
context->push_new_loop_context (expr.get_mappings ().get_hirid (),
expr.get_locus ());
- // Forward the caller's expected type to the block's tail expression only
+ // Forward the caller's expected type to the block's tail expression only.
TyTy::BaseType *outer_expected = context->peek_expected_type ();
context->push_expected_type (nullptr);
@@ -1493,7 +1492,6 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
return;
}
- fn->prepare_higher_ranked_bounds ();
rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}",
found_candidate.candidate.ty->get_ref (),
found_candidate.candidate.ty->debug_str ().c_str ());
@@ -1518,10 +1516,7 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
}
if (!infer_arguments.is_empty ())
- {
- lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
- lookup->debug ();
- }
+ lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
}
// apply any remaining generic arguments
@@ -1894,7 +1889,7 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr)
TyTy::TyVar result_type
= expr.has_return_type ()
? TyTy::TyVar (
- TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
+ TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
: TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
// resolve the block
@@ -2163,7 +2158,6 @@ TypeCheckExpr::resolve_operator_overload (
}
// we found a valid operator overload
- fn->prepare_higher_ranked_bounds ();
rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u}
{%s}",
candidate.candidate.ty->get_ref (),
candidate.candidate.ty->debug_str ().c_str ());
@@ -2312,12 +2306,8 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr
&expr,
return false;
}
- if (receiver_tyty->get_kind () == TyTy::TypeKind::CLOSURE)
- {
- const TyTy::ClosureType &closure
- = static_cast<TyTy::ClosureType &> (*receiver_tyty);
- closure.setup_fn_once_output ();
- }
+ // FnOnce::Output is normalized lazily by normalize_projection's closure
+ // special-case; no explicit setup is required here.
auto candidate = *candidates.begin ();
rust_debug_loc (expr.get_locus (),
@@ -2417,7 +2407,8 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
Resolver2_0::Namespace::Types);
// return the result of the function back
- *result = function_ret_tyty;
+ auto mono = function_ret_tyty->monomorphized_clone ();
+ *result = mono;
return true;
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 850ed0758..9ac226d26 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -565,10 +565,23 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
merge_attributes (type.get_outer_attrs (), *hir_trait_item);
+ // unwrap a ProjectionType that already wraps a concrete
+ if (auto *p = lookup->try_as<TyTy::ProjectionType> ())
+ if (!p->is_trait_position () && p->get () != nullptr
+ && p->get ()->get_kind () != TyTy::TypeKind::PROJECTION)
+ lookup = p->get ();
+
+ // The impl alias is itself a projection so the substitution machinery has a
+ // handle to bind the impl's generic arguments to the alias body.
+ auto projection
+ = new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup,
tref,
+ raw_trait_item->get_mappings ().get_defid (),
+ substitutions, self);
+
// check the types are compatible
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
if (!types_compatable (TyTy::TyWithLocation (trait_item_type),
- TyTy::TyWithLocation (lookup), type.get_locus (),
+ TyTy::TyWithLocation (projection), type.get_locus (),
true /*emit_errors*/))
{
rich_location r (line_table, type.get_locus ());
@@ -579,15 +592,7 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
trait_reference.get_name ().c_str ());
}
- // its actually a projection, since we need a way to actually bind the
- // generic substitutions to the type itself
- TyTy::ProjectionType *projection
- = new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup,
tref,
- raw_trait_item->get_mappings ().get_defid (),
- substitutions);
-
context->insert_type (type.get_mappings (), projection);
- raw_trait_item->associated_type_set (projection);
}
void
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 52754f202..8f51cf135 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -480,7 +480,7 @@ IntrinsicChecker::check_type (const TyTy::BaseType *actual,
return ref->get_base ()->get_kind () == TyTy::TypeKind::STR;
}
case IRT::AssocTypePlaceholder:
- return actual->get_kind () == TyTy::TypeKind::PLACEHOLDER;
+ return true;
case IRT::TupleFirstGenericAndBool:
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 3e4e23658..1299e29b0 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -27,6 +27,7 @@
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-pattern.h"
#include "rust-hir-trait-resolve.h"
+#include "rust-hir-type-check.h"
#include "rust-identifier.h"
#include "rust-rib.h"
#include "rust-session-manager.h"
@@ -34,6 +35,7 @@
#include "rust-substitution-mapper.h"
#include "rust-type-util.h"
#include "rust-tyty-variance-analysis.h"
+#include "rust-tyty.h"
namespace Rust {
namespace Resolver {
@@ -156,6 +158,73 @@ TypeCheckItem::ResolveImplBlockSelfWithInference (
return infer;
}
+std::vector<TyTy::SubstitutionParamMapping>
+TypeCheckItem::ResolveImplBlockSubstitutions (HIR::ImplBlock &impl_block,
+ bool &failure_flag)
+{
+ TypeCheckItem resolver;
+ auto result
+ = resolver.resolve_impl_block_substitutions (impl_block, failure_flag);
+ return std::move (result.first);
+}
+
+void
+TypeCheckItem::validate_trait_impl_block (
+ const TyTy::TypeBoundPredicate &specified_bound,
+ std::vector<const TraitItemReference *> trait_item_refs,
+ TraitReference *trait_reference, HIR::ImplBlock &impl_block,
+ TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> &substitutions)
+{
+ bool impl_block_missing_trait_items
+ = !specified_bound.is_error ()
+ && trait_reference->size () != trait_item_refs.size ();
+ if (impl_block_missing_trait_items
+ && impl_block.get_polarity () == BoundPolarity::RegularBound)
+ {
+ // filter the missing impl_items
+ std::vector<std::reference_wrapper<const TraitItemReference>>
+ missing_trait_items;
+ for (const auto &trait_item_ref : trait_reference->get_trait_items ())
+ {
+ bool found = false;
+ for (auto implemented_trait_item : trait_item_refs)
+ {
+ std::string trait_item_name = trait_item_ref.get_identifier ();
+ std::string impl_item_name
+ = implemented_trait_item->get_identifier ();
+ found = trait_item_name == impl_item_name;
+ if (found)
+ break;
+ }
+
+ bool is_required_trait_item = !trait_item_ref.is_optional ();
+ if (!found && is_required_trait_item)
+ missing_trait_items.emplace_back (trait_item_ref);
+ }
+
+ if (!missing_trait_items.empty ())
+ {
+ std::string missing_items_buf;
+ rich_location r (line_table, impl_block.get_locus ());
+ for (size_t i = 0; i < missing_trait_items.size (); i++)
+ {
+ bool has_more = (i + 1) < missing_trait_items.size ();
+ const TraitItemReference &missing_trait_item
+ = missing_trait_items.at (i);
+ missing_items_buf += missing_trait_item.get_identifier ()
+ + (has_more ? ", " : "");
+ r.add_range (missing_trait_item.get_locus ());
+ }
+
+ rust_error_at (r, ErrorCode::E0046,
+ "missing %s in implementation of trait %qs",
+ missing_items_buf.c_str (),
+ trait_reference->get_name ().c_str ());
+ }
+ }
+}
+
void
TypeCheckItem::visit (HIR::TypeAlias &alias)
{
@@ -471,17 +540,39 @@ TypeCheckItem::visit (HIR::ConstantItem &constant)
void
TypeCheckItem::visit (HIR::ImplBlock &impl_block)
+{
+ if (impl_block.has_trait_ref ())
+ resolve_trait_impl_block (impl_block);
+ else
+ resolve_impl_block (impl_block);
+}
+
+void
+TypeCheckItem::resolve_impl_block (HIR::ImplBlock &impl_block)
{
auto binder_pin = context->push_clean_lifetime_resolver (true);
- TraitReference *trait_reference = &TraitReference::error_node ();
- if (impl_block.has_trait_ref ())
+ bool failed_flag = false;
+ auto result = resolve_impl_block_substitutions (impl_block, failed_flag);
+ if (failed_flag)
{
- HIR::TypePath &ref = impl_block.get_trait_ref ();
- trait_reference = TraitResolver::Resolve (ref);
- if (trait_reference->is_error ())
- return;
+ infered = new TyTy::ErrorType (impl_block.get_mappings ().get_hirid ());
+ return;
}
+ std::vector<TyTy::SubstitutionParamMapping> substitutions
+ = std::move (result.first);
+ TyTy::RegionConstraints region_constraints = std::move (result.second);
+
+ TyTy::BaseType *self = resolve_impl_block_self (impl_block);
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ TypeCheckImplItem::Resolve (impl_block, *impl_item, self, substitutions);
+}
+
+void
+TypeCheckItem::resolve_trait_impl_block (HIR::ImplBlock &impl_block)
+{
+ auto binder_pin = context->push_clean_lifetime_resolver (true);
bool failed_flag = false;
auto result = resolve_impl_block_substitutions (impl_block, failed_flag);
@@ -494,16 +585,99 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
= std::move (result.first);
TyTy::RegionConstraints region_constraints = std::move (result.second);
+ auto specified_bound = TyTy::TypeBoundPredicate::error ();
+ TraitReference *trait_reference = &TraitReference::error_node ();
TyTy::BaseType *self = resolve_impl_block_self (impl_block);
- // resolve each impl_item
+ HIR::TypePath &ref = impl_block.get_trait_ref ();
+ trait_reference = TraitResolver::Resolve (ref);
+ if (trait_reference->is_error ())
+ return;
+
+ // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
+ // for example
+ specified_bound = get_predicate_from_bound (ref, impl_block.get_type (),
+ impl_block.get_polarity ());
+
+ // need to check that if this specified bound has super traits does this
+ // Self implement them?
+ specified_bound.validate_type_implements_super_traits (
+ *self, impl_block.get_type (), impl_block.get_trait_ref ());
+
+ std::map<DefId, AssocTypeEntry> assoc_types_by_trait_item;
+ std::vector<const TraitItemReference *> trait_item_refs;
+ ResolveImplTraitAssociatedTypes (context, impl_block, specified_bound, self,
+ substitutions, assoc_types_by_trait_item,
+ trait_item_refs);
+
+ ImplTraitContextFrame frame{trait_reference, self,
+ std::move (assoc_types_by_trait_item)};
+ ImplTraitFrameGuard guard (frame);
for (auto &impl_item : impl_block.get_impl_items ())
{
- TypeCheckImplItem::Resolve (impl_block, *impl_item, self, substitutions);
+ bool is_type_alias = impl_item->get_impl_item_type ()
+ == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
+ if (is_type_alias)
+ continue;
+
+ auto trait_item_ref
+ = TypeCheckImplItemWithTrait::Resolve (impl_block, *impl_item, self,
+ specified_bound, substitutions);
+ if (!trait_item_ref.is_error ())
+ trait_item_refs.push_back (trait_item_ref.get_raw_item ());
}
- // validate the impl items
- validate_trait_impl_block (trait_reference, impl_block, self, substitutions);
+ validate_trait_impl_block (specified_bound, trait_item_refs, trait_reference,
+ impl_block, self, substitutions);
+
+ AssociatedImplTrait associated (trait_reference, specified_bound,
&impl_block,
+ self, frame);
+ context->insert_associated_trait_impl (
+ impl_block.get_mappings ().get_hirid (), std::move (associated));
+ context->insert_associated_impl_mapping (
+ trait_reference->get_mappings ().get_hirid (), self,
+ impl_block.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckItem::ResolveImplTraitAssociatedTypes (
+ TypeCheckContext *context, HIR::ImplBlock &impl_block,
+ TyTy::TypeBoundPredicate &specified_bound, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> &substitutions,
+ std::map<DefId, AssocTypeEntry> &assoc_types_by_trait_item,
+ std::vector<const TraitItemReference *> &trait_item_refs)
+{
+ for (auto &impl_item : impl_block.get_impl_items ())
+ {
+ bool is_type_alias = impl_item->get_impl_item_type ()
+ == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
+ if (!is_type_alias)
+ continue;
+
+ rust_debug_loc (impl_item->get_locus (), "RESOLVE ITEM 1");
+ self->debug ();
+ auto trait_item_ref
+ = TypeCheckImplItemWithTrait::Resolve (impl_block, *impl_item, self,
+ specified_bound, substitutions);
+ rust_debug_loc (impl_item->get_locus (), "RESOLVE ITEM 2");
+ if (!trait_item_ref.is_error ())
+ {
+ const TraitItemReference *tiref = trait_item_ref.get_raw_item ();
+ trait_item_refs.push_back (tiref);
+
+ DefId impl_item_defid = impl_item->get_impl_mappings ().get_defid ();
+ DefId trait_item_defid = tiref->get_mappings ().get_defid ();
+ TyTy::BaseType *impl_item_ty;
+
+ bool ok = context->lookup_type (
+ impl_item->get_impl_mappings ().get_hirid (), &impl_item_ty);
+ rust_assert (ok);
+
+ AssocTypeEntry entry
+ = {trait_item_defid, impl_item_defid, impl_item_ty};
+ assoc_types_by_trait_item[trait_item_defid] = std::move (entry);
+ }
+ }
}
TyTy::BaseType *
@@ -655,6 +829,8 @@ TypeCheckItem::visit (HIR::Module &module)
void
TypeCheckItem::visit (HIR::Trait &trait)
{
+ auto lifetime_pin = context->push_clean_lifetime_resolver ();
+
if (trait.has_type_param_bounds ())
{
for (auto &tp_bound : trait.get_type_param_bounds ())
@@ -736,12 +912,14 @@ TypeCheckItem::resolve_impl_block_substitutions
(HIR::ImplBlock &impl_block,
{
auto &ref = impl_block.get_trait_ref ();
trait_reference = TraitResolver::Resolve (ref);
- rust_assert (!trait_reference->is_error ());
-
- // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
- // for example
- specified_bound = get_predicate_from_bound (ref, impl_block.get_type (),
- impl_block.get_polarity ());
+ if (!trait_reference->is_error ())
+ {
+ // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
+ // for example
+ specified_bound
+ = get_predicate_from_bound (ref, impl_block.get_type (),
+ impl_block.get_polarity ());
+ }
}
TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ());
@@ -770,109 +948,6 @@ TypeCheckItem::resolve_impl_block_substitutions
(HIR::ImplBlock &impl_block,
return {substitutions, region_constraints};
}
-void
-TypeCheckItem::validate_trait_impl_block (
- TraitReference *trait_reference, HIR::ImplBlock &impl_block,
- TyTy::BaseType *self,
- std::vector<TyTy::SubstitutionParamMapping> &substitutions)
-{
- auto specified_bound = TyTy::TypeBoundPredicate::error ();
- if (impl_block.has_trait_ref ())
- {
- auto &ref = impl_block.get_trait_ref ();
- trait_reference = TraitResolver::Resolve (ref);
- if (trait_reference->is_error ())
- return;
-
- // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
- // for example
- specified_bound = get_predicate_from_bound (ref, impl_block.get_type (),
- impl_block.get_polarity ());
-
- // need to check that if this specified bound has super traits does this
- // Self
- // implement them?
- specified_bound.validate_type_implements_super_traits (
- *self, impl_block.get_type (), impl_block.get_trait_ref ());
- }
-
- bool is_trait_impl_block = !trait_reference->is_error ();
- std::vector<const TraitItemReference *> trait_item_refs;
- for (auto &impl_item : impl_block.get_impl_items ())
- {
- if (!specified_bound.is_error ())
- {
- auto trait_item_ref
- = TypeCheckImplItemWithTrait::Resolve (impl_block, *impl_item, self,
- specified_bound,
- substitutions);
- if (!trait_item_ref.is_error ())
- trait_item_refs.push_back (trait_item_ref.get_raw_item ());
- }
- }
-
- bool impl_block_missing_trait_items
- = !specified_bound.is_error ()
- && trait_reference->size () != trait_item_refs.size ();
- if (impl_block_missing_trait_items
- && impl_block.get_polarity () == BoundPolarity::RegularBound)
- {
- // filter the missing impl_items
- std::vector<std::reference_wrapper<const TraitItemReference>>
- missing_trait_items;
- for (const auto &trait_item_ref : trait_reference->get_trait_items ())
- {
- bool found = false;
- for (auto implemented_trait_item : trait_item_refs)
- {
- std::string trait_item_name = trait_item_ref.get_identifier ();
- std::string impl_item_name
- = implemented_trait_item->get_identifier ();
- found = trait_item_name == impl_item_name;
- if (found)
- break;
- }
-
- bool is_required_trait_item = !trait_item_ref.is_optional ();
- if (!found && is_required_trait_item)
- missing_trait_items.emplace_back (trait_item_ref);
- }
-
- if (!missing_trait_items.empty ())
- {
- std::string missing_items_buf;
- rich_location r (line_table, impl_block.get_locus ());
- for (size_t i = 0; i < missing_trait_items.size (); i++)
- {
- bool has_more = (i + 1) < missing_trait_items.size ();
- const TraitItemReference &missing_trait_item
- = missing_trait_items.at (i);
- missing_items_buf += missing_trait_item.get_identifier ()
- + (has_more ? ", " : "");
- r.add_range (missing_trait_item.get_locus ());
- }
-
- rust_error_at (r, ErrorCode::E0046,
- "missing %s in implementation of trait %qs",
- missing_items_buf.c_str (),
- trait_reference->get_name ().c_str ());
- }
- }
-
- if (is_trait_impl_block)
- {
- trait_reference->clear_associated_types ();
-
- AssociatedImplTrait associated (trait_reference, specified_bound,
- &impl_block, self, context);
- context->insert_associated_trait_impl (
- impl_block.get_mappings ().get_hirid (), std::move (associated));
- context->insert_associated_impl_mapping (
- trait_reference->get_mappings ().get_hirid (), self,
- impl_block.get_mappings ().get_hirid ());
- }
-}
-
TyTy::BaseType *
TypeCheckItem::resolve_impl_block_self (HIR::ImplBlock &impl_block)
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h
b/gcc/rust/typecheck/rust-hir-type-check-item.h
index 11b50255b..1f8cddef4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -39,6 +39,17 @@ public:
HIR::ImplBlock &impl, location_t locus,
TyTy::SubstitutionArgumentMappings *infer_arguments);
+ static std::vector<TyTy::SubstitutionParamMapping>
+ ResolveImplBlockSubstitutions (HIR::ImplBlock &impl_block,
+ bool &failure_flag);
+
+ static void ResolveImplTraitAssociatedTypes (
+ TypeCheckContext *context, HIR::ImplBlock &impl_block,
+ TyTy::TypeBoundPredicate &specified_bound, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> &substitutions,
+ std::map<DefId, AssocTypeEntry> &assoc_types_by_trait_item,
+ std::vector<const TraitItemReference *> &trait_item_refs);
+
void visit (HIR::Module &module) override;
void visit (HIR::Function &function) override;
void visit (HIR::TypeAlias &alias) override;
@@ -57,12 +68,17 @@ public:
void visit (HIR::UseDeclaration &) override {}
protected:
+ void resolve_impl_block (HIR::ImplBlock &impl_block);
+ void resolve_trait_impl_block (HIR::ImplBlock &impl_block);
+
std::pair<std::vector<TyTy::SubstitutionParamMapping>,
TyTy::RegionConstraints>
resolve_impl_block_substitutions (HIR::ImplBlock &impl_block,
bool &failure_flag);
void validate_trait_impl_block (
+ const TyTy::TypeBoundPredicate &specified_bound,
+ std::vector<const TraitItemReference *> trait_item_refs,
TraitReference *trait_reference, HIR::ImplBlock &impl_block,
TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc
b/gcc/rust/typecheck/rust-hir-type-check-path.cc
index bb1f1d06f..2e13ae4dd 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-path.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -94,8 +94,6 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
= lookup_associated_impl_block (specified_bound, root);
if (associated_impl_trait != nullptr)
{
- associated_impl_trait->setup_associated_types (root, specified_bound);
-
for (auto &i :
associated_impl_trait->get_impl_block ()->get_impl_items ())
{
@@ -480,22 +478,13 @@ TypeCheckExpr::resolve_segments (NodeId
root_resolved_node_id,
if (associated_impl_block != nullptr && !receiver_is_dyn)
{
- // associated types
- HirId impl_block_id
- = associated_impl_block->get_mappings ().get_hirid ();
-
- AssociatedImplTrait *associated = nullptr;
- bool found_impl_trait
- = context->lookup_associated_trait_impl (impl_block_id,
- &associated);
-
+ // unify the segments receiver against the impls self so
+ // infer vars on either side get pinned
auto mappings = TyTy::SubstitutionArgumentMappings::error ();
TyTy::BaseType *impl_block_ty
= TypeCheckItem::ResolveImplBlockSelfWithInference (
*associated_impl_block, seg.get_locus (), &mappings);
- // we need to apply the arguments to the segment type so they get
- // unified properly
if (!mappings.is_error ())
tyseg = SubstMapperInternal::Resolve (tyseg, mappings);
@@ -503,24 +492,8 @@ TypeCheckExpr::resolve_segments (NodeId
root_resolved_node_id,
TyTy::TyWithLocation (prev_segment),
TyTy::TyWithLocation (impl_block_ty),
seg.get_locus ());
- bool ok = prev_segment->get_kind () != TyTy::TypeKind::ERROR;
- if (!ok)
+ if (prev_segment->get_kind () == TyTy::TypeKind::ERROR)
return;
-
- if (found_impl_trait)
- {
- // we need to setup with apropriate bounds
- HIR::TypePath &bound_path
- = associated->get_impl_block ()->get_trait_ref ();
- const auto &trait_ref = *TraitResolver::Resolve (bound_path);
- rust_assert (!trait_ref.is_error ());
-
- const auto &predicate
- = impl_block_ty->lookup_predicate (trait_ref.get_defid ());
- if (!predicate.is_error ())
- associated->setup_associated_types (prev_segment, predicate,
- nullptr, false);
- }
}
if (seg.has_generic_args ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index a7455eb22..634d04988 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -140,8 +140,6 @@ TypeCheckType::visit (HIR::TupleType &tuple)
void
TypeCheckType::visit (HIR::TypePath &path)
{
- rust_debug ("{ARTHUR}: Path visited: %s", path.to_string ().c_str ());
-
// this can happen so we need to look up the root then resolve the
// remaining segments if possible
bool wasBigSelf = false;
@@ -171,6 +169,11 @@ TypeCheckType::visit (HIR::TypePath &path)
offset, path_type, path.get_mappings (),
path.get_locus (), wasBigSelf);
+ if (auto p = translated->try_as<TyTy::ProjectionType> ())
+ translated
+ = normalize_projection (p, path.get_locus (), false /*emit errors*/,
+ false /*unify self*/);
+
rust_debug_loc (path.get_locus (), "resolved type-path to: [%s]",
translated->debug_str ().c_str ());
}
@@ -234,57 +237,17 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
return;
}
- // we try to look for the real impl item if possible
- TyTy::SubstitutionArgumentMappings args
- = TyTy::SubstitutionArgumentMappings::error ();
- HIR::ImplItem *impl_item = nullptr;
- if (root->is_concrete ())
- {
- // lookup the associated impl trait for this if we can (it might be
- // generic)
- AssociatedImplTrait *associated_impl_trait
- = lookup_associated_impl_block (specified_bound, root);
- if (associated_impl_trait != nullptr)
- {
- associated_impl_trait->setup_associated_types (root, specified_bound,
- &args);
-
- for (auto &i :
- associated_impl_trait->get_impl_block ()->get_impl_items ())
- {
- bool found = i->get_impl_item_name ().compare (
- item_seg_identifier.to_string ())
- == 0;
- if (found)
- {
- impl_item = i.get ();
- break;
- }
- }
- }
- }
-
- if (impl_item == nullptr)
- {
- // this may be valid as there could be a default trait implementation
here
- // and we dont need to worry if the trait item is actually implemented or
- // not because this will have already been validated as part of the trait
- // impl block
- translated = item->get_tyty_for_receiver (root);
- }
+ // Build projection via the predicates own rebasing helper so the
+ // projection's substitutions are populated with the trait-coord args from
+ // the qualified path:
+ // (<Bar<i32> as Foo<i32>>::A -> Projection Self=Bar<i32>, T=i32)
+ TyTy::BaseType *rebased_item = item->get_tyty_for_receiver (root);
+ if (auto *proj = rebased_item->try_as<TyTy::ProjectionType> ())
+ translated
+ = normalize_projection (proj, path.get_locus (), false /*emit errors*/,
+ false /*unify self*/);
else
- {
- HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid ();
- bool ok = query_type (impl_item_id, &translated);
- if (!ok)
- return;
-
- if (!args.is_error ())
- {
- // apply the args
- translated = SubstMapperInternal::Resolve (translated, args);
- }
- }
+ translated = rebased_item;
// turbo-fish segment path::<ty>
if (item_seg.get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
@@ -308,6 +271,11 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
&generic_seg.get_generic_args (),
context->regions_from_generic_args (
generic_seg.get_generic_args ()));
+
+ // unwrap the sweets
+ if (auto *proj = translated->try_as<TyTy::ProjectionType> ())
+ if (!proj->is_trait_position () && proj->get () != nullptr)
+ translated = proj->get ();
}
}
@@ -588,7 +556,6 @@ TypeCheckType::resolve_segments (
ignore_mandatory_trait_items);
if (candidates.size () == 0)
{
- prev_segment->debug ();
rust_error_at (
seg->get_locus (),
"failed to resolve path segment using an impl Probe");
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h
b/gcc/rust/typecheck/rust-hir-type-check.h
index 38dbfa62c..916ee2f2d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -22,6 +22,7 @@
#include "rust-hir-map.h"
#include "rust-mapping-common.h"
#include "rust-tyty.h"
+#include "rust-hir-impl-trait-context.h"
#include "rust-hir-trait-reference.h"
#include "rust-stacked-contexts.h"
#include "rust-autoderef.h"
@@ -236,6 +237,14 @@ public:
void swap_head_loop_context (TyTy::BaseType *val);
+ bool
+ find_matching_impl_trait_frame (const TraitReference &tref,
+ struct ImplTraitContextFrame *find) const;
+ bool have_impl_trait_context () const;
+ void push_impl_trait_context (struct ImplTraitContextFrame frame);
+ struct ImplTraitContextFrame pop_impl_trait_context ();
+ struct ImplTraitContextFrame peek_impl_trait_context ();
+
void insert_trait_reference (DefId id, TraitReference &&ref);
bool lookup_trait_reference (DefId id, TraitReference **ref);
@@ -328,6 +337,7 @@ private:
StackedContexts<TypeCheckBlockContextItem> block_stack;
std::map<DefId, TraitReference> trait_context;
std::map<HirId, AssociatedImplTrait> associated_impl_traits;
+ std::vector<ImplTraitContextFrame> impl_trait_frame_stack;
// trait-id -> list of < self-tyty:impl-id>
std::map<HirId, std::vector<std::pair<TyTy::BaseType *, HirId>>>
@@ -563,6 +573,47 @@ private:
TypeCheckContext &ctx;
};
+template <typename T> class ScopedPush
+{
+public:
+ ScopedPush (std::vector<T> &stack, T value, bool enabled = true)
+ : stack (stack), enabled (enabled)
+ {
+ if (enabled)
+ stack.push_back (value);
+ }
+
+ ~ScopedPush ()
+ {
+ if (enabled)
+ stack.pop_back ();
+ }
+
+ static bool contains (const std::vector<T> &stack, const T &value)
+ {
+ return std::find (stack.begin (), stack.end (), value) != stack.end ();
+ }
+
+private:
+ std::vector<T> &stack;
+ bool enabled;
+};
+
+class ImplTraitFrameGuard
+{
+public:
+ ImplTraitFrameGuard (ImplTraitContextFrame frame)
+ : ctx (*TypeCheckContext::get ())
+ {
+ ctx.push_impl_trait_context (frame);
+ }
+
+ ~ImplTraitFrameGuard () { ctx.pop_impl_trait_context (); }
+
+private:
+ Resolver::TypeCheckContext &ctx;
+};
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-type-util.cc
b/gcc/rust/typecheck/rust-type-util.cc
index 76451c771..5fcea2c8b 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -16,25 +16,28 @@
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#include "rust-system.h"
#include "rust-type-util.h"
#include "rust-diagnostics.h"
#include "rust-hir-map.h"
#include "rust-hir-type-check-implitem.h"
#include "rust-hir-type-check-item.h"
#include "rust-hir-type-check.h"
-#include "rust-hir-type-check-type.h"
#include "rust-casts.h"
#include "rust-mapping-common.h"
#include "rust-rib.h"
#include "rust-unify.h"
#include "rust-coercion.h"
#include "rust-hir-type-bounds.h"
+#include "rust-hir-trait-resolve.h"
+#include "rust-substitution-mapper.h"
#include "rust-finalized-name-resolution-context.h"
-#include "options.h"
namespace Rust {
namespace Resolver {
+const size_t kNormalizeProjectionLimit = 10;
+
bool
query_type (HirId reference, TyTy::BaseType **result)
{
@@ -80,6 +83,51 @@ query_type (HirId reference, TyTy::BaseType **result)
auto impl_block
= mappings.lookup_hir_impl_block (impl_item->second).value ();
+ tl::optional<ImplTraitFrameGuard> guard;
+ if (impl_block->has_trait_ref ())
+ {
+ bool failure_flag = false;
+ auto substitutions
+ = TypeCheckItem::ResolveImplBlockSubstitutions (*impl_block,
+ failure_flag);
+ if (failure_flag)
+ {
+ context->query_completed (reference);
+ return false;
+ }
+
+ TyTy::BaseType *self = nullptr;
+ bool ok
+ = query_type (impl_block->get_type ().get_mappings ().get_hirid (),
+ &self);
+ if (!ok)
+ {
+ context->query_completed (reference);
+ return false;
+ }
+
+ HIR::TypePath &ref = impl_block->get_trait_ref ();
+ auto trait_reference = TraitResolver::Resolve (ref);
+ if (trait_reference->is_error ())
+ {
+ context->query_completed (reference);
+ return false;
+ }
+
+ auto specified_bound = TypeCheckBase::ResolvePredicateFromBound (
+ ref, impl_block->get_type (), impl_block->get_polarity ());
+
+ std::map<DefId, AssocTypeEntry> assoc_types_by_trait_item;
+ std::vector<const TraitItemReference *> trait_item_refs;
+ TypeCheckItem::ResolveImplTraitAssociatedTypes (
+ context, *impl_block, specified_bound, self, substitutions,
+ assoc_types_by_trait_item, trait_item_refs);
+
+ ImplTraitContextFrame frame{trait_reference, self,
+ std::move (assoc_types_by_trait_item)};
+ guard.emplace (frame);
+ }
+
// found an impl item
rust_debug_loc (impl_item->first->get_locus (),
"resolved impl-item {%u} to", reference);
@@ -433,5 +481,336 @@ lookup_associated_impl_block (const
TyTy::TypeBoundPredicate &bound,
return associate_impl_trait;
}
+void
+rebind_projection_self_from_fn (TyTy::FnType &fn, TyTy::BaseType *root)
+{
+ // After substitution+monomorphize the fn's substitution clones carry the
+ // call-site bindings. Inner projections in the return/params can still
+ // reference the traits formal Self via TyVar(formal.ref) whose type table
+ // entry resolves to the unbound formal
+ std::map<HirId, TyTy::BaseGeneric *> bound_by_formal;
+ for (auto &sub : fn.get_substs ())
+ {
+ auto *pty = sub.get_param_ty ();
+ if (pty == nullptr || pty->get_kind () != TyTy::TypeKind::PARAM
+ || !pty->can_resolve ())
+ continue;
+ bound_by_formal[pty->get_ref ()] = pty;
+ }
+
+ std::function<void (TyTy::BaseType *)> rebind;
+ rebind = [&] (TyTy::BaseType *ty) {
+ if (ty == nullptr)
+ return;
+
+ if (auto *proj = ty->try_as<TyTy::ProjectionType> ())
+ {
+ auto *self = proj->get_self ();
+ if (self->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ auto it = bound_by_formal.find (self->get_ref ());
+ if (it != bound_by_formal.end ())
+ proj->set_self (it->second);
+ }
+
+ for (auto &sub : proj->get_substs ())
+ {
+ auto *param = sub.get_param_ty ();
+ if (param == nullptr || param->get_kind () != TyTy::TypeKind::PARAM
+ || param->can_resolve ())
+ continue;
+
+ auto it = bound_by_formal.find (param->get_ref ());
+ if (it == bound_by_formal.end ()
+ || it->second->get_kind () != TyTy::TypeKind::PARAM)
+ continue;
+
+ auto *bound = static_cast<TyTy::ParamType *> (it->second);
+ if (bound->can_resolve ())
+ param->set_ty_ref (bound->get_ty_ref ());
+ }
+ return;
+ }
+
+ if (auto *adt = ty->try_as<TyTy::ADTType> ())
+ {
+ for (auto &variant : adt->get_variants ())
+ for (auto &field : variant->get_fields ())
+ rebind (field->get_field_type ());
+ return;
+ }
+
+ if (auto *ref = ty->try_as<TyTy::ReferenceType> ())
+ rebind (ref->get_base ());
+ else if (auto *ptr = ty->try_as<TyTy::PointerType> ())
+ rebind (ptr->get_base ());
+ else if (auto *tup = ty->try_as<TyTy::TupleType> ())
+ for (size_t i = 0; i < tup->num_fields (); i++)
+ rebind (tup->get_field (i));
+ };
+
+ rebind (root);
+}
+
+TyTy::BaseType *
+normalize_projection (TyTy::ProjectionType *proj, location_t locus,
+ bool emit_errors, bool unify_self)
+{
+ static std::vector<TyTy::ProjectionType *> active_projections;
+ if (ScopedPush<TyTy::ProjectionType *>::contains (active_projections, proj))
+ return proj;
+
+ ScopedPush<TyTy::ProjectionType *> guard (active_projections, proj);
+
+ if (!proj->is_trait_position ())
+ return proj->get ();
+
+ // special case the discriminant_type lang item
+ auto &mappings = Analysis::Mappings::get ();
+ auto *ctx = TypeCheckContext::get ();
+ if (auto discriminant_type_id
+ = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE))
+ {
+ if (proj->get_item_defid () == discriminant_type_id.value ())
+ {
+ TyTy::BaseType *isize_ty = nullptr;
+ bool ok = ctx->lookup_builtin ("isize", &isize_ty);
+ rust_assert (ok);
+
+ // If the self type is a concrete ADT, use its repr.
+ TyTy::BaseType *self = proj->get_self ()->destructure ();
+ if (auto *adt = self->try_as<TyTy::ADTType> ())
+ {
+ auto *repr = adt->get_repr_options ().repr;
+ if (repr != nullptr)
+ return repr;
+ }
+ return isize_ty;
+ }
+ }
+
+ ImplTraitContextFrame frame;
+ if (!ctx->find_matching_impl_trait_frame (*proj->get_trait_ref (), &frame))
+ {
+ // No concrete impl frame check WHERE clause bindings on the self type
+ //
+ // fn foo<T: Trait<AssocType = X>>()
+ //
+ // normalizes
+ //
+ // <T as Trait>::AssocType -> X.
+
+ TyTy::BaseType *self = proj->get_self ()->destructure ();
+ const DefId item_defid = proj->get_item_defid ();
+
+ // find the name of the associated type from the trait reference
+ std::string assoc_name;
+ for (const auto &ti : proj->get_trait_ref ()->get_trait_items ())
+ {
+ if (ti.get_mappings ().get_defid () == item_defid)
+ {
+ assoc_name = ti.get_identifier ();
+ break;
+ }
+ }
+
+ if (!assoc_name.empty ())
+ {
+ for (auto &bound : self->get_specified_bounds ())
+ {
+ if (!bound.get ()->is_equal (*proj->get_trait_ref ()))
+ continue;
+
+ auto &binding
+ = bound.get_substitution_arguments ().get_binding_args ();
+ auto it = binding.find (assoc_name);
+ if (it != binding.end ())
+ return it->second;
+ }
+ }
+
+ // If self is a trait-position projection recursively normalize it first
+ // so the impl-block lookup below works on a concrete type.
+ if (auto *self_proj = self->try_as<TyTy::ProjectionType> ())
+ {
+ if (self_proj->is_trait_position ())
+ {
+ auto *norm = normalize_projection (self_proj, locus, emit_errors,
+ unify_self);
+ if (norm != self_proj
+ && norm->get_kind () != TyTy::TypeKind::ERROR)
+ self = norm->destructure ();
+ }
+ else
+ {
+ auto *base = self_proj->get ();
+ if (base && base != self_proj)
+ self = base->destructure ();
+ }
+ }
+
+ // Direct impl-block lookup for concrete self types (no active frame).
+ if (!assoc_name.empty () && self->get_kind () != TyTy::TypeKind::PARAM
+ && self->get_kind () != TyTy::TypeKind::INFER
+ && self->get_kind () != TyTy::TypeKind::PROJECTION)
+ {
+ auto candidates = TypeBoundsProbe::Probe (self);
+ for (auto &probed : candidates)
+ {
+ HIR::ImplBlock *impl_block = probed.second;
+ if (!impl_block->has_trait_ref ())
+ continue;
+
+ HIR::TypePath &ref = impl_block->get_trait_ref ();
+ auto *tref = TraitResolver::Resolve (ref);
+ if (tref->is_error ()
+ || !tref->is_equal (*proj->get_trait_ref ()))
+ continue;
+
+ for (auto &impl_item : impl_block->get_impl_items ())
+ {
+ if (impl_item->get_impl_item_name ().compare (assoc_name)
+ != 0)
+ continue;
+
+ TyTy::BaseType *result = nullptr;
+ if (query_type (impl_item->get_impl_mappings ().get_hirid (),
+ &result))
+ {
+ AssociatedImplTrait *associated = nullptr;
+ if (ctx->lookup_associated_trait_impl (
+ impl_block->get_mappings ().get_hirid (),
+ &associated)
+ && associated != nullptr)
+ {
+ auto mapping
+ = associated->bind_impl_for_projection (*proj,
+ locus);
+ if (!mapping.is_error ())
+ result
+ = SubstMapperInternal::Resolve (result, mapping);
+ }
+
+ // impl type aliases are stored as non-trait-position
+ // ProjectionType; unwrap to base only when there are no
+ // substitution params (non-GAT)
+ if (auto *p = result->try_as<TyTy::ProjectionType> ())
+ {
+ if (!p->is_trait_position ())
+ {
+ bool all_substs_bound = true;
+ for (auto &s : p->get_substs ())
+ {
+ auto *sp = s.get_param_ty ();
+ if (sp == nullptr || !sp->can_resolve ()
+ || sp->resolve ()->get_kind ()
+ == TyTy::TypeKind::PARAM)
+ {
+ all_substs_bound = false;
+ break;
+ }
+ }
+
+ // Also unwrap when the base is already concrete
+ bool base_is_concrete
+ = p->get () != nullptr
+ && p->get ()->is_concrete ();
+ if (!p->has_substitutions () || all_substs_bound
+ || base_is_concrete)
+ result = p->get ();
+ }
+ }
+
+ return result;
+ }
+ break;
+ }
+ }
+ }
+
+ // special-case FnOnce::Output
+ if (proj->is_trait_position ())
+ {
+ auto fn_once_lookup
+ = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE);
+ auto fn_once_output_lookup
+ = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE_OUTPUT);
+ if (!fn_once_lookup || !fn_once_output_lookup)
+ return proj;
+
+ DefId &fn_once_trait_id = fn_once_lookup.value ();
+ DefId &fn_once_output_id = fn_once_output_lookup.value ();
+ DefId proj_trait_id = proj->get_trait_ref ()->get_defid ();
+ DefId proj_trait_item_id = proj->get_item_defid ();
+
+ if (proj_trait_id == fn_once_trait_id
+ && proj_trait_item_id == fn_once_output_id)
+ {
+ auto pself = proj->get_self ();
+ if (auto closure = pself->try_as<TyTy::ClosureType> ())
+ return &closure->get_result_type ();
+ }
+ }
+
+ return proj;
+ }
+
+ if (unify_self)
+ {
+ TyTy::BaseType *proj_self = proj->get_self ();
+ TyTy::BaseType *impl_self = frame.self;
+ TyTy::BaseType *self
+ = unify_site_and (/*id*/ 0, TyTy::TyWithLocation (proj_self, locus),
+ TyTy::TyWithLocation (impl_self, locus), locus,
+ /*emit_errors*/ false,
+ /*commit*/ false,
+ /*infer*/ false,
+ /*cleanup*/ true,
+ /*check_bounds*/ false);
+
+ if (self->get_kind () == TyTy::TypeKind::ERROR)
+ return self;
+ }
+
+ // Lookup the trait item -> impl type mapping (key = trait item DefId).
+ const DefId item = proj->get_item_defid ();
+ auto it = frame.assoc_types_by_trait_item.find (item);
+ if (it == frame.assoc_types_by_trait_item.end ())
+ {
+ return proj;
+ }
+
+ auto &entry = it->second;
+ auto impl_value = entry.value;
+
+ // chase the impl body through any further projections it contains
+ TyTy::BaseType *normalized = impl_value;
+ for (size_t i = 0; i < kNormalizeProjectionLimit; i++)
+ {
+ if (!normalized->is<TyTy::ProjectionType> ())
+ break;
+
+ auto p = normalized->as<TyTy::ProjectionType> ();
+ if (p->is_trait_position ())
+ {
+ auto *n = normalize_projection (p, locus, emit_errors, unify_self);
+ if (n == p)
+ break;
+
+ normalized = n;
+ }
+ else
+ {
+ auto *v = p->get ();
+ if (v == nullptr || v == p)
+ break;
+
+ normalized = v;
+ }
+ }
+
+ return normalized;
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-type-util.h
b/gcc/rust/typecheck/rust-type-util.h
index e58b086e4..860f23cfc 100644
--- a/gcc/rust/typecheck/rust-type-util.h
+++ b/gcc/rust/typecheck/rust-type-util.h
@@ -56,6 +56,12 @@ lookup_associated_impl_block (const TyTy::TypeBoundPredicate
&bound,
TyTy::BaseType *binding,
bool *ambigious = nullptr);
+TyTy::BaseType *normalize_projection (TyTy::ProjectionType *proj,
+ location_t locus, bool emit_errors,
+ bool unify_self);
+
+void rebind_projection_self_from_fn (TyTy::FnType &fn, TyTy::BaseType *root);
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc
b/gcc/rust/typecheck/rust-typecheck-context.cc
index fa7d5efe5..5b482dd9f 100644
--- a/gcc/rust/typecheck/rust-typecheck-context.cc
+++ b/gcc/rust/typecheck/rust-typecheck-context.cc
@@ -251,6 +251,53 @@ TypeCheckContext::swap_head_loop_context (TyTy::BaseType
*val)
loop_type_stack.push_back (val);
}
+bool
+TypeCheckContext::find_matching_impl_trait_frame (
+ const TraitReference &tref, struct ImplTraitContextFrame *find) const
+{
+ if (!have_impl_trait_context ())
+ return false;
+
+ for (auto it = impl_trait_frame_stack.rbegin ();
+ it != impl_trait_frame_stack.rend (); ++it)
+ {
+ const auto &i = *it;
+ if (i.trait->is_equal (tref))
+ {
+ *find = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+TypeCheckContext::have_impl_trait_context () const
+{
+ return !impl_trait_frame_stack.empty ();
+}
+
+void
+TypeCheckContext::push_impl_trait_context (struct ImplTraitContextFrame frame)
+{
+ impl_trait_frame_stack.push_back (frame);
+}
+
+struct ImplTraitContextFrame
+TypeCheckContext::pop_impl_trait_context ()
+{
+ auto back = peek_impl_trait_context ();
+ impl_trait_frame_stack.pop_back ();
+ return back;
+}
+
+struct ImplTraitContextFrame
+TypeCheckContext::peek_impl_trait_context ()
+{
+ return impl_trait_frame_stack.back ();
+}
+
void
TypeCheckContext::insert_trait_reference (DefId id, TraitReference &&ref)
{
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 79798c7b2..5ec3f0b40 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -567,22 +567,8 @@ TypeBoundPredicate::apply_argument_mappings (
substs_need_bounds_check);
}
- // associated argument mappings
- for (auto &it : subst_mappings.get_binding_args ())
- {
- std::string identifier = it.first;
- TyTy::BaseType *type = it.second;
-
- tl::optional<TypeBoundPredicateItem> item
- = lookup_associated_item (identifier);
-
- if (!item.has_value ())
- continue;
-
- const auto item_ref = item->get_raw_item ();
- item_ref->associated_type_set (type);
- }
-
+ // Associated type binding args (Iterator<Item = i32>) are consumed
+ // by BaseType::satisfies_bound at check time
for (auto &super_trait : super_traits)
{
auto adjusted
@@ -667,20 +653,31 @@ TypeBoundPredicate::lookup_associated_item (
BaseType *
TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
{
+ auto ctx = Resolver::TypeCheckContext::get ();
+
TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
if (parent.get_substitution_arguments ().is_empty ())
return trait_item_tyty;
- const Resolver::TraitItemReference *tref = get_raw_item ();
- bool is_associated_type = tref->get_trait_item_type ();
- if (is_associated_type)
- return trait_item_tyty;
-
// set up the self mapping
SubstitutionArgumentMappings gargs = parent.get_substitution_arguments ();
rust_assert (!gargs.is_empty ());
- // setup the adjusted mappings
+ // The associated-type projection we are rebasing is stored in trait
+ // coordinates
+ //
+ // Self/X for trait SliceIndex<X>
+ //
+ // The predicate's own SubstitutionParamMappings may have already been
+ // mutated by SubstitutionParamMapping::fill_param_ty when the bound is a
+ // where-clause like I: SliceIndex<[T]>: substituting Self with the
+ // ParamType I rebinds the predicate's first param from Self to I.
+ // Building adjusted_mappings from those renamed mappings would make
+ // name-based lookup (get_argument_for_symbol) miss the trait's Self/X
+ // symbols inside the projection.
+ const auto &trait_substs = parent.get ()->get_trait_substs ();
+ rust_assert (gargs.get_mappings ().size () <= trait_substs.size ());
+
std::vector<SubstitutionArg> adjusted_mappings;
for (size_t i = 0; i < gargs.get_mappings ().size (); i++)
{
@@ -690,7 +687,7 @@ TypeBoundPredicateItem::get_tyty_for_receiver (const
TyTy::BaseType *receiver)
TyTy::BaseType *argument
= is_implicit_self ? receiver->clone () : mapping.get_tyty ();
- adjusted_mappings.emplace_back (mapping.get_param_mapping (), argument);
+ adjusted_mappings.emplace_back (&trait_substs.at (i), argument);
}
SubstitutionArgumentMappings adjusted (adjusted_mappings, {},
@@ -698,7 +695,19 @@ TypeBoundPredicateItem::get_tyty_for_receiver (const
TyTy::BaseType *receiver)
gargs.get_locus (),
gargs.get_subst_cb (),
true /* trait-mode-flag */);
- return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
+ TyTy::BaseType *res
+ = Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
+
+ if (res != trait_item_tyty)
+ {
+ auto &mappings = Analysis::Mappings::get ();
+ HirId fresh = mappings.get_next_hir_id ();
+ res->set_ref (fresh);
+ res->set_ty_ref (fresh);
+ ctx->insert_implicit_type (fresh, res);
+ }
+
+ return res;
}
bool
TypeBoundPredicate::is_error () const
@@ -727,21 +736,6 @@ TypeBoundPredicate::handle_substitions (
p->set_ty_ref (s->get_ty_ref ());
}
- // associated argument mappings
- for (auto &it : subst_mappings.get_binding_args ())
- {
- std::string identifier = it.first;
- TyTy::BaseType *type = it.second;
-
- tl::optional<TypeBoundPredicateItem> item
- = lookup_associated_item (identifier);
- if (item.has_value ())
- {
- const auto item_ref = item->get_raw_item ();
- item_ref->associated_type_set (type);
- }
- }
-
// FIXME more error handling at some point
// used_arguments = subst_mappings;
// error_flag |= used_arguments.is_error ();
diff --git a/gcc/rust/typecheck/rust-tyty-call.cc
b/gcc/rust/typecheck/rust-tyty-call.cc
index 0b8d424d6..5a2b105e2 100644
--- a/gcc/rust/typecheck/rust-tyty-call.cc
+++ b/gcc/rust/typecheck/rust-tyty-call.cc
@@ -140,6 +140,7 @@ TypeCheckCallExpr::visit (FnType &type)
// with the fn's return type before checking arguments. This lets the callee
// result constrain inference variables that may appear in parameter
// projections.
+
auto *ctx = Resolver::TypeCheckContext::get ();
TyTy::BaseType *expected = ctx->peek_expected_type ();
const TyTy::BaseType *return_infer
@@ -278,7 +279,9 @@ TypeCheckCallExpr::visit (FnType &type)
}
type.monomorphize ();
- resolved = type.get_return_type ()->monomorphized_clone ();
+ Resolver::rebind_projection_self_from_fn (type, type.get_return_type ());
+
+ resolved = type.get_return_type ();
}
void
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc
b/gcc/rust/typecheck/rust-tyty-subst.cc
index 6ee2a60df..46e22288c 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -156,6 +156,35 @@ SubstitutionParamMapping::fill_param_ty (
return true;
TyTy::BaseType &type = *arg.get_tyty ();
+ std::pair<HirId, HirId> subst_key (param->get_ref (), type.get_ref ());
+ static std::vector<std::pair<HirId, HirId>> active_substs;
+ bool is_recursive_subst
+ = Resolver::ScopedPush<std::pair<HirId, HirId>>::contains (active_substs,
+ subst_key);
+ bool skip_recursive_bounds
+ = is_recursive_subst && type.get_kind () == TyTy::TypeKind::INFER;
+ if (skip_recursive_bounds)
+ {
+ type.append_reference (param->get_ref ());
+ type.append_reference (param->get_ty_ref ());
+ for (auto ref : param->get_combined_refs ())
+ type.append_reference (ref);
+ if (param->can_resolve ())
+ {
+ TyTy::BaseType *resolved = param->resolve ();
+ type.append_reference (resolved->get_ref ());
+ type.append_reference (resolved->get_ty_ref ());
+ for (auto ref : resolved->get_combined_refs ())
+ type.append_reference (ref);
+ if (resolved->get_kind () != TyTy::TypeKind::PARAM
+ && resolved->get_kind () != TyTy::TypeKind::INFER)
+ return true;
+ }
+ }
+
+ Resolver::ScopedPush<std::pair<HirId, HirId>> guard (active_substs,
subst_key,
+ !is_recursive_subst);
+
if (type.get_kind () == TyTy::TypeKind::INFER)
{
type.inherit_bounds (*param);
@@ -182,15 +211,17 @@ SubstitutionParamMapping::fill_param_ty (
rust_debug_loc (locus,
"fill_param_ty bounds_compatible: param %s type %s",
param->get_name ().c_str (), type.get_name ().c_str ());
- if (needs_bounds_check && !p.is_implicit_self_trait ())
+ if (!skip_recursive_bounds && needs_bounds_check
+ && !p.is_implicit_self_trait ())
{
if (!param->bounds_compatible (type, locus, true))
return false;
}
// recursively pass this down to all HRTB's
- for (auto &bound : param->get_specified_bounds ())
- bound.handle_substitions (subst_mappings);
+ if (!skip_recursive_bounds)
+ for (auto &bound : param->get_specified_bounds ())
+ bound.handle_substitions (subst_mappings);
param->set_ty_ref (type.get_ref ());
subst_mappings.on_param_subst (p, arg);
@@ -712,7 +743,8 @@ SubstitutionRef::get_mappings_from_generic_args (
= args.get_type_args ().size () + args.get_const_args ().size ();
if (total_arguments < substitutions.size ())
{
- offs = used_arguments.size ();
+ offs = used_arguments.get_mappings ().empty () ? get_outer_param_count ()
+ : used_arguments.size ();
total_arguments += offs;
}
@@ -1072,20 +1104,6 @@ SubstitutionRef::solve_mappings_from_receiver_for_self (
mappings.get_locus ());
}
-void
-SubstitutionRef::prepare_higher_ranked_bounds ()
-{
- for (const auto &subst : get_substs ())
- {
- const auto pty = subst.get_param_ty ();
- for (const auto &bound : pty->get_specified_bounds ())
- {
- const auto ref = bound.get ();
- ref->clear_associated_type_projections ();
- }
- }
-}
-
bool
SubstitutionRef::monomorphize ()
{
@@ -1099,6 +1117,19 @@ SubstitutionRef::monomorphize ()
if (binding->get_kind () == TyTy::TypeKind::PARAM)
continue;
+ // For each where-clause bound on this fn-substitution param, find the
+ // impl block that satisfies the bound for binding and unify
+ // its signature against binding + bound. This pins inference
+ // variables that should be constrained
+ //
+ // fn into_iter<I: Iterator> with binding = Range<{integer}>
+ //
+ // the only matching
+ //
+ // <A: Step> Iterator for Range<A>
+ //
+ // Step for usize impl together force {integer} = usize instead of
+ // letting it default.
for (const auto &bound : pty->get_specified_bounds ())
{
bool ambigious = false;
@@ -1106,7 +1137,7 @@ SubstitutionRef::monomorphize ()
= Resolver::lookup_associated_impl_block (bound, binding,
&ambigious);
if (associated != nullptr)
- associated->setup_associated_types (binding, bound);
+ associated->bind_impl_for_bound (binding, bound, UNKNOWN_LOCATION);
}
}
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h
b/gcc/rust/typecheck/rust-tyty-subst.h
index a78891788..8a71f8907 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -274,6 +274,11 @@ public:
// construct which supports associated types
virtual size_t get_num_associated_bindings () const;
+ // Number of substitution params inherited from an outer scope (e.g. trait
+ // params inherited by a GAT). These are not supplied by the user when
writing
+ // angle-bracket args and are skipped during arity checking.
+ virtual size_t get_outer_param_count () const { return 0; }
+
// this is overridden in TypeBoundPredicate
virtual TypeBoundPredicateItem
lookup_associated_type (const std::string &search);
@@ -398,10 +403,6 @@ public:
// parameters X and Y
BaseType *infer_substitions (location_t locus);
- // this clears any possible projections from higher ranked trait bounds which
- // could be hanging around from a previous resolution
- void prepare_higher_ranked_bounds ();
-
// FIXME
// this is bad name for this, i think it should be something like
// compute-higher-ranked-bounds
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 69ee43c27..144cca0e9 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -27,6 +27,7 @@
#include "rust-substitution-mapper.h"
#include "rust-hir-trait-reference.h"
#include "rust-hir-trait-resolve.h"
+#include "rust-hir-type-check.h"
#include "tree-pretty-print.h"
#include "optional.h"
@@ -337,12 +338,6 @@ BaseType::satisfies_bound (const TypeBoundPredicate
&predicate, bool emit_error)
if (!is_associated_type)
continue;
- TyTy::BaseType *impl_item_ty = nullptr;
- Analysis::NodeMapping i = item->get_impl_mappings ();
- bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty);
- if (!query_ok)
- return false;
-
std::string item_name = item->get_impl_item_name ();
tl::optional<TypeBoundPredicateItem> lookup
= predicate.lookup_associated_item (item_name);
@@ -351,6 +346,32 @@ BaseType::satisfies_bound (const TypeBoundPredicate
&predicate, bool emit_error)
const auto *item_ref = lookup->get_raw_item ();
TyTy::BaseType *bound_ty = item_ref->get_tyty ();
+ const auto &bindings
+ = predicate.get_substitution_arguments ().get_binding_args ();
+ auto bind_it = bindings.find (item_name);
+ if (bind_it != bindings.end ())
+ bound_ty = bind_it->second;
+ else if (auto *proj = bound_ty->try_as<TyTy::ProjectionType> ())
+ if (proj->is_trait_position ())
+ continue;
+
+ TyTy::BaseType *impl_item_ty = nullptr;
+ Analysis::NodeMapping i = item->get_impl_mappings ();
+ bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty);
+ if (!query_ok)
+ return false;
+
+ // If the impl alias still depends on the impl's own generics
+ // defer the binding check to monomorphization.
+ //
+ // The receiver-vs-impl substitution that pins T = i32 only
+ // happens with a committing unification at the call site
+ bool impl_item_concrete = impl_item_ty->is_concrete ();
+ if (auto *p = impl_item_ty->try_as<TyTy::ProjectionType> ())
+ if (!p->is_trait_position () && p->get () != nullptr)
+ impl_item_concrete = p->get ()->is_concrete ();
+ if (!impl_item_concrete)
+ continue;
if (!Resolver::types_compatable (
TyTy::TyWithLocation (bound_ty, predicate.get_locus ()),
@@ -496,10 +517,6 @@ BaseType::destructure ()
x = p->resolve ();
}
- else if (auto p = x->try_as<ProjectionType> ())
- {
- x = p->get ();
- }
else
{
return x;
@@ -558,10 +575,6 @@ BaseType::destructure () const
x = p->resolve ();
}
- else if (auto p = x->try_as<const ProjectionType> ())
- {
- x = p->get ();
- }
else if (auto p = x->try_as<const OpaqueType> ())
{
auto pr = p->resolve ();
@@ -659,6 +672,13 @@ BaseType::monomorphized_clone () const
adt->get_region_constraints (),
adt->get_combined_refs ());
}
+ else if (auto proj = x->try_as<const ProjectionType> ())
+ {
+ TyTy::ProjectionType *xx
+ = static_cast<TyTy::ProjectionType *> (proj->clone ());
+ return Resolver::normalize_projection (xx, UNKNOWN_LOCATION /*FIXME*/,
+ false, true);
+ }
else
{
return x->clone ();
@@ -787,7 +807,7 @@ BaseType::is_concrete () const
{
const TyTy::BaseType *x = destructure ();
- if (x->is<ParamType> () || x->is<ProjectionType> ())
+ if (x->is<ParamType> ())
{
return false;
}
@@ -799,6 +819,11 @@ BaseType::is_concrete () const
return true;
}
+ else if (x->is<ProjectionType> ())
+ {
+ const auto p = x->as<const TyTy::ProjectionType> ();
+ return p->get_self ()->is_concrete ();
+ }
// placeholder is a special case for this case when it is not resolvable
// it means we its just an empty placeholder associated type which is
// concrete
@@ -2443,56 +2468,6 @@ ClosureType::handle_substitions
(SubstitutionArgumentMappings &mappings)
return nullptr;
}
-void
-ClosureType::setup_fn_once_output () const
-{
- // lookup the lang items
- auto fn_once_lookup = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE);
- auto fn_once_output_lookup
- = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE_OUTPUT);
- if (!fn_once_lookup)
- {
- rust_fatal_error (UNKNOWN_LOCATION,
- "Missing required %<fn_once%> lang item");
- return;
- }
- if (!fn_once_output_lookup)
- {
- rust_fatal_error (UNKNOWN_LOCATION,
- "Missing required %<fn_once_ouput%> lang item");
- return;
- }
-
- DefId &trait_id = fn_once_lookup.value ();
- DefId &trait_item_id = fn_once_output_lookup.value ();
-
- // resolve to the trait
- HIR::Item *item = mappings.lookup_defid (trait_id).value ();
- rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
- HIR::Trait *trait = static_cast<HIR::Trait *> (item);
-
- Resolver::TraitReference *trait_ref
- = Resolver::TraitResolver::Resolve (*trait);
- rust_assert (!trait_ref->is_error ());
-
- // resolve to trait item
- HIR::TraitItem *trait_item
- = mappings.lookup_trait_item_defid (trait_item_id).value ();
- rust_assert (trait_item->get_item_kind ()
- == HIR::TraitItem::TraitItemKind::TYPE);
- std::string item_identifier = trait_item->trait_identifier ();
-
- // setup associated types #[lang = "fn_once_output"]
- Resolver::TraitItemReference *item_reference = nullptr;
- bool found = trait_ref->lookup_trait_item_by_type (
- item_identifier, Resolver::TraitItemReference::TraitItemType::TYPE,
- &item_reference);
- rust_assert (found);
-
- // setup
- item_reference->associated_type_set (&get_result_type ());
-}
-
void
ArrayType::accept_vis (TyVisitor &vis)
{
@@ -3088,10 +3063,30 @@ ReferenceType::is_dyn_object () const
return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ();
}
+static const TyTy::BaseType *
+destructure_through_projections (const TyTy::BaseType *t)
+{
+ const TyTy::BaseType *element = t->destructure ();
+ for (int guard = 0; guard < 16; guard++)
+ {
+ auto *proj = element->try_as<const TyTy::ProjectionType> ();
+ if (proj == nullptr)
+ break;
+ auto *normalized = Resolver::normalize_projection (
+ const_cast<TyTy::ProjectionType *> (proj), BUILTINS_LOCATION,
+ false /*emit_errors*/, false /*unify_self*/);
+ if (normalized == proj || normalized == nullptr
+ || normalized->get_kind () == TyTy::TypeKind::ERROR)
+ break;
+ element = normalized->destructure ();
+ }
+ return element;
+}
+
bool
ReferenceType::is_dyn_slice_type (const TyTy::SliceType **slice) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::SLICE)
return false;
if (slice == nullptr)
@@ -3104,7 +3099,7 @@ ReferenceType::is_dyn_slice_type (const TyTy::SliceType
**slice) const
bool
ReferenceType::is_dyn_str_type (const TyTy::StrType **str) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::STR)
return false;
if (str == nullptr)
@@ -3117,7 +3112,7 @@ ReferenceType::is_dyn_str_type (const TyTy::StrType
**str) const
bool
ReferenceType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::DYNAMIC)
return false;
if (dyn == nullptr)
@@ -3246,7 +3241,7 @@ PointerType::is_dyn_object () const
bool
PointerType::is_dyn_slice_type (const TyTy::SliceType **slice) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::SLICE)
return false;
if (slice == nullptr)
@@ -3259,7 +3254,7 @@ PointerType::is_dyn_slice_type (const TyTy::SliceType
**slice) const
bool
PointerType::is_dyn_str_type (const TyTy::StrType **str) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::STR)
return false;
if (str == nullptr)
@@ -3272,7 +3267,7 @@ PointerType::is_dyn_str_type (const TyTy::StrType **str)
const
bool
PointerType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const
{
- const TyTy::BaseType *element = get_base ()->destructure ();
+ const TyTy::BaseType *element = destructure_through_projections (get_base
());
if (element->get_kind () != TyTy::TypeKind::DYNAMIC)
return false;
if (dyn == nullptr)
@@ -3415,6 +3410,12 @@ ParamType::get_name () const
if (!can_resolve ())
return get_symbol ();
+ static std::vector<const ParamType *> active;
+ if (Resolver::ScopedPush<const ParamType *>::contains (active, this))
+ return get_symbol ();
+
+ Resolver::ScopedPush<const ParamType *> guard (active, this);
+
return destructure ()->get_name ();
}
@@ -4146,20 +4147,6 @@ PlaceholderType::clone () const
get_ty_ref (), get_combined_refs ());
}
-void
-PlaceholderType::set_associated_type (HirId ref)
-{
- auto context = Resolver::TypeCheckContext::get ();
- context->insert_associated_type_mapping (get_ty_ref (), ref);
-}
-
-void
-PlaceholderType::clear_associated_type ()
-{
- auto context = Resolver::TypeCheckContext::get ();
- context->clear_associated_type_mapping (get_ty_ref ());
-}
-
bool
PlaceholderType::can_resolve () const
{
@@ -4214,29 +4201,33 @@ PlaceholderType::get_def_id () const
ProjectionType::ProjectionType (
HirId ref, BaseType *base, const Resolver::TraitReference *trait, DefId item,
- std::vector<SubstitutionParamMapping> subst_refs,
+ std::vector<SubstitutionParamMapping> subst_refs, TyTy::BaseType *self,
SubstitutionArgumentMappings generic_arguments,
- RegionConstraints region_constraints, std::set<HirId> refs)
+ RegionConstraints region_constraints, std::set<HirId> refs,
+ size_t num_trait_substitutions)
: BaseType (ref, ref, KIND,
{Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION},
std::move (refs)),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments),
std::move (region_constraints)),
- base (base), trait (trait), item (item)
+ base (base), trait (trait), item (item), self (self),
+ num_trait_substitutions (num_trait_substitutions)
{}
ProjectionType::ProjectionType (
HirId ref, HirId ty_ref, BaseType *base,
const Resolver::TraitReference *trait, DefId item,
- std::vector<SubstitutionParamMapping> subst_refs,
+ std::vector<SubstitutionParamMapping> subst_refs, TyTy::BaseType *self,
SubstitutionArgumentMappings generic_arguments,
- RegionConstraints region_constraints, std::set<HirId> refs)
+ RegionConstraints region_constraints, std::set<HirId> refs,
+ size_t num_trait_substitutions)
: BaseType (ref, ty_ref, KIND,
{Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION},
refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments),
std::move (region_constraints)),
- base (base), trait (trait), item (item)
+ base (base), trait (trait), item (item), self (self),
+ num_trait_substitutions (num_trait_substitutions)
{}
std::string
@@ -4245,18 +4236,50 @@ ProjectionType::get_name () const
return as_string ();
}
+bool
+ProjectionType::is_trait_position () const
+{
+ return base == nullptr;
+}
+
const BaseType *
ProjectionType::get () const
{
+ rust_assert (base != nullptr);
return base;
}
BaseType *
ProjectionType::get ()
{
+ rust_assert (base != nullptr);
return base;
}
+const BaseType *
+ProjectionType::get_self () const
+{
+ return self;
+}
+
+BaseType *
+ProjectionType::get_self ()
+{
+ return self;
+}
+
+const Resolver::TraitReference *
+ProjectionType::get_trait_ref () const
+{
+ return trait;
+}
+
+DefId
+ProjectionType::get_item_defid () const
+{
+ return item;
+}
+
void
ProjectionType::accept_vis (TyVisitor &vis)
{
@@ -4272,29 +4295,28 @@ ProjectionType::accept_vis (TyConstVisitor &vis) const
std::string
ProjectionType::as_string () const
{
- return "<Projection=" + subst_as_string () + "::" + base->as_string () + ">";
+ return "<Projection=" + subst_as_string ()
+ + "::" + (base == nullptr ? "TRAIT_POSITION" : base->as_string ())
+ + "::" + self->as_string () + ">";
}
BaseType *
ProjectionType::clone () const
{
- return new ProjectionType (get_ref (), get_ty_ref (), base->clone (), trait,
- item, clone_substs (), used_arguments,
- region_constraints, get_combined_refs ());
+ auto *cloned
+ = new ProjectionType (get_ref (), get_ty_ref (),
+ base != nullptr ? base->clone () : nullptr, trait,
+ item, clone_substs (), self->clone (), used_arguments,
+ region_constraints, get_combined_refs (),
+ num_trait_substitutions);
+ cloned->inherit_bounds (get_specified_bounds ());
+ return cloned;
}
ProjectionType *
ProjectionType::handle_substitions (
SubstitutionArgumentMappings &subst_mappings)
{
- // // do we really need to substitute this?
- // if (base->needs_generic_substitutions () ||
- // base->contains_type_parameters
- // ())
- // {
- // return this;
- // }
-
ProjectionType *projection = static_cast<ProjectionType *> (clone ());
projection->set_ty_ref (mappings.get_next_hir_id ());
projection->used_arguments = subst_mappings;
@@ -4311,9 +4333,52 @@ ProjectionType::handle_substitions (
sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
}
- auto fty = projection->base;
- bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
- if (is_param_ty)
+ auto fty = projection->self;
+ if (fty->get_kind () == TypeKind::PARAM)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ projection->self = new_field;
+ }
+ else
+ {
+ fty->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->needs_generic_substitutions () || !fty->is_concrete ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete == nullptr || concrete->get_kind () ==
TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return nullptr;
+ }
+
+ projection->self = concrete;
+ }
+
+ fty = projection->base;
+ if (fty == nullptr)
+ return projection;
+
+ if (fty->get_kind () == TypeKind::PARAM)
{
ParamType *p = static_cast<ParamType *> (fty);
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 516f460e6..1079314a4 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1338,8 +1338,6 @@ public:
DefId get_def_id () const { return id; }
- void setup_fn_once_output () const;
-
const std::set<NodeId> &get_captures () const { return captures; }
private:
@@ -1792,10 +1790,6 @@ public:
std::string get_symbol () const;
- void set_associated_type (HirId ref);
-
- void clear_associated_type ();
-
bool can_resolve () const;
BaseType *resolve () const;
@@ -1817,22 +1811,28 @@ public:
ProjectionType (HirId ref, BaseType *base,
const Resolver::TraitReference *trait, DefId item,
std::vector<SubstitutionParamMapping> subst_refs,
+ TyTy::BaseType *self,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = {},
- std::set<HirId> refs = std::set<HirId> ());
+ std::set<HirId> refs = std::set<HirId> (),
+ size_t num_trait_substitutions = 0);
ProjectionType (HirId ref, HirId ty_ref, BaseType *base,
const Resolver::TraitReference *trait, DefId item,
std::vector<SubstitutionParamMapping> subst_refs,
+ TyTy::BaseType *self,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = {},
- std::set<HirId> refs = std::set<HirId> ());
+ std::set<HirId> refs = std::set<HirId> (),
+ size_t num_trait_substitutions = 0);
void accept_vis (TyVisitor &vis) override;
void accept_vis (TyConstVisitor &vis) const override;
+ bool is_trait_position () const;
+
std::string as_string () const override;
BaseType *clone () const final override;
@@ -1842,13 +1842,28 @@ public:
const BaseType *get () const;
BaseType *get ();
+ const BaseType *get_self () const;
+ BaseType *get_self ();
+ void set_self (BaseType *s) { self = s; }
+
+ const Resolver::TraitReference *get_trait_ref () const;
+
+ DefId get_item_defid () const;
+
ProjectionType *
handle_substitions (SubstitutionArgumentMappings &mappings) override final;
+ size_t get_outer_param_count () const override
+ {
+ return num_trait_substitutions;
+ }
+
private:
BaseType *base;
const Resolver::TraitReference *trait;
DefId item;
+ TyTy::BaseType *self;
+ size_t num_trait_substitutions = 0;
};
template <>
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 6a10a5793..719e21f44 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -18,8 +18,10 @@
#include "rust-unify.h"
#include "fold-const.h"
+#include "rust-substitution-mapper.h"
#include "rust-tyty-util.h"
#include "rust-tyty.h"
+#include "rust-type-util.h"
namespace Rust {
namespace Resolver {
@@ -242,7 +244,6 @@ UnifyRules::go ()
}
}
}
-
if (infer_flag)
{
bool rgot_param = rtype->get_kind () == TyTy::TypeKind::PARAM;
@@ -347,6 +348,9 @@ UnifyRules::go ()
}
}
}
+ // For PROJECTION vs PROJECTION, expect_projection handles the structural
+ // comparison directly. InferSubst on projections creates fresh infer
vars
+ // that are not tracked in `infers` and thus leak when commit=false.
}
if (ltype->get_kind () != TyTy::TypeKind::CONST
@@ -363,6 +367,13 @@ UnifyRules::go ()
ltype = lc->get_specified_type ();
}
+ if (ltype->get_kind () != TyTy::TypeKind::PROJECTION
+ && rtype->get_kind () == TyTy::TypeKind::PROJECTION)
+ {
+ auto *rtype_proj = static_cast<TyTy::ProjectionType *> (rtype);
+ rtype = normalize_projection (rtype_proj, locus, false, false);
+ }
+
switch (ltype->get_kind ())
{
case TyTy::INFER:
@@ -1869,12 +1880,82 @@ UnifyRules::expect_projection (TyTy::ProjectionType
*ltype,
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype;
+ // For non-GENERAL infers (INTEGRAL/FLOAT), try normalizing the
+ // projection first — e.g. unifying `<Bar<i32> as Foo<i32>>::A`
+ // (still trait-position) with an integer literal needs the
+ // projection to collapse to `i32` via the impl's `type A = T`.
+ if (ltype->is_trait_position ())
+ {
+ TyTy::BaseType *ln
+ = normalize_projection (ltype, locus, false, false);
+ if (ln != nullptr && ln != ltype)
+ return resolve_subtype (TyTy::TyWithLocation (ln),
+ TyTy::TyWithLocation (rtype));
+ }
}
break;
- // FIXME
case TyTy::PROJECTION:
- rust_unreachable ();
+ {
+ auto *rtype_proj = static_cast<TyTy::ProjectionType *> (rtype);
+
+ const auto ltype_tref = ltype->get_trait_ref ();
+ const auto rtype_tref = rtype_proj->get_trait_ref ();
+ if (!ltype_tref->is_equal (*rtype_tref))
+ {
+ // Trait refs differ: try normalizing ltype via the active
+ // ImplTraitContextFrame before giving up. This handles cases like
+ // <[T] as Index<I>>::Output vs <I as SliceIndex<[T]>>::Output where
+ // the frame resolves Index::Output -> I::Output
+ // (SliceIndex::Output).
+ if (ltype->is_trait_position ())
+ {
+ TyTy::BaseType *ln
+ = normalize_projection (ltype, locus, false, false);
+ if (ln != nullptr && ln != ltype)
+ return resolve_subtype (TyTy::TyWithLocation (ln),
+ TyTy::TyWithLocation (rtype));
+ }
+ return unify_error_type_node ();
+ }
+
+ auto ltype_item = ltype->get_item_defid ();
+ auto rtype_item = rtype_proj->get_item_defid ();
+ if (ltype_item != rtype_item)
+ return unify_error_type_node ();
+
+ auto lrecv = ltype->get_self ();
+ auto rrecv = rtype_proj->get_self ();
+ auto res = resolve_subtype (TyTy::TyWithLocation (lrecv),
+ TyTy::TyWithLocation (rrecv));
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ return unify_error_type_node ();
+
+ auto base_res = unify_error_type_node ();
+ bool ltrait = ltype->is_trait_position ();
+ bool rtrait = rtype_proj->is_trait_position ();
+ if (!ltrait && !rtrait)
+ {
+ auto lbase = ltype->get ();
+ auto rbase = rtype_proj->get ();
+ base_res = resolve_subtype (TyTy::TyWithLocation (lbase),
+ TyTy::TyWithLocation (rbase));
+ if (base_res->get_kind () == TyTy::TypeKind::ERROR)
+ return unify_error_type_node ();
+ }
+ else if (!ltrait)
+ base_res = ltype->get ();
+ else if (!rtrait)
+ base_res = rtype_proj->get ();
+ else
+ base_res = nullptr;
+
+ auto result
+ = new TyTy::ProjectionType (ltype->get_ref (), ltype->get_ty_ref (),
+ base_res, ltype_tref, ltype_item,
+ ltype->get_substs (), res);
+ return result;
+ }
break;
case TyTy::DYNAMIC:
@@ -1900,6 +1981,25 @@ UnifyRules::expect_projection (TyTy::ProjectionType
*ltype,
case TyTy::PLACEHOLDER:
case TyTy::OPAQUE:
case TyTy::CONST:
+ {
+ if (ltype->is_trait_position ())
+ {
+ TyTy::BaseType *ln
+ = normalize_projection (ltype, locus, false, false);
+ if (ln != nullptr && ln != ltype)
+ return resolve_subtype (TyTy::TyWithLocation (ln),
+ TyTy::TyWithLocation (rtype));
+ }
+ else
+ {
+ TyTy::BaseType *lb = ltype->get ();
+ if (lb != nullptr && lb != ltype)
+ return resolve_subtype (TyTy::TyWithLocation (lb),
+ TyTy::TyWithLocation (rtype));
+ }
+ }
+ break;
+
case TyTy::ERROR:
return unify_error_type_node ();
}
diff --git a/gcc/testsuite/rust/compile/gat1.rs
b/gcc/testsuite/rust/compile/gat1.rs
index 0131b7d27..19ec16c1f 100644
--- a/gcc/testsuite/rust/compile/gat1.rs
+++ b/gcc/testsuite/rust/compile/gat1.rs
@@ -1,6 +1,10 @@
+#![feature(lang_items)]
#![feature(no_core)]
#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+
trait Foo {
type Bar<T>;
type Baz<'a>;
diff --git a/gcc/testsuite/rust/compile/gat2.rs
b/gcc/testsuite/rust/compile/gat2.rs
index 2aead485c..db7361f83 100644
--- a/gcc/testsuite/rust/compile/gat2.rs
+++ b/gcc/testsuite/rust/compile/gat2.rs
@@ -1,3 +1,5 @@
+#![feature(no_core)]
+#![no_core]
#![feature(lang_items)]
#[lang = "sized"]
diff --git a/gcc/testsuite/rust/compile/gat3.rs
b/gcc/testsuite/rust/compile/gat3.rs
new file mode 100644
index 000000000..9c62bfbac
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat3.rs
@@ -0,0 +1,26 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+ type Bar<T>;
+
+ fn foo<T>(self, value: T) -> Self::Bar<T>;
+}
+
+impl Foo for i32 {
+ type Bar<T> = T;
+
+ fn foo<T>(self, value: T) -> Self::Bar<T> {
+ value
+ }
+}
+
+fn main() {
+ let a = 15;
+
+ let _b = a.foo::<i8>(14i8);
+}
diff --git a/gcc/testsuite/rust/compile/gat4.rs
b/gcc/testsuite/rust/compile/gat4.rs
new file mode 100644
index 000000000..3a85ae96f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat4.rs
@@ -0,0 +1,25 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+pub struct Pair<A, B>(A, B);
+
+trait Foo {
+ type Out<A, B>;
+ fn build<A, B>(self, a: A, b: B) -> Self::Out<A, B>;
+}
+
+impl Foo for i32 {
+ type Out<A, B> = Pair<A, B>;
+ fn build<A, B>(self, a: A, b: B) -> Self::Out<A, B> {
+ Pair(a, b)
+ }
+}
+
+fn main() {
+ let x: i32 = 1;
+ let _p = x.build::<i32, i64>(2, 3i64);
+}
diff --git a/gcc/testsuite/rust/compile/gat5.rs
b/gcc/testsuite/rust/compile/gat5.rs
new file mode 100644
index 000000000..6a60c9574
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat5.rs
@@ -0,0 +1,23 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+ type Bar<T>;
+ fn put<T>(self, x: Self::Bar<T>) -> Self::Bar<T>;
+}
+
+impl Foo for i32 {
+ type Bar<T> = T;
+ fn put<T>(self, x: Self::Bar<T>) -> Self::Bar<T> {
+ x
+ }
+}
+
+fn main() {
+ let x: i32 = 1;
+ let _r = x.put::<i64>(2i64);
+}
diff --git a/gcc/testsuite/rust/compile/gat6.rs
b/gcc/testsuite/rust/compile/gat6.rs
new file mode 100644
index 000000000..c22beea58
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat6.rs
@@ -0,0 +1,23 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+ type Bar<T>;
+ fn nest<T>(self, x: T) -> Self::Bar<Self::Bar<T>>;
+}
+
+impl Foo for i32 {
+ type Bar<T> = T;
+ fn nest<T>(self, x: T) -> Self::Bar<Self::Bar<T>> {
+ x
+ }
+}
+
+fn main() {
+ let x: i32 = 1;
+ let _r = x.nest::<i64>(5i64);
+}
diff --git a/gcc/testsuite/rust/compile/gat7.rs
b/gcc/testsuite/rust/compile/gat7.rs
new file mode 100644
index 000000000..0fe786643
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat7.rs
@@ -0,0 +1,18 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait LendingIter {
+ type Item<'a>;
+}
+
+struct Foo; // { dg-warning "struct is never constructed" }
+
+impl LendingIter for Foo {
+ type Item<'a> = &'a i32;
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/gat8.rs
b/gcc/testsuite/rust/compile/gat8.rs
new file mode 100644
index 000000000..6d3017b39
--- /dev/null
+++ b/gcc/testsuite/rust/compile/gat8.rs
@@ -0,0 +1,21 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+ type Bar<T>;
+ fn make<T>(self) -> Self::Bar<T>;
+}
+
+impl Foo for i32 {
+ type Bar<T> = T;
+ fn make<T>(self) -> Self::Bar<T> { loop {} }
+}
+
+fn main() {
+ let x: i32 = 1;
+ let _r = x.make::<i32, i64>(); // { dg-error "generic item takes at most 1
type arguments but 2 were supplied" }
+}
diff --git a/gcc/testsuite/rust/compile/issue-2036.rs
b/gcc/testsuite/rust/compile/issue-2036.rs
index 19ec94a2e..fe097fca3 100644
--- a/gcc/testsuite/rust/compile/issue-2036.rs
+++ b/gcc/testsuite/rust/compile/issue-2036.rs
@@ -29,7 +29,6 @@ impl<H: StreamHasher> Hash<H> for u8 {
fn hash2(&self, hasher: &H) -> u64 {
let mut stream = hasher.stream();
self.input_stream(&mut stream);
- // { dg-error "type annotations needed" "" { target *-*-* } .-1 }
Stream::result(&stream)
}
}
diff --git a/gcc/testsuite/rust/compile/issue-2905-2.rs
b/gcc/testsuite/rust/compile/issue-2905-2.rs
index e5c6c87d0..77d083640 100644
--- a/gcc/testsuite/rust/compile/issue-2905-2.rs
+++ b/gcc/testsuite/rust/compile/issue-2905-2.rs
@@ -76,17 +76,13 @@ pub mod core {
impl<T> Foo for Weird<T> {}
- // impl<T> core::iter::Iterator for Iter<T> {
- // type Item = &T;
-
- // fn next(&mut self) -> Option<&T> {
- // if self.is_empty() {
- // Option::None
- // } else {
- // Option::Some(&*self.next_unchecked())
- // }
- // }
- // }
+ impl<T> crate::core::iter::Iterator for Weird<T> {
+ type Item = &T;
+
+ fn next(&mut self) -> Option<&T> {
+ Option::None
+ }
+ }
union Repr<T> {
pub(crate) rust: *const [T],
diff --git a/gcc/testsuite/rust/compile/issue-4293.rs
b/gcc/testsuite/rust/compile/issue-4293.rs
new file mode 100644
index 000000000..d7609a2c7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4293.rs
@@ -0,0 +1,32 @@
+#![feature(no_core)]
+#![no_core]
+#![feature(lang_items)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+trait Foo {
+ type Bar<T>;
+
+ fn foo<T>(self, value: T) -> Self::Bar<T>;
+ fn baz<T>(self, value: T) -> Self::Bar<T>;
+}
+
+impl Foo for i32 {
+ type Bar<T> = T;
+
+ fn foo<T>(self, value: T) -> Self::Bar<T> {
+ value
+ }
+
+ fn baz<T>(self, value: T) -> Self::Bar<T> {
+ value
+ }
+}
+
+fn main() {
+ let a = 15;
+
+ let _b = a.foo::<i8>(14i8);
+ let _c = a.baz::<u32>(32u32);
+}
diff --git a/gcc/testsuite/rust/compile/torture/traits18.rs
b/gcc/testsuite/rust/compile/torture/traits18.rs.disabled
similarity index 100%
rename from gcc/testsuite/rust/compile/torture/traits18.rs
rename to gcc/testsuite/rust/compile/torture/traits18.rs.disabled
--
2.54.0