aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-08-22 13:59:00 +0000
committerGitHub <noreply@github.com>2021-08-22 13:59:00 +0000
commitac3be517de2c0ec596eeee754b863243cb071098 (patch)
tree9bef8c57466f78db9fd8444f33ed854c24187d16
parente9746f445cf57c12f70d0016722835ec504cc655 (diff)
parent5a0e34b74aa6de092632bad2bee4883c5a23e036 (diff)
downloadgcc-ac3be517de2c0ec596eeee754b863243cb071098.zip
gcc-ac3be517de2c0ec596eeee754b863243cb071098.tar.gz
gcc-ac3be517de2c0ec596eeee754b863243cb071098.tar.bz2
Merge #640
640: Optional Trait items constants r=philberty a=philberty This adds more support for optional trait items such as constants. Some fixes come along with this PR such as improved query-based compilation for trait items which is now a canonical implementation for qualified and normal paths in HIR. Co-authored-by: Philip Herron <philip.herron@embecosm.com>
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/backend/rust-compile-implitem.h98
-rw-r--r--gcc/rust/backend/rust-compile-item.h48
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.cc293
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.h11
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc3
-rw-r--r--gcc/rust/typecheck/rust-hir-path-probe.h32
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-ref.h7
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc22
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.h40
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h434
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-path.cc452
-rw-r--r--gcc/testsuite/rust/execute/torture/trait2.rs37
13 files changed, 871 insertions, 607 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 7ed380e..9c69b44 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -84,6 +84,7 @@ GRS_OBJS = \
rust/rust-hir-trait-resolve.o \
rust/rust-hir-const-fold.o \
rust/rust-lint-marklive.o \
+ rust/rust-hir-type-check-path.o \
$(END)
# removed object files from here
diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h
index 7337154..bdeda22 100644
--- a/gcc/rust/backend/rust-compile-implitem.h
+++ b/gcc/rust/backend/rust-compile-implitem.h
@@ -34,11 +34,25 @@ class CompileInherentImplItem : public HIRCompileBase
using Rust::Compile::HIRCompileBase::visit;
public:
- static void Compile (TyTy::BaseType *self, HIR::ImplItem *item, Context *ctx,
- bool compile_fns, TyTy::BaseType *concrete = nullptr)
+ static Bexpression *Compile (TyTy::BaseType *self, HIR::ImplItem *item,
+ Context *ctx, bool compile_fns,
+ TyTy::BaseType *concrete = nullptr,
+ bool is_query_mode = false,
+ Location ref_locus = Location ())
{
- CompileInherentImplItem compiler (self, ctx, compile_fns, concrete);
+ CompileInherentImplItem compiler (self, ctx, compile_fns, concrete,
+ ref_locus);
item->accept_vis (compiler);
+
+ if (is_query_mode
+ && ctx->get_backend ()->is_error_expression (compiler.reference))
+ {
+ rust_error_at (ref_locus, "failed to compile impl item: %s",
+ item->as_string ().c_str ());
+ rust_assert (
+ !ctx->get_backend ()->is_error_expression (compiler.reference));
+ }
+ return compiler.reference;
}
void visit (HIR::ConstantItem &constant) override
@@ -63,6 +77,8 @@ public:
ctx->push_const (const_expr);
ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr);
+
+ reference = const_expr;
}
void visit (HIR::Function &function) override
@@ -104,8 +120,13 @@ public:
{
Bfunction *dummy = nullptr;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
- ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype);
-
+ {
+ ctx->insert_function_decl (fntype->get_ty_ref (), lookup,
+ fntype);
+ }
+ reference
+ = ctx->get_backend ()->function_code_expression (lookup,
+ ref_locus);
return;
}
}
@@ -281,20 +302,25 @@ public:
}
ctx->pop_fn ();
-
ctx->push_function (fndecl);
+
+ reference
+ = ctx->get_backend ()->function_code_expression (fndecl, ref_locus);
}
private:
CompileInherentImplItem (TyTy::BaseType *self, Context *ctx, bool compile_fns,
- TyTy::BaseType *concrete)
+ TyTy::BaseType *concrete, Location ref_locus)
: HIRCompileBase (ctx), self (self), compile_fns (compile_fns),
- concrete (concrete)
+ concrete (concrete), reference (ctx->get_backend ()->error_expression ()),
+ ref_locus (ref_locus)
{}
TyTy::BaseType *self;
bool compile_fns;
TyTy::BaseType *concrete;
+ Bexpression *reference;
+ Location ref_locus;
};
class CompileTraitItem : public HIRCompileBase
@@ -302,11 +328,47 @@ class CompileTraitItem : public HIRCompileBase
using Rust::Compile::HIRCompileBase::visit;
public:
- static void Compile (TyTy::BaseType *self, HIR::TraitItem *item, Context *ctx,
- TyTy::BaseType *concrete)
+ static Bexpression *Compile (TyTy::BaseType *self, HIR::TraitItem *item,
+ Context *ctx, TyTy::BaseType *concrete,
+ bool is_query_mode = false,
+ Location ref_locus = Location ())
{
- CompileTraitItem compiler (self, ctx, concrete);
+ CompileTraitItem compiler (self, ctx, concrete, ref_locus);
item->accept_vis (compiler);
+
+ if (is_query_mode
+ && ctx->get_backend ()->is_error_expression (compiler.reference))
+ {
+ rust_error_at (ref_locus, "failed to compile trait item: %s",
+ item->as_string ().c_str ());
+ rust_assert (
+ !ctx->get_backend ()->is_error_expression (compiler.reference));
+ }
+ return compiler.reference;
+ }
+
+ void visit (HIR::TraitItemConst &constant) override
+ {
+ rust_assert (concrete != nullptr);
+ TyTy::BaseType *resolved_type = concrete;
+
+ ::Btype *type = TyTyResolveCompile::compile (ctx, resolved_type);
+ Bexpression *value
+ = CompileExpr::Compile (constant.get_expr ().get (), ctx);
+
+ const Resolver::CanonicalPath *canonical_path = nullptr;
+ rust_assert (ctx->get_mappings ()->lookup_canonical_path (
+ constant.get_mappings ().get_crate_num (),
+ constant.get_mappings ().get_nodeid (), &canonical_path));
+
+ std::string ident = canonical_path->get ();
+ Bexpression *const_expr = ctx->get_backend ()->named_constant_expression (
+ type, constant.get_name (), value, constant.get_locus ());
+
+ ctx->push_const (const_expr);
+ ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr);
+
+ reference = const_expr;
}
void visit (HIR::TraitItemFunc &func) override
@@ -330,6 +392,9 @@ public:
ctx->insert_function_decl (fntype->get_ty_ref (), lookup,
fntype);
}
+ reference
+ = ctx->get_backend ()->function_code_expression (lookup,
+ ref_locus);
return;
}
}
@@ -499,16 +564,23 @@ public:
ctx->pop_fn ();
ctx->push_function (fndecl);
+
+ reference
+ = ctx->get_backend ()->function_code_expression (fndecl, ref_locus);
}
private:
CompileTraitItem (TyTy::BaseType *self, Context *ctx,
- TyTy::BaseType *concrete)
- : HIRCompileBase (ctx), self (self), concrete (concrete)
+ TyTy::BaseType *concrete, Location ref_locus)
+ : HIRCompileBase (ctx), self (self), concrete (concrete),
+ reference (ctx->get_backend ()->error_expression ()),
+ ref_locus (ref_locus)
{}
TyTy::BaseType *self;
TyTy::BaseType *concrete;
+ Bexpression *reference;
+ Location ref_locus;
};
} // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index af0bc43..eb7d9ef 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -33,14 +33,28 @@ namespace Compile {
class CompileItem : public HIRCompileBase
{
+protected:
using Rust::Compile::HIRCompileBase::visit;
public:
- static void compile (HIR::Item *item, Context *ctx, bool compile_fns = true,
- TyTy::BaseType *concrete = nullptr)
+ static Bexpression *compile (HIR::Item *item, Context *ctx,
+ bool compile_fns = true,
+ TyTy::BaseType *concrete = nullptr,
+ bool is_query_mode = false,
+ Location ref_locus = Location ())
{
- CompileItem compiler (ctx, compile_fns, concrete);
+ CompileItem compiler (ctx, compile_fns, concrete, ref_locus);
item->accept_vis (compiler);
+
+ if (is_query_mode
+ && ctx->get_backend ()->is_error_expression (compiler.reference))
+ {
+ rust_error_at (ref_locus, "failed to compile item: %s",
+ item->as_string ().c_str ());
+ rust_assert (
+ !ctx->get_backend ()->is_error_expression (compiler.reference));
+ }
+ return compiler.reference;
}
void visit (HIR::StaticItem &var) override
@@ -73,6 +87,8 @@ public:
ctx->insert_var_decl (var.get_mappings ().get_hirid (), static_global);
ctx->push_var (static_global);
+
+ reference = ctx->get_backend ()->var_expression (static_global, ref_locus);
}
void visit (HIR::ConstantItem &constant) override
@@ -98,6 +114,8 @@ public:
ctx->push_const (const_expr);
ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr);
+
+ reference = const_expr;
}
void visit (HIR::Function &function) override
@@ -139,8 +157,14 @@ public:
{
Bfunction *dummy = nullptr;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
- ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype);
-
+ {
+ ctx->insert_function_decl (fntype->get_ty_ref (), lookup,
+ fntype);
+ }
+
+ reference
+ = ctx->get_backend ()->function_code_expression (lookup,
+ ref_locus);
return;
}
}
@@ -287,6 +311,9 @@ public:
ctx->pop_fn ();
ctx->push_function (fndecl);
+
+ reference
+ = ctx->get_backend ()->function_code_expression (fndecl, ref_locus);
}
void visit (HIR::ImplBlock &impl_block) override
@@ -319,13 +346,18 @@ public:
CompileItem::compile (item.get (), ctx, compile_fns);
}
-private:
- CompileItem (Context *ctx, bool compile_fns, TyTy::BaseType *concrete)
- : HIRCompileBase (ctx), compile_fns (compile_fns), concrete (concrete)
+protected:
+ CompileItem (Context *ctx, bool compile_fns, TyTy::BaseType *concrete,
+ Location ref_locus)
+ : HIRCompileBase (ctx), compile_fns (compile_fns), concrete (concrete),
+ reference (ctx->get_backend ()->error_expression ()),
+ ref_locus (ref_locus)
{}
bool compile_fns;
TyTy::BaseType *concrete;
+ Bexpression *reference;
+ Location ref_locus;
};
} // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
index 1539378..98c04df 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -29,18 +29,18 @@ namespace Compile {
void
ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr)
{
- resolve (expr.get_final_segment ().get_segment (), expr.get_mappings (),
- expr.get_locus (), true);
+ resolved = resolve (expr.get_final_segment ().get_segment (),
+ expr.get_mappings (), expr.get_locus (), true);
}
void
ResolvePathRef::visit (HIR::PathInExpression &expr)
{
- resolve (expr.get_final_segment ().get_segment (), expr.get_mappings (),
- expr.get_locus (), false);
+ resolved = resolve (expr.get_final_segment ().get_segment (),
+ expr.get_mappings (), expr.get_locus (), false);
}
-void
+Bexpression *
ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
const Analysis::NodeMapping &mappings,
Location expr_locus, bool is_qualified_path)
@@ -54,7 +54,7 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
if (!ctx->get_resolver ()->lookup_definition (ref_node_id, &def))
{
rust_error_at (expr_locus, "unknown reference for resolved name");
- return;
+ return ctx->get_backend ()->error_expression ();
}
ref_node_id = def.parent;
}
@@ -62,167 +62,165 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
// this can fail because it might be a Constructor for something
// in that case the caller should attempt ResolvePathType::Compile
if (ref_node_id == UNKNOWN_NODEID)
- return;
+ {
+ rust_error_at (expr_locus, "unknown nodeid for path expr");
+ return ctx->get_backend ()->error_expression ();
+ }
HirId ref;
if (!ctx->get_mappings ()->lookup_node_to_hir (mappings.get_crate_num (),
ref_node_id, &ref))
{
rust_error_at (expr_locus, "reverse call path lookup failure");
- return;
+ return ctx->get_backend ()->error_expression ();
}
// might be a constant
- if (ctx->lookup_const_decl (ref, &resolved))
- return;
+ Bexpression *constant_expr;
+ if (ctx->lookup_const_decl (ref, &constant_expr))
+ return constant_expr;
// this might be a variable reference or a function reference
Bvariable *var = nullptr;
if (ctx->lookup_var_decl (ref, &var))
- {
- resolved = ctx->get_backend ()->var_expression (var, expr_locus);
- return;
- }
+ return ctx->get_backend ()->var_expression (var, expr_locus);
- // must be a function call but it might be a generic function which needs to
- // be compiled first
+ // it might be a function call
TyTy::BaseType *lookup = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
rust_assert (ok);
- rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+ if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+ Bfunction *fn = nullptr;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
+ {
+ return ctx->get_backend ()->function_code_expression (fn, expr_locus);
+ }
+ }
+
+ // let the query system figure it out
+ return query_compile (ref, lookup, final_segment, mappings, expr_locus,
+ is_qualified_path);
+}
- Bfunction *fn = nullptr;
- if (!ctx->lookup_function_decl (lookup->get_ty_ref (), &fn))
+Bexpression *
+ResolvePathRef::query_compile (HirId ref, TyTy::BaseType *lookup,
+ const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings,
+ Location expr_locus, bool is_qualified_path)
+{
+ HIR::Item *resolved_item
+ = ctx->get_mappings ()->lookup_hir_item (mappings.get_crate_num (), ref);
+ bool is_hir_item = resolved_item != nullptr;
+ if (is_hir_item)
+ {
+ if (!lookup->has_subsititions_defined ())
+ return CompileItem::compile (resolved_item, ctx, true, nullptr, true,
+ expr_locus);
+ else
+ return CompileItem::compile (resolved_item, ctx, true, lookup, true,
+ expr_locus);
+ }
+ else
{
- // it must resolve to some kind of HIR::Item or HIR::InheritImplItem
- HIR::Item *resolved_item
- = ctx->get_mappings ()->lookup_hir_item (mappings.get_crate_num (),
- ref);
- if (resolved_item != nullptr)
+ HirId parent_impl_id = UNKNOWN_HIRID;
+ HIR::ImplItem *resolved_item
+ = ctx->get_mappings ()->lookup_hir_implitem (mappings.get_crate_num (),
+ ref, &parent_impl_id);
+ bool is_impl_item = resolved_item != nullptr;
+ if (is_impl_item)
{
+ rust_assert (parent_impl_id != UNKNOWN_HIRID);
+ HIR::Item *impl_ref
+ = ctx->get_mappings ()->lookup_hir_item (mappings.get_crate_num (),
+ parent_impl_id);
+ rust_assert (impl_ref != nullptr);
+ HIR::ImplBlock *impl = static_cast<HIR::ImplBlock *> (impl_ref);
+
+ TyTy::BaseType *self = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ impl->get_type ()->get_mappings ().get_hirid (), &self);
+ rust_assert (ok);
+
if (!lookup->has_subsititions_defined ())
- CompileItem::compile (resolved_item, ctx);
+ return CompileInherentImplItem::Compile (self, resolved_item, ctx,
+ true, nullptr, true,
+ expr_locus);
else
- CompileItem::compile (resolved_item, ctx, true, lookup);
+ return CompileInherentImplItem::Compile (self, resolved_item, ctx,
+ true, lookup, true,
+ expr_locus);
}
else
{
- HirId parent_impl_id = UNKNOWN_HIRID;
- HIR::ImplItem *resolved_item
- = ctx->get_mappings ()->lookup_hir_implitem (
- mappings.get_crate_num (), ref, &parent_impl_id);
-
- if (resolved_item == nullptr)
+ // it might be resolved to a trait item
+ HIR::TraitItem *trait_item
+ = ctx->get_mappings ()->lookup_hir_trait_item (
+ mappings.get_crate_num (), ref);
+ HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping (
+ trait_item->get_mappings ().get_hirid ());
+
+ Resolver::TraitReference *trait_ref
+ = &Resolver::TraitReference::error_node ();
+ bool ok = ctx->get_tyctx ()->lookup_trait_reference (
+ trait->get_mappings ().get_defid (), &trait_ref);
+ rust_assert (ok);
+
+ TyTy::BaseType *receiver = nullptr;
+ ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
+ &receiver);
+ rust_assert (ok);
+
+ if (receiver->get_kind () == TyTy::TypeKind::PARAM)
{
- // it might be resolved to a trait item
- HIR::TraitItem *trait_item
- = ctx->get_mappings ()->lookup_hir_trait_item (
- mappings.get_crate_num (), ref);
- HIR::Trait *trait
- = ctx->get_mappings ()->lookup_trait_item_mapping (
- trait_item->get_mappings ().get_hirid ());
-
- Resolver::TraitReference *trait_ref
- = &Resolver::TraitReference::error_node ();
- bool ok = ctx->get_tyctx ()->lookup_trait_reference (
- trait->get_mappings ().get_defid (), &trait_ref);
- rust_assert (ok);
-
- TyTy::BaseType *receiver = nullptr;
- ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
- &receiver);
- rust_assert (ok);
+ TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
+ receiver = p->resolve ();
+ }
- if (receiver->get_kind () == TyTy::TypeKind::PARAM)
- {
- TyTy::ParamType *p
- = static_cast<TyTy::ParamType *> (receiver);
- receiver = p->resolve ();
- }
-
- // the type resolver can only resolve type bounds to their trait
- // item so its up to us to figure out if this path should resolve
- // to an trait-impl-block-item or if it can be defaulted to the
- // trait-impl-item's definition
- std::vector<Resolver::PathProbeCandidate> candidates;
- if (!is_qualified_path)
- {
- candidates
- = Resolver::PathProbeType::Probe (receiver, final_segment,
- true, false, true);
- }
-
- if (candidates.size () == 0)
- {
- // this means we are defaulting back to the trait_item if
- // possible
- Resolver::TraitItemReference *trait_item_ref = nullptr;
- bool ok = trait_ref->lookup_hir_trait_item (*trait_item,
- &trait_item_ref);
- rust_assert (ok); // found
- rust_assert (
- trait_item_ref->is_optional ()); // has definition
-
- Analysis::NodeMapping trait_mappings
- = trait_item_ref->get_parent_trait_mappings ();
- auto associated_impl_id
- = ctx->get_tyctx ()
- ->lookup_associated_impl_mapping_for_self (
- trait_mappings.get_hirid (), receiver);
-
- rust_assert (associated_impl_id != UNKNOWN_HIRID);
-
- Resolver::AssociatedImplTrait *associated = nullptr;
- bool found_associated_trait_impl
- = ctx->get_tyctx ()->lookup_associated_trait_impl (
- associated_impl_id, &associated);
- rust_assert (found_associated_trait_impl);
- associated->setup_associated_types ();
-
- CompileTraitItem::Compile (
- receiver, trait_item_ref->get_hir_trait_item (), ctx,
- fntype);
-
- if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
- {
- resolved = ctx->get_backend ()->error_expression ();
- rust_error_at (expr_locus,
- "forward declaration was not compiled");
- return;
- }
- }
- else
- {
- Resolver::PathProbeCandidate &candidate = candidates.at (0);
- rust_assert (candidate.is_impl_candidate ());
-
- HIR::ImplBlock *impl = candidate.item.impl.parent;
- HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
-
- TyTy::BaseType *self = nullptr;
- bool ok = ctx->get_tyctx ()->lookup_type (
- impl->get_type ()->get_mappings ().get_hirid (), &self);
- rust_assert (ok);
-
- if (!lookup->has_subsititions_defined ())
- CompileInherentImplItem::Compile (self, impl_item, ctx,
- true);
- else
- CompileInherentImplItem::Compile (self, impl_item, ctx,
- true, lookup);
-
- lookup->set_ty_ref (
- impl_item->get_impl_mappings ().get_hirid ());
- }
+ // the type resolver can only resolve type bounds to their trait
+ // item so its up to us to figure out if this path should resolve
+ // to an trait-impl-block-item or if it can be defaulted to the
+ // trait-impl-item's definition
+ std::vector<Resolver::PathProbeCandidate> candidates
+ = Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
+ trait_ref);
+ if (candidates.size () == 0)
+ {
+ // this means we are defaulting back to the trait_item if
+ // possible
+ Resolver::TraitItemReference *trait_item_ref = nullptr;
+ bool ok = trait_ref->lookup_hir_trait_item (*trait_item,
+ &trait_item_ref);
+ rust_assert (ok); // found
+ rust_assert (trait_item_ref->is_optional ()); // has definition
+
+ Analysis::NodeMapping trait_mappings
+ = trait_item_ref->get_parent_trait_mappings ();
+ auto associated_impl_id
+ = ctx->get_tyctx ()->lookup_associated_impl_mapping_for_self (
+ trait_mappings.get_hirid (), receiver);
+
+ rust_assert (associated_impl_id != UNKNOWN_HIRID);
+
+ Resolver::AssociatedImplTrait *associated = nullptr;
+ bool found_associated_trait_impl
+ = ctx->get_tyctx ()->lookup_associated_trait_impl (
+ associated_impl_id, &associated);
+ rust_assert (found_associated_trait_impl);
+ associated->setup_associated_types ();
+
+ return CompileTraitItem::Compile (
+ receiver, trait_item_ref->get_hir_trait_item (), ctx, lookup,
+ true, expr_locus);
}
else
{
- rust_assert (parent_impl_id != UNKNOWN_HIRID);
- HIR::Item *impl_ref = ctx->get_mappings ()->lookup_hir_item (
- mappings.get_crate_num (), parent_impl_id);
- rust_assert (impl_ref != nullptr);
- HIR::ImplBlock *impl = static_cast<HIR::ImplBlock *> (impl_ref);
+ Resolver::PathProbeCandidate &candidate = candidates.at (0);
+ rust_assert (candidate.is_impl_candidate ());
+
+ HIR::ImplBlock *impl = candidate.item.impl.parent;
+ HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
TyTy::BaseType *self = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
@@ -230,23 +228,20 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
rust_assert (ok);
if (!lookup->has_subsititions_defined ())
- CompileInherentImplItem::Compile (self, resolved_item, ctx,
- true);
+ return CompileInherentImplItem::Compile (self, impl_item, ctx,
+ true, nullptr, true,
+ expr_locus);
else
- CompileInherentImplItem::Compile (self, resolved_item, ctx,
- true, lookup);
- }
- }
+ return CompileInherentImplItem::Compile (self, impl_item, ctx,
+ true, lookup, true,
+ expr_locus);
- if (!ctx->lookup_function_decl (lookup->get_ty_ref (), &fn))
- {
- resolved = ctx->get_backend ()->error_expression ();
- rust_error_at (expr_locus, "forward declaration was not compiled");
- return;
+ lookup->set_ty_ref (impl_item->get_impl_mappings ().get_hirid ());
+ }
}
}
- resolved = ctx->get_backend ()->function_code_expression (fn, expr_locus);
+ return ctx->get_backend ()->error_expression ();
}
} // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h
index 41067c8..2b50ec1 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.h
+++ b/gcc/rust/backend/rust-compile-resolve-path.h
@@ -54,9 +54,14 @@ private:
: HIRCompileBase (ctx), resolved (ctx->get_backend ()->error_expression ())
{}
- void resolve (const HIR::PathIdentSegment &final_segment,
- const Analysis::NodeMapping &mappings, Location locus,
- bool is_qualified_path);
+ Bexpression *resolve (const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings, Location locus,
+ bool is_qualified_path);
+
+ Bexpression *query_compile (HirId ref, TyTy::BaseType *lookup,
+ const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings,
+ Location expr_locus, bool is_qualified_path);
Bexpression *resolved;
};
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index 5b6bb24..9d79b36 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -225,9 +225,6 @@ Resolver::lookup_definition (NodeId id, Definition *def)
void
Resolver::insert_resolved_name (NodeId refId, NodeId defId)
{
- auto it = resolved_names.find (refId);
- rust_assert (it == resolved_names.end ());
-
resolved_names[refId] = defId;
get_name_scope ().append_reference_for_def (refId, defId);
}
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
index f737141..60cd98a 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe.h
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -114,6 +114,7 @@ struct PathProbeCandidate
class PathProbeType : public TypeCheckBase
{
+protected:
using Rust::Resolver::TypeCheckBase::visit;
public:
@@ -207,7 +208,7 @@ public:
}
}
-private:
+protected:
void process_impl_items_for_candidates ()
{
mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
@@ -313,7 +314,7 @@ private:
}
}
-private:
+protected:
PathProbeType (const TyTy::BaseType *receiver,
const HIR::PathIdentSegment &query)
: TypeCheckBase (), receiver (receiver), search (query),
@@ -404,6 +405,33 @@ private:
RichLocation &r;
};
+class PathProbeImplTrait : public PathProbeType
+{
+public:
+ static std::vector<PathProbeCandidate>
+ Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ const TraitReference *trait_reference)
+ {
+ PathProbeImplTrait probe (receiver, segment_name, trait_reference);
+ // iterate all impls for this trait and receiver
+ // then search for possible candidates using base class behaviours
+ probe.process_trait_impl_items_for_candidates ();
+ return probe.candidates;
+ }
+
+private:
+ void process_trait_impl_items_for_candidates ();
+
+ PathProbeImplTrait (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &query,
+ const TraitReference *trait_reference)
+ : PathProbeType (receiver, query), trait_reference (trait_reference)
+ {}
+
+ const TraitReference *trait_reference;
+};
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h
index 9d16e36..c86892e 100644
--- a/gcc/rust/typecheck/rust-hir-trait-ref.h
+++ b/gcc/rust/typecheck/rust-hir-trait-ref.h
@@ -335,6 +335,13 @@ public:
}
}
+ bool is_equal (const TraitReference &other) const
+ {
+ DefId this_id = get_mappings ().get_defid ();
+ DefId other_id = other.get_mappings ().get_defid ();
+ return this_id == other_id;
+ }
+
private:
const HIR::Trait *hir_trait_ref;
std::vector<TraitItemReference> item_refs;
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index cf3f2fb..aeedf7e 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -227,5 +227,27 @@ AssociatedImplTrait::get_projected_type (
return trait_item_tyty;
}
+// rust-hir-path-probe.h
+
+void
+PathProbeImplTrait::process_trait_impl_items_for_candidates ()
+{
+ mappings->iterate_impl_items (
+ [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
+ // just need to check if this is an impl block for this trait the next
+ // function checks the receiver
+ if (!impl->has_trait_ref ())
+ return true;
+
+ TraitReference *resolved
+ = TraitResolver::Lookup (*(impl->get_trait_ref ().get ()));
+ if (!trait_reference->is_equal (*resolved))
+ return true;
+
+ process_impl_item_candidate (id, item, impl);
+ return true;
+ });
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h
index 6874a3a..0fe2406 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.h
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h
@@ -72,6 +72,12 @@ public:
return resolver.go (path);
}
+ static TraitReference *Lookup (HIR::TypePath &path)
+ {
+ TraitResolver resolver;
+ return resolver.lookup_path (path);
+ }
+
private:
TraitResolver () : TypeCheckBase () {}
@@ -162,6 +168,40 @@ private:
return tref;
}
+ TraitReference *lookup_path (HIR::TypePath &path)
+ {
+ NodeId ref;
+ if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
+ &ref))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
+ return &TraitReference::error_node ();
+ }
+
+ HirId hir_node = UNKNOWN_HIRID;
+ if (!mappings->lookup_node_to_hir (mappings->get_current_crate (), ref,
+ &hir_node))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
+ return &TraitReference::error_node ();
+ }
+
+ HIR::Item *resolved_item
+ = mappings->lookup_hir_item (mappings->get_current_crate (), hir_node);
+
+ rust_assert (resolved_item != nullptr);
+ resolved_item->accept_vis (*this);
+ rust_assert (trait_reference != nullptr);
+
+ TraitReference *tref = &TraitReference::error_node ();
+ if (context->lookup_trait_reference (
+ trait_reference->get_mappings ().get_defid (), &tref))
+ {
+ return tref;
+ }
+ return &TraitReference::error_node ();
+ }
+
HIR::Trait *trait_reference;
public:
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index e3347ea..a95a4e9 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -925,169 +925,9 @@ public:
infered = resolved->get_field_type ();
}
- void visit (HIR::QualifiedPathInExpression &expr) override
- {
- HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
- TyTy::BaseType *root
- = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
- if (root->get_kind () == TyTy::TypeKind::ERROR)
- return;
-
- if (!qual_path_type.has_as_clause ())
- {
- // then this is just a normal path-in-expression
- NodeId root_resolved_node_id = UNKNOWN_NODEID;
- bool ok = resolver->lookup_resolved_type (
- qual_path_type.get_type ()->get_mappings ().get_nodeid (),
- &root_resolved_node_id);
- rust_assert (ok);
-
- resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
- expr.get_mappings (), expr.get_locus ());
- }
-
- // Resolve the trait now
- TraitReference *trait_ref
- = TraitResolver::Resolve (*qual_path_type.get_trait ().get ());
- if (trait_ref->is_error ())
- return;
-
- // does this type actually implement this type-bound?
- if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
- return;
-
- // then we need to look at the next segment to create perform the correct
- // projection type
- if (expr.get_segments ().empty ())
- return;
-
- // we need resolve to the impl block
- NodeId impl_resolved_id = UNKNOWN_NODEID;
- bool ok = resolver->lookup_resolved_name (
- qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
- rust_assert (ok);
-
- HirId impl_block_id;
- ok = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
- impl_resolved_id, &impl_block_id);
- rust_assert (ok);
-
- AssociatedImplTrait *lookup_associated = nullptr;
- bool found_impl_trait
- = context->lookup_associated_trait_impl (impl_block_id,
- &lookup_associated);
- rust_assert (found_impl_trait);
-
- DefId resolved_item_id = UNKNOWN_DEFID;
- HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
-
- const TraitItemReference *trait_item_ref = nullptr;
- ok = trait_ref->lookup_trait_item (item_seg.get_segment ().as_string (),
- &trait_item_ref);
- if (!ok)
- {
- rust_error_at (item_seg.get_locus (), "unknown associated item");
- return;
- }
- resolved_item_id = trait_item_ref->get_mappings ().get_defid ();
-
- infered = lookup_associated->get_projected_type (
- trait_item_ref, root, item_seg.get_mappings ().get_hirid (),
- item_seg.get_locus ());
-
- // turbo-fish segment path::<ty>
- if (item_seg.has_generic_args ())
- {
- if (!infered->can_substitute ())
- {
- rust_error_at (item_seg.get_locus (),
- "substitutions not supported for %s",
- infered->as_string ().c_str ());
- infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
- return;
- }
- infered = SubstMapper::Resolve (infered, expr.get_locus (),
- &item_seg.get_generic_args ());
- }
-
- TyTy::ProjectionType *projection
- = new TyTy::ProjectionType (qual_path_type.get_mappings ().get_hirid (),
- TyTy::TyVar (root->get_ref ()), trait_ref,
- resolved_item_id, lookup_associated);
- context->insert_type (qual_path_type.get_mappings (), projection);
-
- // continue on as a path-in-expression
- NodeId root_resolved_node_id
- = trait_item_ref->get_mappings ().get_nodeid ();
- bool fully_resolved = expr.get_segments ().size () <= 1;
-
- if (fully_resolved)
- {
- // 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_assert (path_resolved_id == root_resolved_node_id);
- }
- // check the type scope
- else if (resolver->lookup_resolved_type (
- expr.get_mappings ().get_nodeid (), &path_resolved_id))
- {
- rust_assert (path_resolved_id == root_resolved_node_id);
- }
- else
- {
- resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
- root_resolved_node_id);
- }
-
- context->insert_receiver (expr.get_mappings ().get_hirid (), root);
- return;
- }
-
- resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
- expr.get_mappings (), expr.get_locus ());
- }
-
- void visit (HIR::PathInExpression &expr) override
- {
- NodeId resolved_node_id = UNKNOWN_NODEID;
-
- size_t offset = -1;
- TyTy::BaseType *tyseg
- = resolve_root_path (expr, &offset, &resolved_node_id);
-
- if (tyseg == nullptr)
- {
- rust_debug_loc (expr.get_locus (), "failed to resolve root_seg");
- }
- rust_assert (tyseg != nullptr);
+ void visit (HIR::QualifiedPathInExpression &expr) override;
- if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
- return;
-
- if (expr.get_num_segments () == 1)
- {
- Location locus = expr.get_segments ().back ().get_locus ();
-
- bool is_big_self
- = expr.get_segments ().front ().get_segment ().as_string ().compare (
- "Self")
- == 0;
- if (!is_big_self && tyseg->needs_generic_substitutions ())
- {
- tyseg = SubstMapper::InferSubst (tyseg, locus);
- }
-
- infered = tyseg;
- return;
- }
-
- resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
- expr.get_mappings (), expr.get_locus ());
- }
+ void visit (HIR::PathInExpression &expr) override;
void visit (HIR::LoopExpr &expr) override
{
@@ -1235,277 +1075,13 @@ private:
// Beware: currently returns Tyty::ErrorType or nullptr in case of error.
TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr,
size_t *offset,
- NodeId *root_resolved_node_id)
- {
- TyTy::BaseType *root_tyty = nullptr;
- *offset = 0;
- for (size_t i = 0; i < expr.get_num_segments (); i++)
- {
- HIR::PathExprSegment &seg = expr.get_segments ().at (i);
-
- bool have_more_segments = (expr.get_num_segments () - 1 != i);
- bool is_root = *offset == 0;
- NodeId ast_node_id = seg.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);
- }
-
- // ref_node_id is the NodeId that the segments refers to.
- if (ref_node_id == UNKNOWN_NODEID)
- {
- if (is_root)
- {
- rust_error_at (seg.get_locus (),
- "failed to type resolve root segment");
- return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
- }
- return root_tyty;
- }
-
- // node back to HIR
- HirId ref;
- if (!mappings->lookup_node_to_hir (
- expr.get_mappings ().get_crate_num (), ref_node_id, &ref))
- {
- if (is_root)
- {
- rust_error_at (seg.get_locus (), "456 reverse lookup failure");
- rust_debug_loc (
- seg.get_locus (),
- "failure with [%s] mappings [%s] ref_node_id [%u]",
- seg.as_string ().c_str (),
- seg.get_mappings ().as_string ().c_str (), ref_node_id);
-
- return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
- }
-
- return root_tyty;
- }
-
- auto seg_is_module
- = (nullptr
- != mappings->lookup_module (expr.get_mappings ().get_crate_num (),
- ref));
-
- if (seg_is_module)
- {
- // A::B::C::this_is_a_module::D::E::F
- // ^^^^^^^^^^^^^^^^
- // Currently handling this.
- if (have_more_segments)
- {
- (*offset)++;
- continue;
- }
-
- // In the case of :
- // A::B::C::this_is_a_module
- // ^^^^^^^^^^^^^^^^
- // This is an error, we are not expecting a module.
- rust_error_at (seg.get_locus (), "expected value");
- return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
- }
-
- TyTy::BaseType *lookup = nullptr;
- if (!context->lookup_type (ref, &lookup))
- {
- if (is_root)
- {
- rust_error_at (seg.get_locus (),
- "failed to resolve root segment");
- return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
- }
- return root_tyty;
- }
-
- // if we have a previous segment type
- if (root_tyty != nullptr)
- {
- // if this next segment needs substitution we must apply the
- // previous type arguments
- //
- // such as: GenericStruct::<_>::new(123, 456)
- if (lookup->needs_generic_substitutions ())
- {
- if (!root_tyty->needs_generic_substitutions ())
- {
- auto used_args_in_prev_segment
- = GetUsedSubstArgs::From (root_tyty);
- lookup = SubstMapperInternal::Resolve (
- lookup, used_args_in_prev_segment);
- }
- }
- }
-
- // turbo-fish segment path::<ty>
- if (seg.has_generic_args ())
- {
- if (!lookup->can_substitute ())
- {
- rust_error_at (seg.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 (),
- &seg.get_generic_args ());
- }
-
- *root_resolved_node_id = ref_node_id;
- *offset = *offset + 1;
- root_tyty = lookup;
- }
-
- return root_tyty;
- }
+ NodeId *root_resolved_node_id);
void resolve_segments (NodeId root_resolved_node_id,
std::vector<HIR::PathExprSegment> &segments,
size_t offset, TyTy::BaseType *tyseg,
const Analysis::NodeMapping &expr_mappings,
- Location expr_locus)
- {
- NodeId resolved_node_id = root_resolved_node_id;
- TyTy::BaseType *prev_segment = tyseg;
- for (size_t i = offset; i < segments.size (); i++)
- {
- HIR::PathExprSegment &seg = segments.at (i);
-
- bool reciever_is_generic
- = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
- bool probe_bounds = true;
- bool probe_impls = !reciever_is_generic;
- bool ignore_mandatory_trait_items = !reciever_is_generic;
-
- // probe the path
- auto candidates
- = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
- probe_bounds, ignore_mandatory_trait_items);
- if (candidates.size () == 0)
- {
- rust_error_at (
- seg.get_locus (),
- "failed to resolve path segment using an impl Probe");
- return;
- }
- else if (candidates.size () > 1)
- {
- ReportMultipleCandidateError::Report (candidates,
- seg.get_segment (),
- seg.get_locus ());
- return;
- }
-
- auto &candidate = candidates.at (0);
- prev_segment = tyseg;
- tyseg = candidate.ty;
-
- if (candidate.is_impl_candidate ())
- {
- resolved_node_id
- = candidate.item.impl.impl_item->get_impl_mappings ()
- .get_nodeid ();
- }
- else
- {
- resolved_node_id
- = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
-
- // lookup the associated-impl-trait
- HIR::ImplBlock *impl = candidate.item.trait.impl;
- if (impl != nullptr)
- {
- AssociatedImplTrait *lookup_associated = nullptr;
- bool found_impl_trait = context->lookup_associated_trait_impl (
- impl->get_mappings ().get_hirid (), &lookup_associated);
- rust_assert (found_impl_trait);
-
- lookup_associated->setup_associated_types ();
-
- // we need a new ty_ref_id for this trait item
- tyseg = tyseg->clone ();
- tyseg->set_ty_ref (mappings->get_next_hir_id ());
- }
- }
-
- if (seg.has_generic_args ())
- {
- if (!tyseg->can_substitute ())
- {
- rust_error_at (expr_locus, "substitutions not supported for %s",
- tyseg->as_string ().c_str ());
- return;
- }
-
- tyseg = SubstMapper::Resolve (tyseg, expr_locus,
- &seg.get_generic_args ());
- if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
- return;
- }
- }
-
- context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
- if (tyseg->needs_generic_substitutions ())
- {
- Location locus = segments.back ().get_locus ();
- if (!prev_segment->needs_generic_substitutions ())
- {
- auto used_args_in_prev_segment
- = GetUsedSubstArgs::From (prev_segment);
- if (!used_args_in_prev_segment.is_error ())
- tyseg = SubstMapperInternal::Resolve (tyseg,
- used_args_in_prev_segment);
- }
- else
- {
- tyseg = SubstMapper::InferSubst (tyseg, locus);
- }
-
- if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
- return;
- }
-
- 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_mappings.get_nodeid (),
- &path_resolved_id))
- {
- rust_assert (path_resolved_id == resolved_node_id);
- }
- // check the type scope
- else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (),
- &path_resolved_id))
- {
- rust_assert (path_resolved_id == resolved_node_id);
- }
- else
- {
- resolver->insert_resolved_name (expr_mappings.get_nodeid (),
- resolved_node_id);
- }
-
- infered = tyseg;
- }
+ Location expr_locus);
bool
validate_arithmetic_type (TyTy::BaseType *type,
@@ -1569,7 +1145,7 @@ private:
Location root_array_expr_locus;
bool inside_loop;
-}; // namespace Resolver
+};
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
new file mode 100644
index 0000000..7b0e8ae
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -0,0 +1,452 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-hir-type-check-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
+{
+ HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
+ TyTy::BaseType *root
+ = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
+ if (root->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ if (!qual_path_type.has_as_clause ())
+ {
+ // then this is just a normal path-in-expression
+ NodeId root_resolved_node_id = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (
+ qual_path_type.get_type ()->get_mappings ().get_nodeid (),
+ &root_resolved_node_id);
+ rust_assert (ok);
+
+ resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
+ expr.get_mappings (), expr.get_locus ());
+ }
+
+ // Resolve the trait now
+ TraitReference *trait_ref
+ = TraitResolver::Resolve (*qual_path_type.get_trait ().get ());
+ if (trait_ref->is_error ())
+ return;
+
+ // does this type actually implement this type-bound?
+ if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
+ return;
+
+ // then we need to look at the next segment to create perform the correct
+ // projection type
+ if (expr.get_segments ().empty ())
+ return;
+
+ // we need resolve to the impl block
+ NodeId impl_resolved_id = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (
+ qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
+ rust_assert (ok);
+
+ HirId impl_block_id;
+ ok = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+ impl_resolved_id, &impl_block_id);
+ rust_assert (ok);
+
+ AssociatedImplTrait *lookup_associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id, &lookup_associated);
+ rust_assert (found_impl_trait);
+
+ DefId resolved_item_id = UNKNOWN_DEFID;
+ HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
+
+ const TraitItemReference *trait_item_ref = nullptr;
+ ok = trait_ref->lookup_trait_item (item_seg.get_segment ().as_string (),
+ &trait_item_ref);
+ if (!ok)
+ {
+ rust_error_at (item_seg.get_locus (), "unknown associated item");
+ return;
+ }
+ resolved_item_id = trait_item_ref->get_mappings ().get_defid ();
+
+ infered = lookup_associated->get_projected_type (
+ trait_item_ref, root, item_seg.get_mappings ().get_hirid (),
+ item_seg.get_locus ());
+
+ // turbo-fish segment path::<ty>
+ if (item_seg.has_generic_args ())
+ {
+ if (!infered->can_substitute ())
+ {
+ rust_error_at (item_seg.get_locus (),
+ "substitutions not supported for %s",
+ infered->as_string ().c_str ());
+ infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ return;
+ }
+ infered = SubstMapper::Resolve (infered, expr.get_locus (),
+ &item_seg.get_generic_args ());
+ }
+
+ TyTy::ProjectionType *projection
+ = new TyTy::ProjectionType (qual_path_type.get_mappings ().get_hirid (),
+ TyTy::TyVar (root->get_ref ()), trait_ref,
+ resolved_item_id, lookup_associated);
+ context->insert_type (qual_path_type.get_mappings (), projection);
+
+ // continue on as a path-in-expression
+ NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
+ bool fully_resolved = expr.get_segments ().size () <= 1;
+
+ if (fully_resolved)
+ {
+ resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
+ root_resolved_node_id);
+ context->insert_receiver (expr.get_mappings ().get_hirid (), root);
+ return;
+ }
+
+ resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
+ expr.get_mappings (), expr.get_locus ());
+}
+
+void
+TypeCheckExpr::visit (HIR::PathInExpression &expr)
+{
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+
+ size_t offset = -1;
+ TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
+
+ if (tyseg == nullptr)
+ {
+ rust_debug_loc (expr.get_locus (), "failed to resolve root_seg");
+ }
+ rust_assert (tyseg != nullptr);
+
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ if (expr.get_num_segments () == 1)
+ {
+ Location locus = expr.get_segments ().back ().get_locus ();
+
+ bool is_big_self
+ = expr.get_segments ().front ().get_segment ().as_string ().compare (
+ "Self")
+ == 0;
+ if (!is_big_self && tyseg->needs_generic_substitutions ())
+ {
+ tyseg = SubstMapper::InferSubst (tyseg, locus);
+ }
+
+ infered = tyseg;
+ return;
+ }
+
+ resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
+ expr.get_mappings (), expr.get_locus ());
+}
+
+TyTy::BaseType *
+TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
+ NodeId *root_resolved_node_id)
+{
+ TyTy::BaseType *root_tyty = nullptr;
+ *offset = 0;
+ for (size_t i = 0; i < expr.get_num_segments (); i++)
+ {
+ HIR::PathExprSegment &seg = expr.get_segments ().at (i);
+
+ bool have_more_segments = (expr.get_num_segments () - 1 != i);
+ bool is_root = *offset == 0;
+ NodeId ast_node_id = seg.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);
+ }
+
+ // ref_node_id is the NodeId that the segments refers to.
+ if (ref_node_id == UNKNOWN_NODEID)
+ {
+ if (is_root)
+ {
+ rust_error_at (seg.get_locus (),
+ "failed to type resolve root segment");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+ return root_tyty;
+ }
+
+ // node back to HIR
+ HirId ref;
+ if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+ ref_node_id, &ref))
+ {
+ if (is_root)
+ {
+ rust_error_at (seg.get_locus (), "456 reverse lookup failure");
+ rust_debug_loc (
+ seg.get_locus (),
+ "failure with [%s] mappings [%s] ref_node_id [%u]",
+ seg.as_string ().c_str (),
+ seg.get_mappings ().as_string ().c_str (), ref_node_id);
+
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ return root_tyty;
+ }
+
+ auto seg_is_module
+ = (nullptr
+ != mappings->lookup_module (expr.get_mappings ().get_crate_num (),
+ ref));
+
+ if (seg_is_module)
+ {
+ // A::B::C::this_is_a_module::D::E::F
+ // ^^^^^^^^^^^^^^^^
+ // Currently handling this.
+ if (have_more_segments)
+ {
+ (*offset)++;
+ continue;
+ }
+
+ // In the case of :
+ // A::B::C::this_is_a_module
+ // ^^^^^^^^^^^^^^^^
+ // This is an error, we are not expecting a module.
+ rust_error_at (seg.get_locus (), "expected value");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ TyTy::BaseType *lookup = nullptr;
+ if (!context->lookup_type (ref, &lookup))
+ {
+ if (is_root)
+ {
+ rust_error_at (seg.get_locus (),
+ "failed to resolve root segment");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+ return root_tyty;
+ }
+
+ // if we have a previous segment type
+ if (root_tyty != nullptr)
+ {
+ // if this next segment needs substitution we must apply the
+ // previous type arguments
+ //
+ // such as: GenericStruct::<_>::new(123, 456)
+ if (lookup->needs_generic_substitutions ())
+ {
+ if (!root_tyty->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (root_tyty);
+ lookup
+ = SubstMapperInternal::Resolve (lookup,
+ used_args_in_prev_segment);
+ }
+ }
+ }
+
+ // turbo-fish segment path::<ty>
+ if (seg.has_generic_args ())
+ {
+ if (!lookup->can_substitute ())
+ {
+ rust_error_at (seg.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 (),
+ &seg.get_generic_args ());
+ }
+
+ *root_resolved_node_id = ref_node_id;
+ *offset = *offset + 1;
+ root_tyty = lookup;
+ }
+
+ return root_tyty;
+}
+
+void
+TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
+ std::vector<HIR::PathExprSegment> &segments,
+ size_t offset, TyTy::BaseType *tyseg,
+ const Analysis::NodeMapping &expr_mappings,
+ Location expr_locus)
+{
+ NodeId resolved_node_id = root_resolved_node_id;
+ TyTy::BaseType *prev_segment = tyseg;
+ for (size_t i = offset; i < segments.size (); i++)
+ {
+ HIR::PathExprSegment &seg = segments.at (i);
+
+ bool reciever_is_generic
+ = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
+ bool probe_bounds = true;
+ bool probe_impls = !reciever_is_generic;
+ bool ignore_mandatory_trait_items = !reciever_is_generic;
+
+ // probe the path is done in two parts one where we search impls if no
+ // candidate is found then we search extensions from traits
+ auto candidates
+ = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
+ false, ignore_mandatory_trait_items);
+ if (candidates.size () == 0)
+ {
+ candidates
+ = PathProbeType::Probe (prev_segment, seg.get_segment (), false,
+ probe_bounds, ignore_mandatory_trait_items);
+ if (candidates.size () == 0)
+ {
+ rust_error_at (
+ seg.get_locus (),
+ "failed to resolve path segment using an impl Probe");
+ return;
+ }
+ }
+
+ if (candidates.size () > 1)
+ {
+ ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
+ seg.get_locus ());
+ return;
+ }
+
+ auto &candidate = candidates.at (0);
+ prev_segment = tyseg;
+ tyseg = candidate.ty;
+
+ if (candidate.is_impl_candidate ())
+ {
+ resolved_node_id
+ = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
+ }
+ else
+ {
+ resolved_node_id
+ = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
+
+ // lookup the associated-impl-trait
+ HIR::ImplBlock *impl = candidate.item.trait.impl;
+ if (impl != nullptr)
+ {
+ AssociatedImplTrait *lookup_associated = nullptr;
+ bool found_impl_trait = context->lookup_associated_trait_impl (
+ impl->get_mappings ().get_hirid (), &lookup_associated);
+ rust_assert (found_impl_trait);
+
+ lookup_associated->setup_associated_types ();
+
+ // we need a new ty_ref_id for this trait item
+ tyseg = tyseg->clone ();
+ tyseg->set_ty_ref (mappings->get_next_hir_id ());
+ }
+ }
+
+ if (seg.has_generic_args ())
+ {
+ if (!tyseg->can_substitute ())
+ {
+ rust_error_at (expr_locus, "substitutions not supported for %s",
+ tyseg->as_string ().c_str ());
+ return;
+ }
+
+ tyseg = SubstMapper::Resolve (tyseg, expr_locus,
+ &seg.get_generic_args ());
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+ }
+
+ context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
+ if (tyseg->needs_generic_substitutions ())
+ {
+ Location locus = segments.back ().get_locus ();
+ if (!prev_segment->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (prev_segment);
+ if (!used_args_in_prev_segment.is_error ())
+ tyseg
+ = SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment);
+ }
+ else
+ {
+ tyseg = SubstMapper::InferSubst (tyseg, locus);
+ }
+
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+
+ 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_mappings.get_nodeid (),
+ &path_resolved_id))
+ {
+ rust_assert (path_resolved_id == resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (),
+ &path_resolved_id))
+ {
+ rust_assert (path_resolved_id == resolved_node_id);
+ }
+ else
+ {
+ resolver->insert_resolved_name (expr_mappings.get_nodeid (),
+ resolved_node_id);
+ }
+
+ infered = tyseg;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/testsuite/rust/execute/torture/trait2.rs b/gcc/testsuite/rust/execute/torture/trait2.rs
new file mode 100644
index 0000000..c96615f
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait2.rs
@@ -0,0 +1,37 @@
+/* { dg-output "Bar::A = 456\n<Foo as Bar>::A = 456\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+trait Foo {
+ const A: i32 = 123;
+}
+
+struct Bar;
+impl Foo for Bar {
+ const A: i32 = 456;
+}
+
+fn main() -> i32 {
+ let a;
+ a = Bar::A;
+
+ unsafe {
+ let _a = "Bar::A = %i\n\0";
+ let _b = _a as *const str;
+ let _c = _b as *const i8;
+ printf(_c, a);
+ }
+
+ let b;
+ b = <Bar as Foo>::A;
+
+ unsafe {
+ let _a = "<Foo as Bar>::A = %i\n\0";
+ let _b = _a as *const str;
+ let _c = _b as *const i8;
+ printf(_c, b);
+ }
+
+ 0
+}