aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h25
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-implitem.h44
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h9
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.h18
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h54
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h159
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc210
-rw-r--r--gcc/rust/resolve/rust-ast-verify-assignee.h3
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h88
-rw-r--r--gcc/rust/typecheck/rust-hir-method-resolve.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h203
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct-field.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc84
-rw-r--r--gcc/rust/typecheck/rust-substitution-mapper.h5
-rw-r--r--gcc/testsuite/rust.test/compile/generics13.rs34
-rw-r--r--gcc/testsuite/rust.test/compile/generics14.rs17
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/generics6.rs29
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/redef_error6.rs14
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 &gt : 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 &gt : 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 &gt : 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() {}