Skip to content

Commit

Permalink
gccrs: fix name resolution for generics where type param is declared …
Browse files Browse the repository at this point in the history
…later

Rust allows you to use generics within type bounds when they are declared
later on. This changes the name resolution to walk the genric params
in two passes to ensure the type parameters are setup before drilling down
into the type parameters

This issue has exposed another type checking issue which needs fixed in
a subseqent patch.

Addresses #3022

gcc/rust/ChangeLog:

	* resolve/rust-ast-resolve-item.cc (ResolveTraitItems::visit): use new api
	(ResolveItem::visit): likewise
	(ResolveExternItem::visit): likewise
	* resolve/rust-ast-resolve-stmt.h: likewise
	* resolve/rust-ast-resolve-type.h (class ResolveGenericParam): remove
	(class ResolveGenericParams): added new api

Signed-off-by: Philip Herron <[email protected]>
  • Loading branch information
philberty committed Feb 13, 2025
1 parent 5f7213e commit 3bf3621
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 75 deletions.
48 changes: 24 additions & 24 deletions gcc/rust/resolve/rust-ast-resolve-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ ResolveTraitItems::visit (AST::Function &function)
resolver->push_new_label_rib (resolver->get_label_scope ().peek ());

if (function.has_generics ())
for (auto &generic : function.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (function.get_generic_params (), prefix,
canonical_prefix);

if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
Expand Down Expand Up @@ -188,8 +188,8 @@ ResolveItem::visit (AST::TypeAlias &alias)
resolver->get_type_scope ().push (scope_node_id);

if (alias.has_generics ())
for (auto &generic : alias.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (alias.get_generic_params (), prefix,
canonical_prefix);

if (alias.has_where_clause ())
ResolveWhereClause::Resolve (alias.get_where_clause ());
Expand Down Expand Up @@ -250,8 +250,8 @@ ResolveItem::visit (AST::TupleStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);

if (struct_decl.has_generics ())
for (auto &generic : struct_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
canonical_prefix);

if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
Expand Down Expand Up @@ -284,8 +284,8 @@ ResolveItem::visit (AST::Enum &enum_decl)
resolver->get_type_scope ().push (scope_node_id);

if (enum_decl.has_generics ())
for (auto &generic : enum_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, cpath);
ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
canonical_prefix);

if (enum_decl.has_where_clause ())
ResolveWhereClause::Resolve (enum_decl.get_where_clause ());
Expand Down Expand Up @@ -374,8 +374,8 @@ ResolveItem::visit (AST::StructStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);

if (struct_decl.has_generics ())
for (auto &generic : struct_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
canonical_prefix);

if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
Expand Down Expand Up @@ -409,8 +409,8 @@ ResolveItem::visit (AST::Union &union_decl)
resolver->get_type_scope ().push (scope_node_id);

if (union_decl.has_generics ())
for (auto &generic : union_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
canonical_prefix);

if (union_decl.has_where_clause ())
ResolveWhereClause::Resolve (union_decl.get_where_clause ());
Expand Down Expand Up @@ -476,8 +476,8 @@ ResolveItem::visit (AST::Function &function)
resolver->push_new_label_rib (resolver->get_label_scope ().peek ());

if (function.has_generics ())
for (auto &generic : function.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (function.get_generic_params (), prefix,
canonical_prefix);

// resolve any where clause items
if (function.has_where_clause ())
Expand Down Expand Up @@ -567,8 +567,8 @@ ResolveItem::visit (AST::InherentImpl &impl_block)
resolve_visibility (impl_block.get_visibility ());

if (impl_block.has_generics ())
for (auto &generic : impl_block.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
canonical_prefix);

// resolve any where clause items
if (impl_block.has_where_clause ())
Expand Down Expand Up @@ -651,8 +651,8 @@ ResolveItem::visit (AST::TraitImpl &impl_block)
resolver->push_new_label_rib (resolver->get_label_scope ().peek ());

if (impl_block.has_generics ())
for (auto &generic : impl_block.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
canonical_prefix);

// resolve any where clause items
if (impl_block.has_where_clause ())
Expand Down Expand Up @@ -776,10 +776,10 @@ ResolveItem::visit (AST::Trait &trait)
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());

ResolveGenericParam::go (trait.get_implicit_self (), prefix,
canonical_prefix);
for (auto &generic : trait.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go_single (trait.get_implicit_self (), prefix,
canonical_prefix);
ResolveGenericParams::go (trait.get_generic_params (), prefix,
canonical_prefix);

// Self is an implicit TypeParam so lets mark it as such
resolver->get_type_scope ().append_reference_for_def (
Expand Down Expand Up @@ -1044,8 +1044,8 @@ ResolveExternItem::visit (AST::Function &function)

// resolve the generics
if (function.has_generics ())
for (auto &generic : function.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (function.get_generic_params (), prefix,
canonical_prefix);

if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
Expand Down
26 changes: 10 additions & 16 deletions gcc/rust/resolve/rust-ast-resolve-stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,8 @@ class ResolveStmt : public ResolverBase
resolver->get_type_scope ().push (scope_node_id);

if (struct_decl.has_generics ())
{
for (auto &generic : struct_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
}
ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
canonical_prefix);

for (AST::TupleField &field : struct_decl.get_fields ())
ResolveType::go (field.get_field_type ());
Expand Down Expand Up @@ -137,10 +135,8 @@ class ResolveStmt : public ResolverBase
resolver->get_type_scope ().push (scope_node_id);

if (enum_decl.has_generics ())
{
for (auto &generic : enum_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
}
ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
canonical_prefix);

for (auto &variant : enum_decl.get_variants ())
ResolveStmt::go (*variant, path, canonical_prefix, path);
Expand Down Expand Up @@ -262,10 +258,8 @@ class ResolveStmt : public ResolverBase
resolver->get_type_scope ().push (scope_node_id);

if (struct_decl.has_generics ())
{
for (auto &generic : struct_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
}
ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
canonical_prefix);

for (AST::StructField &field : struct_decl.get_fields ())
{
Expand Down Expand Up @@ -300,8 +294,8 @@ class ResolveStmt : public ResolverBase
resolver->get_type_scope ().push (scope_node_id);

if (union_decl.has_generics ())
for (auto &generic : union_decl.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
canonical_prefix);

for (AST::StructField &field : union_decl.get_variants ())
{
Expand Down Expand Up @@ -341,8 +335,8 @@ class ResolveStmt : public ResolverBase
resolver->push_new_label_rib (resolver->get_label_scope ().peek ());

if (function.has_generics ())
for (auto &generic : function.get_generic_params ())
ResolveGenericParam::go (*generic, prefix, canonical_prefix);
ResolveGenericParams::go (function.get_generic_params (), prefix,
canonical_prefix);

if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
Expand Down
87 changes: 52 additions & 35 deletions gcc/rust/resolve/rust-ast-resolve-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,66 +142,83 @@ class ResolveTypeBound : public ResolverBase
ResolveTypeBound () : ResolverBase () {}
};

class ResolveGenericParam : public ResolverBase
class ResolveGenericParams : public ResolverBase
{
using Rust::Resolver::ResolverBase::visit;

public:
static NodeId go (AST::GenericParam &param, const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
static void go (std::vector<std::unique_ptr<AST::GenericParam>> &params,
const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
{
ResolveGenericParam resolver (prefix, canonical_prefix);
ResolveGenericParams resolver (prefix, canonical_prefix);

// this needs to be done in two phases as they can be used and defined later
// in bounds
for (auto &param : params)
param->accept_vis (resolver);

resolver.first_pass = false;

for (auto &param : params)
param->accept_vis (resolver);
}

static void go_single (AST::GenericParam &param, const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
{
ResolveGenericParams resolver (prefix, canonical_prefix);

param.accept_vis (resolver);
resolver.first_pass = false;
param.accept_vis (resolver);
return resolver.resolved_node;
}

void visit (AST::ConstGenericParam &param) override
{
ResolveType::go (param.get_type ());

if (param.has_default_value ())
if (first_pass)
ResolveType::go (param.get_type ());
else if (param.has_default_value ())
ResolveExpr::go (param.get_default_value ().get_expression (), prefix,
canonical_prefix);

ok = true;
}

void visit (AST::TypeParam &param) override
{
// if it has a type lets resolve it
if (param.has_type ())
ResolveType::go (param.get_type ());

if (param.has_type_param_bounds ())
if (first_pass)
{
// if it has a type lets resolve it
if (param.has_type ())
ResolveType::go (param.get_type ());

auto seg = CanonicalPath::new_seg (
param.get_node_id (), param.get_type_representation ().as_string ());
resolver->get_type_scope ().insert (
seg, param.get_node_id (), param.get_locus (), false,
Rib::ItemType::Type,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rust_error_at (param.get_locus (),
"generic param redefined multiple times");
rust_error_at (locus, "was defined here");
});

mappings.insert_canonical_path (param.get_node_id (), seg);
}
else if (param.has_type_param_bounds ())
{
for (auto &bound : param.get_type_param_bounds ())
{
ResolveTypeBound::go (*bound);
}
ResolveTypeBound::go (*bound);
}

auto seg
= CanonicalPath::new_seg (param.get_node_id (),
param.get_type_representation ().as_string ());
resolver->get_type_scope ().insert (
seg, param.get_node_id (), param.get_locus (), false, Rib::ItemType::Type,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rust_error_at (param.get_locus (),
"generic param redefined multiple times");
rust_error_at (locus, "was defined here");
});

mappings.insert_canonical_path (param.get_node_id (), seg);
}

private:
ResolveGenericParam (const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
: ResolverBase (), ok (false), prefix (prefix),
ResolveGenericParams (const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
: ResolverBase (), first_pass (true), prefix (prefix),
canonical_prefix (canonical_prefix)
{}

bool ok;
bool first_pass;
const CanonicalPath &prefix;
const CanonicalPath &canonical_prefix;
};
Expand Down

0 comments on commit 3bf3621

Please sign in to comment.