Skip to content

Commit

Permalink
Complete refactor of generic traits handling
Browse files Browse the repository at this point in the history
From PR #1086 I introduced a new setup_associated_types2 interface which
is used to ensure we handle the complex associated types in libcore slices
but this interface was inconsistant as well as the get_projected_type.

This path refactors the code base to get rid of the old
setup_associated_types interface in favour of this new one. It also removes
the get_projected_type interface which was not going to work either.

Fixes #1105
  • Loading branch information
philberty committed Apr 28, 2022
1 parent 712ae2f commit be158fc
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 197 deletions.
1 change: 1 addition & 0 deletions gcc/rust/backend/rust-compile-implitem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func)

rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (concrete);
fntype->monomorphize ();

// items can be forward compiled which means we may not need to invoke this
// code. We might also have already compiled this generic function as well.
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/backend/rust-compile-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ CompileItem::visit (HIR::Function &function)
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
fntype->monomorphize ();
}
}

Expand Down
15 changes: 0 additions & 15 deletions gcc/rust/backend/rust-compile-resolve-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -251,21 +251,6 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
rust_assert (ok); // found
rust_assert (trait_item_ref->is_optional ()); // has definition

Analysis::NodeMapping trait_mappings
= trait_item_ref->get_parent_trait_mappings ();

HirId associated_impl_id;
ok = ctx->get_tyctx ()->lookup_associated_impl_mapping_for_self (
trait_mappings.get_hirid (), receiver, &associated_impl_id);
rust_assert (ok);

Resolver::AssociatedImplTrait *associated = nullptr;
bool found_associated_trait_impl
= ctx->get_tyctx ()->lookup_associated_trait_impl (
associated_impl_id, &associated);
rust_assert (found_associated_trait_impl);
associated->setup_associated_types ();

return CompileTraitItem::Compile (
trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
expr_locus);
Expand Down
12 changes: 0 additions & 12 deletions gcc/rust/typecheck/rust-hir-path-probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,18 +326,6 @@ class PathProbeType : public TypeCheckBase
}

TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ();
if (impl != nullptr && !is_reciever_generic ())

{
HirId impl_block_id = impl->get_mappings ().get_hirid ();
AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait
= context->lookup_associated_trait_impl (impl_block_id,
&lookup_associated);
// see testsuite/rust/compile/torture/traits10.rs this can be false
if (found_impl_trait)
lookup_associated->setup_associated_types ();
}

// we can substitute the Self with the receiver here
if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
Expand Down
11 changes: 2 additions & 9 deletions gcc/rust/typecheck/rust-hir-trait-ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,18 +454,11 @@ class AssociatedImplTrait

TyTy::BaseType *get_self () { return self; }

void setup_associated_types ();

void setup_associated_types2 (const TyTy::BaseType *self,
const TyTy::TypeBoundPredicate &bound);
void setup_associated_types (const TyTy::BaseType *self,
const TyTy::TypeBoundPredicate &bound);

void reset_associated_types ();

TyTy::BaseType *get_projected_type (const TraitItemReference *trait_item_ref,
TyTy::BaseType *reciever, HirId ref,
HIR::GenericArgs &trait_generics,
Location expr_locus);

private:
TraitReference *trait;
HIR::ImplBlock *impl;
Expand Down
64 changes: 1 addition & 63 deletions gcc/rust/typecheck/rust-hir-trait-resolve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,29 +154,7 @@ TraitItemReference::associated_type_reset () const
}

void
AssociatedImplTrait::setup_associated_types ()
{
ImplTypeIterator iter (*impl, [&] (HIR::TypeAlias &type) {
TraitItemReference *resolved_trait_item = nullptr;
bool ok = trait->lookup_trait_item (type.get_new_type_name (),
&resolved_trait_item);
if (!ok)
return;
if (resolved_trait_item->get_trait_item_type ()
!= TraitItemReference::TraitItemType::TYPE)
return;

TyTy::BaseType *lookup;
if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
return;

resolved_trait_item->associated_type_set (lookup);
});
iter.go ();
}

void
AssociatedImplTrait::setup_associated_types2 (
AssociatedImplTrait::setup_associated_types (
const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound)
{
// compute the constrained impl block generic arguments based on self and the
Expand Down Expand Up @@ -390,46 +368,6 @@ TraitItemReference::is_object_safe () const
return false;
}

TyTy::BaseType *
AssociatedImplTrait::get_projected_type (
const TraitItemReference *trait_item_ref, TyTy::BaseType *receiver, HirId ref,
HIR::GenericArgs &trait_generics, Location expr_locus)
{
TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ()->clone ();

// we can substitute the Self with the receiver here
if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
{
TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
TyTy::SubstitutionParamMapping *param = nullptr;
for (auto &param_mapping : fn->get_substs ())
{
const HIR::TypeParam &type_param = param_mapping.get_generic_param ();
if (type_param.get_type_representation ().compare ("Self") == 0)
{
param = &param_mapping;
break;
}
}
rust_assert (param != nullptr);

std::vector<TyTy::SubstitutionArg> mappings;
mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ()));

TyTy::SubstitutionArgumentMappings args (std::move (mappings),
expr_locus);
trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args);
}

if (!trait_generics.is_empty ())
{
trait_item_tyty
= SubstMapper::Resolve (trait_item_tyty, expr_locus, &trait_generics);
}

return trait_item_tyty;
}

// rust-hir-path-probe.h

void
Expand Down
71 changes: 29 additions & 42 deletions gcc/rust/typecheck/rust-hir-type-check-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,41 +67,41 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
// inherit the bound
root->inherit_bounds ({specified_bound});

// we need resolve to the impl block
NodeId impl_resolved_id = UNKNOWN_NODEID;
bool ok = resolver->lookup_resolved_name (
qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
rust_assert (ok);

HirId impl_block_id;
ok = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
impl_resolved_id, &impl_block_id);
rust_assert (ok);

AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait
= context->lookup_associated_trait_impl (impl_block_id, &lookup_associated);
rust_assert (found_impl_trait);

// lookup the associated item from the specified bound
HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);

const TraitItemReference *trait_item_ref = nullptr;
ok = trait_ref->lookup_trait_item (item_seg.get_segment ().as_string (),
&trait_item_ref);
if (!ok)
HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
TyTy::TypeBoundPredicateItem item
= specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
if (item.is_error ())
{
rust_error_at (item_seg.get_locus (), "unknown associated item");
return;
}

HIR::GenericArgs trait_generics = qual_path_type.trait_has_generic_args ()
? qual_path_type.get_trait_generic_args ()
: HIR::GenericArgs::create_empty ();
// infer the root type
infered = item.get_tyty_for_receiver (root);

lookup_associated->setup_associated_types ();
infered = lookup_associated->get_projected_type (
trait_item_ref, root, item_seg.get_mappings ().get_hirid (), trait_generics,
item_seg.get_locus ());
// we need resolve to the impl block
NodeId impl_resolved_id = UNKNOWN_NODEID;
bool have_associated_impl = resolver->lookup_resolved_name (
qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
AssociatedImplTrait *lookup_associated = nullptr;
if (have_associated_impl)
{
HirId impl_block_id;
bool ok
= mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
impl_resolved_id, &impl_block_id);
rust_assert (ok);

bool found_impl_trait
= context->lookup_associated_trait_impl (impl_block_id,
&lookup_associated);
if (found_impl_trait)
{
lookup_associated->setup_associated_types (root, specified_bound);
}
}

// turbo-fish segment path::<ty>
if (item_seg.has_generic_args ())
Expand All @@ -119,6 +119,7 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
}

// continue on as a path-in-expression
const TraitItemReference *trait_item_ref = item.get_raw_item ();
NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
bool fully_resolved = expr.get_segments ().size () <= 1;

Expand Down Expand Up @@ -348,20 +349,6 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
HIR::ImplBlock *impl = candidate.item.trait.impl;
if (impl != nullptr)
{
AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait = context->lookup_associated_trait_impl (
impl->get_mappings ().get_hirid (), &lookup_associated);

// setup associated mappings if possible we might be resolving a
// path within a default implementation of a trait function
// see: testsuite/rust/compile/torture/traits16.rs
if (found_impl_trait)
lookup_associated->setup_associated_types ();

// we need a new ty_ref_id for this trait item
tyseg = tyseg->clone ();
tyseg->set_ty_ref (mappings->get_next_hir_id ());

// get the associated impl block
associated_impl_block = impl;
}
Expand Down
67 changes: 21 additions & 46 deletions gcc/rust/typecheck/rust-hir-type-check-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -142,31 +142,35 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
return;
}

// get the predicate for the bound
auto specified_bound
= get_predicate_from_bound (*qual_path_type.get_trait ().get ());
if (specified_bound.is_error ())
return;

// inherit the bound
root->inherit_bounds ({specified_bound});

// lookup the associated item from the specified bound
std::unique_ptr<HIR::TypePathSegment> &item_seg
= path.get_associated_segment ();
const TraitItemReference *trait_item_ref = nullptr;
bool ok
= trait_ref->lookup_trait_item (item_seg->get_ident_segment ().as_string (),
&trait_item_ref);
if (!ok)
HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment ();
TyTy::TypeBoundPredicateItem item
= specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
if (item.is_error ())
{
rust_error_at (item_seg->get_locus (), "unknown associated item");
return;
}

// this will be the placeholder from the trait but we may be able to project
// it based on the impl block
translated = trait_item_ref->get_tyty ();

// this is the associated generics we need to potentially apply
HIR::GenericArgs trait_generics = qual_path_type.trait_has_generic_args ()
? qual_path_type.get_trait_generic_args ()
: HIR::GenericArgs::create_empty ();
// infer the root type
translated = item.get_tyty_for_receiver (root);

// we need resolve to the impl block
NodeId impl_resolved_id = UNKNOWN_NODEID;
bool have_associated_impl = resolver->lookup_resolved_name (
qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
AssociatedImplTrait *lookup_associated = nullptr;
if (have_associated_impl)
{
HirId impl_block_id;
Expand All @@ -175,30 +179,16 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
impl_resolved_id, &impl_block_id);
rust_assert (ok);

AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait
= context->lookup_associated_trait_impl (impl_block_id,
&lookup_associated);
rust_assert (found_impl_trait);

// project
lookup_associated->setup_associated_types ();
translated = lookup_associated->get_projected_type (
trait_item_ref, root, item_seg->get_mappings ().get_hirid (),
trait_generics, item_seg->get_locus ());
}

if (translated->get_kind () == TyTy::TypeKind::PLACEHOLDER)
{
// lets grab the actual projection type
TyTy::PlaceholderType *p
= static_cast<TyTy::PlaceholderType *> (translated);
if (p->can_resolve ())
if (found_impl_trait)
{
translated = p->resolve ();
lookup_associated->setup_associated_types (root, specified_bound);
}
}

// turbo-fish segment path::<ty>
if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
{
HIR::TypePathSegmentGeneric &generic_seg
Expand All @@ -222,6 +212,7 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
}

// continue on as a path-in-expression
const TraitItemReference *trait_item_ref = item.get_raw_item ();
NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
bool fully_resolved = path.get_segments ().empty ();
if (fully_resolved)
Expand Down Expand Up @@ -448,22 +439,6 @@ TypeCheckType::resolve_segments (
{
resolved_node_id
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();

// lookup the associated-impl-trait
HIR::ImplBlock *impl = candidate.item.trait.impl;
if (impl != nullptr && !reciever_is_generic)
{
AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait = context->lookup_associated_trait_impl (
impl->get_mappings ().get_hirid (), &lookup_associated);
rust_assert (found_impl_trait);

lookup_associated->setup_associated_types ();

// we need a new ty_ref_id for this trait item
tyseg = tyseg->clone ();
tyseg->set_ty_ref (mappings->get_next_hir_id ());
}
}

if (seg->is_generic_segment ())
Expand Down
Loading

0 comments on commit be158fc

Please sign in to comment.