diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-04-10 15:31:29 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-04-12 22:39:45 +0100 |
commit | 85f587410612c8d2ec65dd23063a849d13005957 (patch) | |
tree | becd4a2fe59042dc35cbaae862403105b5ead1df /gcc | |
parent | 5fe4984806be69154e2a48be58965eb67a4be300 (diff) | |
download | gcc-85f587410612c8d2ec65dd23063a849d13005957.zip gcc-85f587410612c8d2ec65dd23063a849d13005957.tar.gz gcc-85f587410612c8d2ec65dd23063a849d13005957.tar.bz2 |
Add Canonical paths to name resolution
In order to support name resolution and checks for duplicate definitions
of names we need canonical paths for all DefId items such as inherent impl
items and normal items.
Consider:
struct Foo<T>(T);
impl Foo<f32> {
fn name()...
}
impl Foo<i32> {
fn name()...
}
Each of the impl blocks have a name function but these are seperate due to
the concrete impl of the Parameter type passed in.
The caveat here is that to call this Function name the programmer must be
explicit in which implentation they wish to call such as:
let a = Foo::<f32>::name();
This lets the Path probe lookup the apropriate impl block. The problem here
is that rust also allows for the compiler to infer the impl you wish such
as:
let a = Foo::name();
This should fail since there are multiple candidates possible for this
Path. Unless there might have only been one name function in which case
it would have worked.
This does not support looking for any inherent impl items overlapping such
as: rustc_typeck/src/coherence/inherent_impls_overlap.rs - see #353
Fixes #355 #335 #325
Diffstat (limited to 'gcc')
19 files changed, 686 insertions, 317 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 48cc18e..fbf05f2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -109,15 +109,16 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) { resolver->insert_resolved_name (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), Definition{expr.get_node_id (), parent}); } - else if (resolver->get_type_scope ().lookup (expr.as_string (), - &resolved_node)) + else if (resolver->get_type_scope ().lookup ( + CanonicalPath (expr.as_string ()), &resolved_node)) { resolver->insert_resolved_type (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), @@ -255,8 +256,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -281,8 +283,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); @@ -311,8 +313,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -338,8 +341,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h index d88b275f..46343c2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-implitem.h +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -31,25 +31,19 @@ class ResolveToplevelImplItem : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::InherentImplItem *item, AST::Type *base) + static void go (AST::InherentImplItem *item, const CanonicalPath &prefix) { - ResolveToplevelImplItem resolver (base); - if (resolver.base_path.is_empty ()) - { - rust_error_at (base->get_locus_slow (), - "failed to resolve simple path"); - return; - } + ResolveToplevelImplItem resolver (prefix); item->accept_vis (resolver); } void visit (AST::ConstantItem &constant) override { - std::string identifier - = base_path.as_string () + "::" + constant.get_identifier (); + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - identifier, constant.get_node_id (), constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -60,11 +54,11 @@ public: void visit (AST::Function &function) override { - std::string identifier - = base_path.as_string () + "::" + function.get_function_name (); + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - identifier, function.get_node_id (), function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -75,11 +69,11 @@ public: void visit (AST::Method &method) override { - std::string identifier - = base_path.as_string () + "::" + method.get_method_name (); + auto path + = prefix.append (ResolveMethodItemToCanonicalPath::resolve (method)); resolver->get_name_scope ().insert ( - identifier, method.get_node_id (), method.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, method.get_node_id (), method.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (method.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -89,15 +83,13 @@ public: } private: - ResolveToplevelImplItem (AST::Type *base) - : ResolverBase (UNKNOWN_NODEID), base (base), - base_path (AST::SimplePath::create_empty ()) + ResolveToplevelImplItem (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) { - ResolveTypeToSimplePath::go (base, base_path, true); + rust_assert (!prefix.is_error ()); } - AST::Type *base; - AST::SimplePath base_path; + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 45d94db..9c19ce6 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -179,18 +179,21 @@ public: } } + bool canonicalize_type_with_generics = false; NodeId resolved_node = ResolveType::go (impl_block.get_type ().get (), - impl_block.get_node_id ()); + impl_block.get_node_id (), + canonicalize_type_with_generics); if (resolved_node == UNKNOWN_NODEID) return; + auto Self = CanonicalPath::get_big_self (); resolver->get_type_scope ().insert ( - "Self", resolved_node, impl_block.get_type ()->get_locus_slow ()); + Self, resolved_node, impl_block.get_type ()->get_locus_slow ()); for (auto &impl_item : impl_block.get_impl_items ()) impl_item->accept_vis (*this); - resolver->get_type_scope ().peek ()->clear_name ("Self", resolved_node); + resolver->get_type_scope ().peek ()->clear_name (Self, resolved_node); resolver->get_type_scope ().pop (); } diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 147bf72..0734908 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -33,7 +33,6 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { ResolvePattern resolver (parent); - pattern->accept_vis (resolver); if (resolver.resolved_node == UNKNOWN_NODEID) { @@ -42,12 +41,10 @@ public: } }; - ~ResolvePattern () {} - void visit (AST::IdentifierPattern &pattern) override { - if (resolver->get_name_scope ().lookup (pattern.get_ident (), - &resolved_node)) + if (resolver->get_name_scope ().lookup ( + CanonicalPath (pattern.get_ident ()), &resolved_node)) { resolver->insert_resolved_name (pattern.get_node_id (), resolved_node); resolver->insert_new_definition (pattern.get_node_id (), @@ -68,23 +65,14 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { PatternDeclaration resolver (parent); - pattern->accept_vis (resolver); - if (resolver.resolved_node != UNKNOWN_NODEID) - { - // print both locations?! - rust_error_at (resolver.locus, "duplicate pattern %s", - pattern->as_string ().c_str ()); - } }; - ~PatternDeclaration () {} - void visit (AST::IdentifierPattern &pattern) override { // if we have a duplicate id this then allows for shadowing correctly // as new refs to this decl will match back here so it is ok to overwrite - resolver->get_name_scope ().insert (pattern.get_ident (), + resolver->get_name_scope ().insert (CanonicalPath (pattern.get_ident ()), pattern.get_node_id (), pattern.get_locus ()); resolver->insert_new_definition (pattern.get_node_id (), diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index afc0068..2550c39 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -32,17 +32,19 @@ class ResolveTopLevel : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::Item *item) + static void go (AST::Item *item, + const CanonicalPath &prefix = CanonicalPath::create_empty ()) { - ResolveTopLevel resolver; + ResolveTopLevel resolver (prefix); item->accept_vis (resolver); }; void visit (AST::TypeAlias &alias) override { resolver->get_type_scope ().insert ( - alias.get_new_type_name (), alias.get_node_id (), alias.get_locus (), - false, [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (alias.get_new_type_name ()), alias.get_node_id (), + alias.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (alias.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -51,9 +53,9 @@ public: void visit (AST::TupleStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -62,9 +64,9 @@ public: void visit (AST::StructStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -73,8 +75,9 @@ public: void visit (AST::StaticItem &var) override { resolver->get_name_scope ().insert ( - var.get_identifier (), var.get_node_id (), var.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (var.get_identifier ()), var.get_node_id (), + var.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (var.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -86,10 +89,11 @@ public: void visit (AST::ConstantItem &constant) override { + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - constant.get_identifier (), constant.get_node_id (), - constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -100,10 +104,11 @@ public: void visit (AST::Function &function) override { + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - function.get_function_name (), function.get_node_id (), - function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -122,13 +127,24 @@ public: void visit (AST::InherentImpl &impl_block) override { + bool canonicalize_type_args = !impl_block.has_generics (); + bool type_resolve_generic_args = false; + CanonicalPath impl_type + = ResolveTypeToCanonicalPath::resolve (*impl_block.get_type ().get (), + canonicalize_type_args, + type_resolve_generic_args); + CanonicalPath impl_prefix = prefix.append (impl_type); + for (auto &impl_item : impl_block.get_impl_items ()) - ResolveToplevelImplItem::go (impl_item.get (), - impl_block.get_type ().get ()); + ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); } private: - ResolveTopLevel () : ResolverBase (UNKNOWN_NODEID) {} + ResolveTopLevel (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) + {} + + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 9e7568e..35e04a8 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -25,73 +25,136 @@ namespace Rust { namespace Resolver { -class ResolveTypeToSimplePath : public ResolverBase +class ResolveConstantItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::ConstantItem &constant) + { + return CanonicalPath (constant.get_identifier ()); + } +}; + +class ResolveFunctionItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Function &function) + { + return CanonicalPath (function.get_function_name ()); + } +}; + +class ResolveMethodItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Method &method) + { + return CanonicalPath (method.get_method_name ()); + } +}; + +class ResolveTypeToCanonicalPath : public ResolverBase { using Rust::Resolver::ResolverBase::visit; public: - static bool go (AST::Type *type, AST::SimplePath &simple_path_result, - bool path_only = false) + static CanonicalPath resolve (AST::Type &type, + bool include_generic_args = true, + bool type_resolve_generic_args = true) { - ResolveTypeToSimplePath resolver (simple_path_result, path_only); - type->accept_vis (resolver); - return !resolver.type_seg_failed_flag; + ResolveTypeToCanonicalPath resolver (include_generic_args, + type_resolve_generic_args); + type.accept_vis (resolver); + return resolver.result; } void visit (AST::TypePath &path) override { - segs.reserve (path.get_num_segments ()); for (auto &seg : path.get_segments ()) { seg->accept_vis (*this); - if (type_seg_failed_flag) + if (failure_flag) return; } - - if (segs.empty ()) - { - rust_error_at (path.get_locus (), "failed to resolve path: %s", - path.as_string ().c_str ()); - return; - } - - bool has_opening_scope_res = false; - result = AST::SimplePath (std::move (segs), has_opening_scope_res, - path.get_locus ()); } void visit (AST::TypePathSegmentGeneric &seg) override; void visit (AST::TypePathSegment &seg) override; + static CanonicalPath canonicalize_generic_args (AST::GenericArgs &args); + + static bool type_resolve_generic_args (AST::GenericArgs &args); + private: - ResolveTypeToSimplePath (AST::SimplePath &simple_path_result, bool path_only) - : ResolverBase (UNKNOWN_NODEID), type_seg_failed_flag (false), - result (simple_path_result), path_only_flag (path_only) + ResolveTypeToCanonicalPath (bool include_generic_args, + bool type_resolve_generic_args) + : ResolverBase (UNKNOWN_NODEID), result (CanonicalPath::create_empty ()), + include_generic_args_flag (include_generic_args), + type_resolve_generic_args_flag (type_resolve_generic_args), + failure_flag (false) {} - bool type_seg_failed_flag; - std::vector<AST::SimplePathSegment> segs; - AST::SimplePath &result; - bool path_only_flag; + CanonicalPath result; + bool include_generic_args_flag; + bool type_resolve_generic_args_flag; + bool failure_flag; +}; + +class ResolvePathSegmentToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::PathExprSegment &seg) + { + CanonicalPath path = CanonicalPath (seg.get_ident_segment ().as_string ()); + if (seg.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + seg.get_generic_args ()); + if (!ok) + { + rust_error_at (seg.get_locus (), + "failed to resolve all generic args"); + return CanonicalPath::create_empty (); + } + + path + = path.append (ResolveTypeToCanonicalPath::canonicalize_generic_args ( + seg.get_generic_args ())); + } + return path; + } }; -class ResolveTypePath +// FIXME: as part of imports and visibility we need to be able to keep a context +// for handling PathInExpressions segments as they can be local to a particular +// lexical scope requiring a context to be maintained for resolution +class ResolveRelativeTypePath { public: - static NodeId go (AST::TypePath &path, NodeId parent) + static NodeId go (AST::TypePath &path, NodeId parent, + const CanonicalPath &prefix, + bool canonicalize_type_with_generics) { - AST::SimplePath path_buffer = AST::SimplePath::create_empty (); - if (!ResolveTypeToSimplePath::go (&path, path_buffer)) - return UNKNOWN_NODEID; + CanonicalPath canonical_path + = ResolveTypeToCanonicalPath::resolve (path, + canonicalize_type_with_generics, + true); + if (canonical_path.is_error ()) + { + rust_error_at (path.get_locus (), "Failed to resolve canonical path"); + return UNKNOWN_NODEID; + } + + CanonicalPath lookup = canonical_path; + if (!prefix.is_error ()) + lookup = prefix.append (canonical_path); auto resolver = Resolver::get (); NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_type_scope ().lookup (path_buffer.as_string (), - &resolved_node)) + if (!resolver->get_type_scope ().lookup (canonical_path, &resolved_node)) { rust_error_at (path.get_locus_slow (), "failed to resolve TypePath: %s", - path_buffer.as_string ().c_str ()); + canonical_path.get ().c_str ()); return UNKNOWN_NODEID; } @@ -104,9 +167,10 @@ class ResolveType : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static NodeId go (AST::Type *type, NodeId parent) + static NodeId go (AST::Type *type, NodeId parent, + bool canonicalize_type_with_generics = false) { - ResolveType resolver (parent); + ResolveType resolver (parent, canonicalize_type_with_generics); type->accept_vis (resolver); if (!resolver.ok) rust_error_at (type->get_locus_slow (), "unresolved type"); @@ -139,7 +203,10 @@ public: void visit (AST::TypePath &path) override { - resolved_node = ResolveTypePath::go (path, parent); + resolved_node + = ResolveRelativeTypePath::go (path, parent, + CanonicalPath::create_empty (), + canonicalize_type_with_generics); ok = resolved_node != UNKNOWN_NODEID; if (ok) { @@ -160,12 +227,16 @@ public: type.get_type_referenced ()->accept_vis (*this); } - // nothing to do for inferred types void visit (AST::InferredType &type) override { ok = true; } private: - ResolveType (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveType (NodeId parent, bool canonicalize_type_with_generics) + : ResolverBase (parent), + canonicalize_type_with_generics (canonicalize_type_with_generics), + ok (false) + {} + bool canonicalize_type_with_generics; bool ok; }; @@ -190,9 +261,9 @@ public: // for now lets focus on handling the basics: like struct<T> { a:T, ....} resolver->get_type_scope ().insert ( - param.get_type_representation (), param.get_node_id (), + CanonicalPath (param.get_type_representation ()), param.get_node_id (), param.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (param.get_locus (), "generic param redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -200,7 +271,11 @@ public: } private: - ResolveGenericParam (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveGenericParam (NodeId parent) + : ResolverBase (parent), + + ok (false) + {} bool ok; }; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 4cc1a93..aac55e2 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -50,7 +50,8 @@ Resolver::Resolver () : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()), name_scope (Scope (mappings->get_current_crate ())), type_scope (Scope (mappings->get_current_crate ())), - label_scope (Scope (mappings->get_current_crate ())) + label_scope (Scope (mappings->get_current_crate ())), + global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID) { generate_builtins (); } @@ -116,9 +117,12 @@ Resolver::insert_builtin_types (Rib *r) { auto builtins = get_builtin_types (); for (auto &builtin : builtins) - r->insert_name (builtin->as_string (), builtin->get_node_id (), - Linemap::predeclared_location (), false, - [] (std::string, NodeId, Location) -> void {}); + { + CanonicalPath builtin_path (builtin->as_string ()); + r->insert_name (builtin_path, builtin->get_node_id (), + Linemap::predeclared_location (), false, + [] (const CanonicalPath &, NodeId, Location) -> void {}); + } } std::vector<AST::Type *> & @@ -374,41 +378,84 @@ ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field) // rust-ast-resolve-type.h -void -ResolveTypeToSimplePath::visit (AST::TypePathSegmentGeneric &seg) +CanonicalPath +ResolveTypeToCanonicalPath::canonicalize_generic_args (AST::GenericArgs &args) { - if (!path_only_flag) + std::string buf; + + size_t i = 0; + size_t total = args.get_type_args ().size (); + + for (auto &ty_arg : args.get_type_args ()) { - AST::GenericArgs &generics = seg.get_generic_args (); - for (auto > : generics.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); + buf += ty_arg->as_string (); + if ((i + 1) < total) + buf += ","; + + i++; } + return CanonicalPath ("<" + buf + ">"); +} + +bool +ResolveTypeToCanonicalPath::type_resolve_generic_args (AST::GenericArgs &args) +{ + for (auto > : args.get_type_args ()) + { + ResolveType::go (gt.get (), UNKNOWN_NODEID); + // FIXME error handling here for inference variable since they do not have + // a node to resolve to + // if (resolved == UNKNOWN_NODEID) return false; + } + return true; +} + +void +ResolveTypeToCanonicalPath::visit (AST::TypePathSegmentGeneric &seg) +{ if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + // ident seg + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); + + // generic args + if (seg.has_generic_args ()) + { + if (include_generic_args_flag) + result + = result.append (canonicalize_generic_args (seg.get_generic_args ())); + + if (type_resolve_generic_args_flag) + { + bool ok = type_resolve_generic_args (seg.get_generic_args ()); + failure_flag = !ok; + } + } } void -ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) +ResolveTypeToCanonicalPath::visit (AST::TypePathSegment &seg) { if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); } // rust-ast-resolve-expr.h @@ -416,38 +463,77 @@ ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) void ResolvePath::resolve_path (AST::PathInExpression *expr) { - // this needs extended similar to the TypePath to lookup each segment - // in turn then look its rib for the next segment and so forth until we - // resolve to a final NodeId generic args can be ignored - std::string path_buf; - for (auto &seg : expr->get_segments ()) + // resolve root segment first then apply segments in turn + AST::PathExprSegment &root_segment = expr->get_segments ().at (0); + AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment (); + + bool segment_is_type = false; + CanonicalPath root_seg_path (root_ident_seg.as_string ()); + + // name scope first + if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node)) { - auto s = seg.get_ident_segment (); - if (s.is_error () && !seg.has_generic_args ()) + segment_is_type = false; + resolver->insert_resolved_name (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = true; + resolver->insert_resolved_type (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + else + { + rust_error_at (expr->get_locus (), + "unknown root segment in path %s lookup %s", + expr->as_string ().c_str (), + root_ident_seg.as_string ().c_str ()); + return; + } + + if (root_segment.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + root_segment.get_generic_args ()); + if (!ok) { - rust_error_at (expr->get_locus (), "malformed path"); + rust_error_at (root_segment.get_locus (), + "failed to resolve generic args"); return; } + } - if (seg.has_generic_args ()) - { - AST::GenericArgs &args = seg.get_generic_args (); - for (auto > : args.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); - } + if (expr->is_single_segment ()) + { + if (segment_is_type) + resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + else + resolver->insert_resolved_name (expr->get_node_id (), resolved_node); - if (!s.is_error ()) - { - bool needs_sep = !path_buf.empty (); - if (needs_sep) - path_buf += "::"; + resolver->insert_new_definition (expr->get_node_id (), + Definition{expr->get_node_id (), + parent}); + return; + } - path_buf += s.as_string (); - } + // we can attempt to resolve this path fully + CanonicalPath path = root_seg_path; + for (size_t i = 1; i < expr->get_segments ().size (); i++) + { + AST::PathExprSegment &seg = expr->get_segments ().at (i); + auto s = ResolvePathSegmentToCanonicalPath::resolve (seg); + path = path.append (s); } - // name scope first - if (resolver->get_name_scope ().lookup (path_buf, &resolved_node)) + if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_name (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -455,7 +541,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) parent}); } // check the type scope - else if (resolver->get_type_scope ().lookup (path_buf, &resolved_node)) + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_type (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -464,8 +550,42 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } else { - rust_error_at (expr->get_locus (), "unknown path %s lookup %s", - expr->as_string ().c_str (), path_buf.c_str ()); + // attempt to fully resolve the path which is allowed to fail given the + // following scenario + // + // https://github.com/Rust-GCC/gccrs/issues/355 Paths are + // resolved fully here, there are limitations though imagine: + // + // struct Foo<A> (A); + // + // impl Foo<isize> { + // fn test() -> ... + // + // impl Foo<f32> { + // fn test() -> ... + // + // fn main() { + // let a:i32 = Foo::test(); + // + // there are multiple paths that test can resolve to Foo::<?>::test here + // so we cannot resolve this case + // + // canonical names: + // + // struct Foo<A> -> Foo + // impl Foo<isize>::fn test -> Foo::isize::test + // impl Foo<f32>::fn test -> Foo::f32::test + // + // Since there is the case we have the following paths for test: + // + // Foo::isize::test + // Foo::f32::test + // vs + // Foo::test + // + // but the lookup was simply Foo::test we must rely on type resolution to + // figure this type out in a similar fashion to method resolution with a + // probe phase } } diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h index b607fbe..13b6c91 100644 --- a/gcc/rust/resolve/rust-ast-verify-assignee.h +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -57,7 +57,8 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (!resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (!resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) return; ok = true; diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h index 9c01d47..205c877 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -26,6 +26,62 @@ namespace Rust { namespace Resolver { +// https://doc.rust-lang.org/reference/paths.html#canonical-paths +// +// struct X - path X +// impl X { fn test - path X::test } +// +// struct X<T> - path X +// +// impl X<T> { fn test - path X::test} +// impl X<i32> { fn test - path X<i32>::test } +// impl X<f32> { fn test - path X<f32>::test } +class CanonicalPath +{ +public: + explicit CanonicalPath (std::string path) : path (path) {} + + CanonicalPath (const CanonicalPath &other) : path (other.path) {} + + CanonicalPath &operator= (const CanonicalPath &other) + { + path = other.path; + return *this; + } + + std::string get () const { return path; } + + static CanonicalPath get_big_self () { return CanonicalPath ("Self"); } + + static CanonicalPath get_wee_self () { return CanonicalPath ("self"); } + + static CanonicalPath create_empty () + { + return CanonicalPath (std::string ()); + } + + bool is_error () const { return path.empty (); } + + CanonicalPath append (const CanonicalPath &other) const + { + rust_assert (!other.is_error ()); + return is_error () ? CanonicalPath (other.get ()) + : CanonicalPath (append (other.get ())); + } + + bool operator== (const CanonicalPath &b) const + { + return get ().compare (b.get ()) == 0; + } + + bool operator< (const CanonicalPath &b) const { return get () < b.get (); } + +private: + std::string append (std::string elem) const { return path + "::" + elem; } + + std::string path; +}; + class Rib { public: @@ -37,10 +93,11 @@ public: ~Rib () {} - void insert_name (std::string ident, NodeId id, Location locus, bool shadow, - std::function<void (std::string, NodeId, Location)> dup_cb) + void insert_name ( + const CanonicalPath &path, NodeId id, Location locus, bool shadow, + std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb) { - auto it = mappings.find (ident); + auto it = mappings.find (path); bool already_exists = it != mappings.end (); if (already_exists && !shadow) { @@ -48,20 +105,20 @@ public: { if (decl.first == it->second) { - dup_cb (ident, it->second, decl.second); + dup_cb (path, it->second, decl.second); return; } } - dup_cb (ident, it->second, locus); + dup_cb (path, it->second, locus); return; } - mappings[ident] = id; + mappings[path] = id; decls_within_rib.insert (std::pair<NodeId, Location> (id, locus)); references[id] = {}; } - bool lookup_name (std::string ident, NodeId *id) + bool lookup_name (const CanonicalPath &ident, NodeId *id) { auto it = mappings.find (ident); if (it == mappings.end ()) @@ -71,7 +128,7 @@ public: return true; } - void clear_name (std::string ident, NodeId id) + void clear_name (const CanonicalPath &ident, NodeId id) { mappings.erase (ident); for (auto &it : decls_within_rib) @@ -136,7 +193,7 @@ public: private: CrateNum crate_num; NodeId node_id; - std::map<std::string, NodeId> mappings; + std::map<CanonicalPath, NodeId> mappings; std::set<std::pair<NodeId, Location> > decls_within_rib; std::map<NodeId, std::set<NodeId> > references; }; @@ -145,21 +202,24 @@ class Scope { public: Scope (CrateNum crate_num) : crate_num (crate_num) {} + ~Scope () {} - void insert (std::string ident, NodeId id, Location locus, bool shadow, - std::function<void (std::string, NodeId, Location)> dup_cb) + void + insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb) { peek ()->insert_name (ident, id, locus, shadow, dup_cb); } - void insert (std::string ident, NodeId id, Location locus) + void insert (const CanonicalPath &ident, NodeId id, Location locus) { peek ()->insert_name (ident, id, locus, true, - [] (std::string, NodeId, Location) -> void {}); + [] (const CanonicalPath &, NodeId, Location) -> void { + }); } - bool lookup (std::string ident, NodeId *id) + bool lookup (const CanonicalPath &ident, NodeId *id) { NodeId lookup = UNKNOWN_NODEID; iterate ([&] (Rib *r) mutable -> bool { diff --git a/gcc/rust/typecheck/rust-hir-method-resolve.h b/gcc/rust/typecheck/rust-hir-method-resolve.h index ca5dbe5..35a5502 100644 --- a/gcc/rust/typecheck/rust-hir-method-resolve.h +++ b/gcc/rust/typecheck/rust-hir-method-resolve.h @@ -40,7 +40,8 @@ public: // lookup impl items for this crate and find all methods that can resolve to // this receiver probe.mappings->iterate_impl_items ( - [&] (HirId id, HIR::InherentImplItem *item) mutable -> bool { + [&] (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) mutable -> bool { item->accept_vis (probe); return true; }); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 6e7dff8..b946812 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -25,6 +25,7 @@ #include "rust-tyty-call.h" #include "rust-hir-type-check-struct-field.h" #include "rust-hir-method-resolve.h" +#include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" namespace Rust { @@ -171,8 +172,6 @@ public: { TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr (), false); - if (function_tyty == nullptr) - return; bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT || function_tyty->get_kind () == TyTy::TypeKind::FNDEF @@ -759,80 +758,93 @@ public: void visit (HIR::PathInExpression &expr) override { - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + // resolve root_segment + TyTy::BaseType *tyseg = resolve_root_path (expr); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + else if (expr.get_num_segments () == 1) + { + infered = tyseg; + return; + } - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + NodeId resolved_node_id = UNKNOWN_NODEID; + for (size_t i = 1; i < expr.get_num_segments (); i++) { - // these ref_node_ids will resolve to a pattern declaration but we are - // interested in the definition that this refers to get the parent id - Definition def; - if (!resolver->lookup_definition (ref_node_id, &def)) + HIR::PathExprSegment &seg = expr.get_segments ().at (i); + + // probe the path + auto candidates = PathProbeType::Probe (tyseg, seg.get_segment ()); + if (candidates.size () == 0) { - rust_error_at (expr.get_locus (), - "unknown reference for resolved name"); + rust_error_at (seg.get_locus (), "failed to resolve path segment"); + return; + } + else if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg.get_segment (), + seg.get_locus ()); return; } - ref_node_id = def.parent; - } - else if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup type reference for node: %s", - expr.as_string ().c_str ()); - return; - } - if (ref_node_id == UNKNOWN_NODEID) - { - rust_error_at (expr.get_locus (), "unresolved node: %s", - expr.as_string ().c_str ()); - return; - } + auto candidate = candidates.at (0); + tyseg = candidate.ty; + resolved_node_id + = candidate.impl_item->get_impl_mappings ().get_nodeid (); - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; + bool did_substitute = false; + if (seg.has_generic_args ()) + { + if (!tyseg->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + tyseg->as_string ().c_str ()); + return; + } + + did_substitute = true; + tyseg = SubstMapper::Resolve (tyseg, expr.get_locus (), + &seg.get_generic_args ()); + + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else + { + if (tyseg->needs_generic_substitutions ()) + { + did_substitute = true; + tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ()); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + } } - if (!context->lookup_type (ref, &infered)) + rust_assert (resolved_node_id != UNKNOWN_NODEID); + + // lookup if the name resolver was able to canonically resolve this or not + NodeId path_resolved_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "failed to resolve PathInExpression type"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!infered->supports_substitutions () && seg.has_generic_args ()) + // check the type scope + else if (resolver->lookup_resolved_type (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "path does not support substitutions"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - if (expr.is_self ()) - return; - - if (infered->has_subsititions_defined ()) + else { - if (!infered->can_substitute ()) - { - rust_error_at (expr.get_locus (), - "substitutions not supported for %s", - infered->as_string ().c_str ()); - return; - } - - infered = SubstMapper::Resolve (infered, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); } + + infered = tyseg; } void visit (HIR::LoopExpr &expr) override @@ -951,6 +963,75 @@ private: inside_loop (inside_loop) {} + TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr) + { + HIR::PathExprSegment &root = expr.get_root_seg (); + NodeId ast_node_id = root.get_mappings ().get_nodeid (); + + // then lookup the reference_node_id + NodeId ref_node_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + // these ref_node_ids will resolve to a pattern declaration but we are + // interested in the definition that this refers to get the parent id + Definition def; + if (!resolver->lookup_definition (ref_node_id, &def)) + { + rust_error_at (expr.get_locus (), + "unknown reference for resolved name"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + ref_node_id = def.parent; + } + else + { + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + } + + if (ref_node_id == UNKNOWN_NODEID) + { + rust_error_at (root.get_locus (), + "failed to type resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // node back to HIR + HirId ref; + if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), + ref_node_id, &ref)) + { + rust_error_at (expr.get_locus (), "reverse lookup failure"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + TyTy::BaseType *lookup = nullptr; + if (!context->lookup_type (ref, &lookup)) + { + rust_error_at (expr.get_locus (), "failed to resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // turbo-fish segment path::<ty> + if (root.has_generic_args ()) + { + if (!lookup->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + lookup->as_string ().c_str ()); + return new TyTy::ErrorType (lookup->get_ref ()); + } + lookup = SubstMapper::Resolve (lookup, expr.get_locus (), + &root.get_generic_args ()); + } + else if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); + } + + return lookup; + } + bool validate_arithmetic_type (TyTy::BaseType *type, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 68becd4..e52368a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -58,7 +58,7 @@ public: { init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr (), inside_loop); - if (init_expr_ty == nullptr) + if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; init_expr_ty = init_expr_ty->clone (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index 3a6cdc7..8124f35 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -41,8 +41,6 @@ public: void visit (HIR::StructExprStructFields &struct_expr) override; - void visit (HIR::PathInExpression &path) override; - void visit (HIR::StructExprFieldIdentifierValue &field) override; void visit (HIR::StructExprFieldIndexValue &field) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 681fb24..6f6ab9c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -60,6 +60,7 @@ TypeResolution::Resolve (HIR::Crate &crate) // nothing to do if (ty->get_kind () != TyTy::TypeKind::INFER) return true; + TyTy::InferType *infer_var = (TyTy::InferType *) ty; TyTy::BaseType *default_type; bool ok = infer_var->default_type (&default_type); @@ -72,6 +73,7 @@ TypeResolution::Resolve (HIR::Crate &crate) UNKNOWN_LOCAL_DEFID), result); } + return true; }); @@ -161,14 +163,16 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) void TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) { - struct_expr.get_struct_name ().accept_vis (*this); - if (struct_path_resolved == nullptr) + TyTy::BaseType *struct_path_ty + = TypeCheckExpr::Resolve (&struct_expr.get_struct_name (), false); + if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT) { - rust_fatal_error (struct_expr.get_struct_name ().get_locus (), - "Failed to resolve type"); + rust_error_at (struct_expr.get_struct_name ().get_locus (), + "expected an ADT type for constructor"); return; } + struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty); TyTy::ADTType *struct_def = struct_path_resolved; if (struct_expr.has_struct_base ()) { @@ -292,78 +296,6 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) } void -TypeCheckStructExpr::visit (HIR::PathInExpression &expr) -{ - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); - - // then lookup the reference_node_id - NodeId ref_node_id; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup reference for node: %s", - expr.as_string ().c_str ()); - return; - } - } - - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; - } - - // the base reference for this name _must_ have a type set - TyTy::BaseType *lookup; - if (!context->lookup_type (ref, &lookup)) - { - rust_error_at (mappings->lookup_location (ref), - "consider giving this a type: %s", - expr.as_string ().c_str ()); - return; - } - - if (lookup->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected an ADT type"); - return; - } - - struct_path_resolved = static_cast<TyTy::ADTType *> (lookup); - if (struct_path_resolved->has_substitutions ()) - { - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!struct_path_resolved->needs_substitution () - && seg.has_generic_args ()) - { - rust_error_at (seg.get_generic_args ().get_locus (), - "unexpected type arguments"); - } - else if (struct_path_resolved->needs_substitution ()) - { - TyTy::BaseType *subst - = SubstMapper::Resolve (struct_path_resolved, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); - if (subst == nullptr || subst->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected a substituted ADT type"); - return; - } - struct_path_resolved = static_cast<TyTy::ADTType *> (subst); - } - } -} - -void TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) { auto it = fields_assigned.find (field.field_name); diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index d449c72..db43cbd 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -37,6 +37,11 @@ public: return mapper.resolved; } + static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus) + { + return SubstMapper::Resolve (base, locus, nullptr); + } + bool have_generic_args () const { return generics != nullptr; } void visit (TyTy::FnType &type) override diff --git a/gcc/testsuite/rust.test/compile/generics13.rs b/gcc/testsuite/rust.test/compile/generics13.rs new file mode 100644 index 0000000..03d6cee --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics13.rs @@ -0,0 +1,34 @@ +struct Foo<A> { + a: A, +} + +struct GenericStruct<T> { + a: T, + b: usize, +} + +impl Foo<isize> { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); + + let a2: GenericStruct<i8>; + a2 = GenericStruct::<i8> { a: 1, b: 456 }; + + let b2: i8 = a2.a; + let c2: usize = a2.b; + + let a4; + a4 = GenericStruct { a: 1.0, b: 456 }; + + let b4: f32 = a4.a; + let c4: usize = a4.b; +} diff --git a/gcc/testsuite/rust.test/compile/generics14.rs b/gcc/testsuite/rust.test/compile/generics14.rs new file mode 100644 index 0000000..bf00f72 --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics14.rs @@ -0,0 +1,17 @@ +struct Foo<A> { + a: A, +} + +impl Foo<isize> { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); +} diff --git a/gcc/testsuite/rust.test/xfail_compile/generics6.rs b/gcc/testsuite/rust.test/xfail_compile/generics6.rs new file mode 100644 index 0000000..256d2aa --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/generics6.rs @@ -0,0 +1,29 @@ +// { dg-excess-errors "Noisy error and debug" } +struct Foo<A> { + a: A, +} + +impl Foo<isize> { + fn test() -> i32 { // {dg-error "possible candidate" } + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +impl Foo<f32> { + fn test() -> i32 { // {dg-error "possible candidate" } + 123 + } + + fn bar(self) -> f32 { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); // { dg-error "multiple applicable items in scope for: test" } +} + diff --git a/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs new file mode 100644 index 0000000..3856b73 --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs @@ -0,0 +1,14 @@ +// { dg-excess-errors "Noisy error and debug" } +struct Foo<T>(T, usize); + +impl Foo<i32> { + fn test() -> i32 { // { dg-error "was defined here" } + 123 + } + + fn test(self) -> i32 { // { dg-error "redefined multiple times" } + self.0 + } +} + +fn main() {} |