diff options
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() {} |