Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gccrs: improve handling of Self Type paths #3269

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gcc/rust/typecheck/rust-hir-trait-resolve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
}
self->inherit_bounds (specified_bounds);

context->push_block_context (TypeCheckBlockContextItem (trait_reference));
std::vector<TraitItemReference> item_refs;
for (auto &item : trait_reference->get_trait_items ())
{
Expand Down Expand Up @@ -307,6 +308,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
// resolve the blocks of functions etc because it can end up in a recursive
// loop of trying to resolve traits as required by the types
tref->on_resolved ();
context->pop_block_context ();

return tref;
}
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-implitem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,10 @@ TypeCheckImplItem::Resolve (

// resolve
TypeCheckImplItem resolver (parent, self, substitutions);
resolver.context->push_block_context (TypeCheckBlockContextItem (&parent));
item.accept_vis (resolver);
resolver.context->pop_block_context ();

return resolver.result;
}

Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/typecheck/rust-hir-type-check-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
NodeId resolved_node_id = root_resolved_node_id;
TyTy::BaseType *prev_segment = tyseg;
bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
bool reciever_is_dyn = prev_segment->get_kind () == TyTy::TypeKind::DYNAMIC;

for (size_t i = offset; i < segments.size (); i++)
{
Expand Down Expand Up @@ -434,7 +435,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
}
}

if (associated_impl_block != nullptr)
if (associated_impl_block != nullptr && !reciever_is_dyn)
{
// associated types
HirId impl_block_id
Expand Down
195 changes: 137 additions & 58 deletions gcc/rust/typecheck/rust-hir-type-check-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,16 @@ TypeCheckType::visit (HIR::TypePath &path)

// this can happen so we need to look up the root then resolve the
// remaining segments if possible
bool wasBigSelf = false;
size_t offset = 0;
NodeId resolved_node_id = UNKNOWN_NODEID;
TyTy::BaseType *root = resolve_root_path (path, &offset, &resolved_node_id);
TyTy::BaseType *root
= resolve_root_path (path, &offset, &resolved_node_id, &wasBigSelf);
if (root->get_kind () == TyTy::TypeKind::ERROR)
return;
{
rust_debug_loc (path.get_locus (), "failed to resolve type-path type");
return;
}

TyTy::BaseType *path_type = root->clone ();
path_type->set_ref (path.get_mappings ().get_hirid ());
Expand All @@ -147,13 +152,18 @@ TypeCheckType::visit (HIR::TypePath &path)
if (fully_resolved)
{
translated = path_type;
rust_debug_loc (path.get_locus (), "root resolved type-path to: [%s]",
translated->debug_str ().c_str ());
return;
}

translated
= resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
path.get_segments (), offset, path_type,
path.get_mappings (), path.get_locus ());
path.get_mappings (), path.get_locus (), wasBigSelf);

rust_debug_loc (path.get_locus (), "resolved type-path to: [%s]",
translated->debug_str ().c_str ());
}

void
Expand Down Expand Up @@ -192,10 +202,11 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
}
rust_assert (ok);

translated = resolve_segments (root_resolved_node_id,
path.get_mappings ().get_hirid (),
path.get_segments (), 0, translated,
path.get_mappings (), path.get_locus ());
translated
= resolve_segments (root_resolved_node_id,
path.get_mappings ().get_hirid (),
path.get_segments (), 0, translated,
path.get_mappings (), path.get_locus (), false);

return;
}
Expand Down Expand Up @@ -356,12 +367,14 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
translated
= resolve_segments (root_resolved_node_id,
path.get_mappings ().get_hirid (), path.get_segments (),
0, translated, path.get_mappings (), path.get_locus ());
0, translated, path.get_mappings (), path.get_locus (),
false);
}

TyTy::BaseType *
TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
NodeId *root_resolved_node_id)
NodeId *root_resolved_node_id,
bool *wasBigSelf)
{
TyTy::BaseType *root_tyty = nullptr;
*offset = 0;
Expand Down Expand Up @@ -403,6 +416,9 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
return root_tyty;
}

if (seg->is_ident_only () && seg->as_string () == "Self")
*wasBigSelf = true;

// node back to HIR
tl::optional<HirId> hid = mappings.lookup_node_to_hir (ref_node_id);
if (!hid.has_value ())
Expand Down Expand Up @@ -509,12 +525,57 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
return root_tyty;
}

bool
TypeCheckType::resolve_associated_type (const std::string &search,
TypeCheckBlockContextItem &ctx,
TyTy::BaseType **result)
{
if (ctx.is_trait_block ())
{
HIR::Trait &trait = ctx.get_trait ();
for (auto &item : trait.get_trait_items ())
{
if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::TYPE)
continue;

if (item->trait_identifier () == search)
{
HirId item_id = item->get_mappings ().get_hirid ();
if (query_type (item_id, result))
return true;
}
}

// FIXME
// query any parent trait?

return false;
}

// look for any segment in here which matches
HIR::ImplBlock &block = ctx.get_impl_block ();
for (auto &item : block.get_impl_items ())
{
if (item->get_impl_item_type () != HIR::ImplItem::TYPE_ALIAS)
continue;

if (item->get_impl_item_name () == search)
{
HirId item_id = item->get_impl_mappings ().get_hirid ();
if (query_type (item_id, result))
return true;
}
}

return false;
}

TyTy::BaseType *
TypeCheckType::resolve_segments (
NodeId root_resolved_node_id, HirId expr_id,
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
location_t expr_locus)
location_t expr_locus, bool tySegIsBigSelf)
{
NodeId resolved_node_id = root_resolved_node_id;
TyTy::BaseType *prev_segment = tyseg;
Expand All @@ -527,66 +588,84 @@ TypeCheckType::resolve_segments (
bool probe_bounds = true;
bool probe_impls = !reciever_is_generic;
bool ignore_mandatory_trait_items = !reciever_is_generic;
bool first_segment = i == offset;
bool selfResolveOk = false;

// probe the path is done in two parts one where we search impls if no
// candidate is found then we search extensions from traits
auto candidates
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
probe_impls, false,
ignore_mandatory_trait_items);
if (candidates.size () == 0)
if (first_segment && tySegIsBigSelf && context->have_block_context ()
&& context->peek_block_context ().is_impl_block ())
{
TypeCheckBlockContextItem ctx = context->peek_block_context ();
TyTy::BaseType *lookup = nullptr;
selfResolveOk
= resolve_associated_type (seg->as_string (), ctx, &lookup);
if (selfResolveOk)
{
prev_segment = tyseg;
tyseg = lookup;
}
}
if (!selfResolveOk)
{
candidates
// probe the path is done in two parts one where we search impls if no
// candidate is found then we search extensions from traits
auto candidates
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
false, probe_bounds,
probe_impls, false,
ignore_mandatory_trait_items);

if (candidates.size () == 0)
{
rust_error_at (
seg->get_locus (),
"failed to resolve path segment using an impl Probe");
candidates
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
false, probe_bounds,
ignore_mandatory_trait_items);
if (candidates.size () == 0)
{
rust_error_at (
seg->get_locus (),
"failed to resolve path segment using an impl Probe");
return new TyTy::ErrorType (expr_id);
}
}

if (candidates.size () > 1)
{
ReportMultipleCandidateError::Report (candidates,
seg->get_ident_segment (),
seg->get_locus ());
return new TyTy::ErrorType (expr_id);
}
}

if (candidates.size () > 1)
{
ReportMultipleCandidateError::Report (candidates,
seg->get_ident_segment (),
seg->get_locus ());
return new TyTy::ErrorType (expr_id);
}
auto &candidate = *candidates.begin ();
prev_segment = tyseg;
tyseg = candidate.ty;

auto &candidate = *candidates.begin ();
prev_segment = tyseg;
tyseg = candidate.ty;
if (candidate.is_enum_candidate ())
{
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg);
auto last_variant = adt->get_variants ();
TyTy::VariantDef *variant = last_variant.back ();

if (candidate.is_enum_candidate ())
{
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg);
auto last_variant = adt->get_variants ();
TyTy::VariantDef *variant = last_variant.back ();

rich_location richloc (line_table, seg->get_locus ());
richloc.add_fixit_replace ("not a type");

rust_error_at (richloc, ErrorCode::E0573,
"expected type, found variant of %<%s::%s%>",
adt->get_name ().c_str (),
variant->get_identifier ().c_str ());
return new TyTy::ErrorType (expr_id);
}
rich_location richloc (line_table, seg->get_locus ());
richloc.add_fixit_replace ("not a type");

if (candidate.is_impl_candidate ())
{
resolved_node_id
= candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
}
else
{
resolved_node_id
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
rust_error_at (richloc, ErrorCode::E0573,
"expected type, found variant of %<%s::%s%>",
adt->get_name ().c_str (),
variant->get_identifier ().c_str ());
return new TyTy::ErrorType (expr_id);
}

if (candidate.is_impl_candidate ())
{
resolved_node_id
= candidate.item.impl.impl_item->get_impl_mappings ()
.get_nodeid ();
}
else
{
resolved_node_id
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
}
}

if (seg->is_generic_segment ())
Expand Down
9 changes: 7 additions & 2 deletions gcc/rust/typecheck/rust-hir-type-check-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,18 @@ class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor
{}

TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset,
NodeId *root_resolved_node_id);
NodeId *root_resolved_node_id,
bool *wasBigSelf);

TyTy::BaseType *resolve_segments (
NodeId root_resolved_node_id, HirId expr_id,
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
location_t expr_locus);
location_t expr_locus, bool tySegIsBigSelf);

bool resolve_associated_type (const std::string &search,
TypeCheckBlockContextItem &ctx,
TyTy::BaseType **result);

TyTy::BaseType *translated;
};
Expand Down
38 changes: 38 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,37 @@ class TypeCheckContextItem
Item item;
};

class TypeCheckBlockContextItem
{
public:
enum ItemType
{
IMPL_BLOCK,
TRAIT
};

TypeCheckBlockContextItem (HIR::ImplBlock *block);
TypeCheckBlockContextItem (HIR::Trait *trait);

bool is_impl_block () const;
bool is_trait_block () const;

HIR::ImplBlock &get_impl_block ();
HIR::Trait &get_trait ();

private:
union Item
{
HIR::ImplBlock *block;
HIR::Trait *trait;

Item (HIR::ImplBlock *block);
Item (HIR::Trait *trait);
};
ItemType type;
Item item;
};

/**
* Interned lifetime representation in TyTy
*
Expand Down Expand Up @@ -154,6 +185,12 @@ class TypeCheckContext
void push_return_type (TypeCheckContextItem item,
TyTy::BaseType *return_type);
void pop_return_type ();

bool have_block_context () const;
TypeCheckBlockContextItem peek_block_context ();
void push_block_context (TypeCheckBlockContextItem item);
void pop_block_context ();

void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb);

bool have_loop_context () const;
Expand Down Expand Up @@ -245,6 +282,7 @@ class TypeCheckContext
std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
return_type_stack;
std::vector<TyTy::BaseType *> loop_type_stack;
std::vector<TypeCheckBlockContextItem> block_stack;
std::map<DefId, TraitReference> trait_context;
std::map<HirId, TyTy::BaseType *> receiver_context;
std::map<HirId, AssociatedImplTrait> associated_impl_traits;
Expand Down
Loading
Loading