diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-08-22 13:59:00 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-22 13:59:00 +0000 |
commit | ac3be517de2c0ec596eeee754b863243cb071098 (patch) | |
tree | 9bef8c57466f78db9fd8444f33ed854c24187d16 | |
parent | e9746f445cf57c12f70d0016722835ec504cc655 (diff) | |
parent | 5a0e34b74aa6de092632bad2bee4883c5a23e036 (diff) | |
download | gcc-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.in | 1 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-implitem.h | 98 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-item.h | 48 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.cc | 293 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.h | 11 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve.cc | 3 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-path-probe.h | 32 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-ref.h | 7 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-resolve.cc | 22 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-resolve.h | 40 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 434 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-path.cc | 452 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/trait2.rs | 37 |
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 +} |