diff options
-rw-r--r-- | gcc/rust/backend/rust-compile-context.h | 2 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 5 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-implitem.h | 3 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-item.h | 16 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.cc | 69 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.h | 18 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile.cc | 19 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-ref.h | 4 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-resolve.cc | 34 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 75 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.cc | 2 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 12 | ||||
-rw-r--r-- | gcc/rust/util/rust-canonical-path.h | 11 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/trait1.rs | 52 |
14 files changed, 274 insertions, 48 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 6356ccc..66d037d 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -287,7 +287,7 @@ public: // this needs to support Legacy and V0 see github #429 or #305 std::string mangle_item (const TyTy::BaseType *ty, - const std::string &name) const; + const Resolver::CanonicalPath &path) const; std::string mangle_impl_item (const TyTy::BaseType *self, const TyTy::BaseType *ty, diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 4658295..80cdc5e 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -629,6 +629,11 @@ public: expr.get_locus ()); } + void visit (HIR::QualifiedPathInExpression &expr) override + { + translated = ResolvePathRef::Compile (expr, ctx); + } + void visit (HIR::PathInExpression &expr) override { translated = ResolvePathRef::Compile (expr, ctx); diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h index 809cf56..7337154 100644 --- a/gcc/rust/backend/rust-compile-implitem.h +++ b/gcc/rust/backend/rust-compile-implitem.h @@ -352,8 +352,7 @@ public: &canonical_path)); std::string fn_identifier = canonical_path->get (); - std::string asm_name - = ctx->mangle_impl_item (self, fntype, function.get_function_name ()); + std::string asm_name = ctx->mangle_item (fntype, *canonical_path); Bfunction *fndecl = ctx->get_backend ()->function (compiled_fn_type, fn_identifier, diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index 8b36289..a12e67e 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -59,7 +59,7 @@ public: &canonical_path)); std::string name = canonical_path->get (); - std::string asm_name = ctx->mangle_item (resolved_type, name); + std::string asm_name = ctx->mangle_item (resolved_type, *canonical_path); bool is_external = false; bool is_hidden = false; @@ -168,12 +168,24 @@ public: std::string ir_symbol_name = canonical_path->get () + fntype->subst_as_string (); + std::string asm_name = function.get_function_name (); // we don't mangle the main fn since we haven't implemented the main shim // yet if (!is_main_fn) - asm_name = ctx->mangle_item (fntype, ir_symbol_name); + { + std::string substs_str = fntype->subst_as_string (); + + Resolver::CanonicalPath mangle_me + = substs_str.empty () + ? *canonical_path + : canonical_path->append ( + Resolver::CanonicalPath::new_seg (0, + fntype->subst_as_string ())); + + asm_name = ctx->mangle_item (fntype, mangle_me); + } Bfunction *fndecl = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 1b892d2..1539378 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -27,18 +27,33 @@ namespace Rust { namespace Compile { void +ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr) +{ + 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); +} + +void +ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, + const Analysis::NodeMapping &mappings, + Location expr_locus, bool is_qualified_path) +{ // need to look up the reference for this identifier NodeId ref_node_id = UNKNOWN_NODEID; - if (ctx->get_resolver ()->lookup_resolved_name ( - expr.get_mappings ().get_nodeid (), &ref_node_id)) + if (ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (), + &ref_node_id)) { Resolver::Definition def; if (!ctx->get_resolver ()->lookup_definition (ref_node_id, &def)) { - rust_error_at (expr.get_locus (), - "unknown reference for resolved name"); + rust_error_at (expr_locus, "unknown reference for resolved name"); return; } ref_node_id = def.parent; @@ -50,10 +65,10 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) return; HirId ref; - if (!ctx->get_mappings ()->lookup_node_to_hir ( - expr.get_mappings ().get_crate_num (), ref_node_id, &ref)) + if (!ctx->get_mappings ()->lookup_node_to_hir (mappings.get_crate_num (), + ref_node_id, &ref)) { - rust_error_at (expr.get_locus (), "reverse call path lookup failure"); + rust_error_at (expr_locus, "reverse call path lookup failure"); return; } @@ -65,15 +80,14 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) Bvariable *var = nullptr; if (ctx->lookup_var_decl (ref, &var)) { - resolved = ctx->get_backend ()->var_expression (var, expr.get_locus ()); + resolved = ctx->get_backend ()->var_expression (var, expr_locus); return; } // must be a function call but it might be a generic function which needs to // be compiled first TyTy::BaseType *lookup = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), - &lookup); + 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); @@ -82,8 +96,9 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) if (!ctx->lookup_function_decl (lookup->get_ty_ref (), &fn)) { // it must resolve to some kind of HIR::Item or HIR::InheritImplItem - HIR::Item *resolved_item = ctx->get_mappings ()->lookup_hir_item ( - expr.get_mappings ().get_crate_num (), ref); + HIR::Item *resolved_item + = ctx->get_mappings ()->lookup_hir_item (mappings.get_crate_num (), + ref); if (resolved_item != nullptr) { if (!lookup->has_subsititions_defined ()) @@ -96,14 +111,14 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) HirId parent_impl_id = UNKNOWN_HIRID; HIR::ImplItem *resolved_item = ctx->get_mappings ()->lookup_hir_implitem ( - expr.get_mappings ().get_crate_num (), ref, &parent_impl_id); + 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 ( - expr.get_mappings ().get_crate_num (), ref); + mappings.get_crate_num (), ref); HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping ( trait_item->get_mappings ().get_hirid ()); @@ -115,8 +130,8 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) rust_assert (ok); TyTy::BaseType *receiver = nullptr; - ok = ctx->get_tyctx ()->lookup_receiver ( - expr.get_mappings ().get_hirid (), &receiver); + ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (), + &receiver); rust_assert (ok); if (receiver->get_kind () == TyTy::TypeKind::PARAM) @@ -130,10 +145,13 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) // 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::PathProbeType::Probe ( - receiver, expr.get_final_segment ().get_segment (), true, - false, true); + std::vector<Resolver::PathProbeCandidate> candidates; + if (!is_qualified_path) + { + candidates + = Resolver::PathProbeType::Probe (receiver, final_segment, + true, false, true); + } if (candidates.size () == 0) { @@ -152,6 +170,7 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) = 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; @@ -168,7 +187,7 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) { resolved = ctx->get_backend ()->error_expression (); - rust_error_at (expr.get_locus (), + rust_error_at (expr_locus, "forward declaration was not compiled"); return; } @@ -201,7 +220,7 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) { rust_assert (parent_impl_id != UNKNOWN_HIRID); HIR::Item *impl_ref = ctx->get_mappings ()->lookup_hir_item ( - expr.get_mappings ().get_crate_num (), parent_impl_id); + mappings.get_crate_num (), parent_impl_id); rust_assert (impl_ref != nullptr); HIR::ImplBlock *impl = static_cast<HIR::ImplBlock *> (impl_ref); @@ -222,14 +241,12 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) if (!ctx->lookup_function_decl (lookup->get_ty_ref (), &fn)) { resolved = ctx->get_backend ()->error_expression (); - rust_error_at (expr.get_locus (), - "forward declaration was not compiled"); + rust_error_at (expr_locus, "forward declaration was not compiled"); return; } } - resolved - = ctx->get_backend ()->function_code_expression (fn, expr.get_locus ()); + resolved = ctx->get_backend ()->function_code_expression (fn, expr_locus); } } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h index 30486d0..41067c8 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.h +++ b/gcc/rust/backend/rust-compile-resolve-path.h @@ -30,6 +30,14 @@ class ResolvePathRef : public HIRCompileBase using Rust::Compile::HIRCompileBase::visit; public: + static Bexpression *Compile (HIR::QualifiedPathInExpression &expr, + Context *ctx) + { + ResolvePathRef resolver (ctx); + expr.accept_vis (resolver); + return resolver.resolved; + } + static Bexpression *Compile (HIR::PathInExpression &expr, Context *ctx) { ResolvePathRef resolver (ctx); @@ -39,8 +47,16 @@ public: void visit (HIR::PathInExpression &expr) override; + void visit (HIR::QualifiedPathInExpression &expr) override; + private: - ResolvePathRef (Context *ctx) : HIRCompileBase (ctx), resolved (nullptr) {} + ResolvePathRef (Context *ctx) + : 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 *resolved; }; diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index c36f848..baaccf0 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -553,6 +553,17 @@ mangle_name (const std::string &name) return std::to_string (name.size ()) + name; } +static std::string +mangle_canonical_path (const Resolver::CanonicalPath &path) +{ + std::string buffer; + path.iterate_segs ([&] (const Resolver::CanonicalPath &p) -> bool { + buffer += mangle_name (p.get ()); + return true; + }); + return buffer; +} + // rustc uses a sip128 hash for legacy mangling, but an fnv 128 was quicker to // implement for now static std::string @@ -603,17 +614,19 @@ mangle_self (const TyTy::BaseType *self) } std::string -Context::mangle_item (const TyTy::BaseType *ty, const std::string &name) const +Context::mangle_item (const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path) const { const std::string &crate_name = mappings->get_current_crate_name (); const std::string hash = legacy_hash (ty->as_string ()); const std::string hash_sig = mangle_name (hash); - return kMangledSymbolPrefix + mangle_name (crate_name) + mangle_name (name) - + hash_sig + kMangledSymbolDelim; + return kMangledSymbolPrefix + mangle_name (crate_name) + + mangle_canonical_path (path) + hash_sig + kMangledSymbolDelim; } +// FIXME this is a wee bit broken std::string Context::mangle_impl_item (const TyTy::BaseType *self, const TyTy::BaseType *ty, const std::string &name) const diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 2c7a0e8..9d16e36 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -359,6 +359,10 @@ public: void reset_associated_types (); + TyTy::BaseType *get_projected_type (const TraitItemReference *trait_item_ref, + TyTy::BaseType *reciever, HirId ref, + Location expr_locus); + private: TraitReference *trait; HIR::ImplBlock *impl; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 5d7c71e..cf3f2fb 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -193,5 +193,39 @@ TraitItemReference::get_parent_trait_mappings () const return trait->get_mappings (); } +TyTy::BaseType * +AssociatedImplTrait::get_projected_type ( + const TraitItemReference *trait_item_ref, TyTy::BaseType *receiver, HirId ref, + Location expr_locus) +{ + TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ()->clone (); + + // we can substitute the Self with the receiver here + if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) + { + TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty); + TyTy::SubstitutionParamMapping *param = nullptr; + for (auto ¶m_mapping : fn->get_substs ()) + { + const HIR::TypeParam &type_param = param_mapping.get_generic_param (); + if (type_param.get_type_representation ().compare ("Self") == 0) + { + param = ¶m_mapping; + break; + } + } + rust_assert (param != nullptr); + + std::vector<TyTy::SubstitutionArg> mappings; + mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ())); + + Location locus; // FIXME + TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus); + trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args); + } + + return trait_item_tyty; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 0ac60c2..e3347ea 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -961,33 +961,92 @@ public: 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; - bool ok - = trait_ref->lookup_trait_item (item_seg.get_segment ().as_string (), - &trait_item_ref); + 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 ()); - // TODO self and generic arguments - infered = trait_item_ref->get_tyty (); - rust_debug_loc (expr.get_locus (), "resolved to:"); - infered->debug (); + // 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); + 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 ()); } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 18ccaee..56fdafd 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2174,7 +2174,7 @@ BaseType * ProjectionType::clone () const { return new ProjectionType (get_ref (), get_ty_ref (), base, trait, item, - get_combined_refs ()); + associated, get_combined_refs ()); } // rust-tyty-call.h diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 2fc6b53..743874a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -27,7 +27,8 @@ namespace Rust { namespace Resolver { class TraitReference; -} +class AssociatedImplTrait; +} // namespace Resolver namespace TyTy { @@ -1730,16 +1731,18 @@ class ProjectionType : public BaseType { public: ProjectionType (HirId ref, TyVar base, Resolver::TraitReference *trait, - DefId item, std::set<HirId> refs = std::set<HirId> ()) + DefId item, Resolver::AssociatedImplTrait *associated, + std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ref, TypeKind::PROJECTION, refs), base (base), - trait (trait), item (item) + trait (trait), item (item), associated (associated) {} ProjectionType (HirId ref, HirId ty_ref, TyVar base, Resolver::TraitReference *trait, DefId item, + Resolver::AssociatedImplTrait *associated, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ty_ref, TypeKind::PROJECTION, refs), base (base), - trait (trait), item (item) + trait (trait), item (item), associated (associated) {} void accept_vis (TyVisitor &vis) override; @@ -1762,6 +1765,7 @@ private: TyVar base; Resolver::TraitReference *trait; DefId item; + Resolver::AssociatedImplTrait *associated; }; } // namespace TyTy diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h index d6ba90d..b5f8dd7 100644 --- a/gcc/rust/util/rust-canonical-path.h +++ b/gcc/rust/util/rust-canonical-path.h @@ -110,6 +110,17 @@ public: } } + void iterate_segs (std::function<bool (const CanonicalPath &)> cb) const + { + for (auto &seg : segs) + { + std::vector<std::pair<NodeId, std::string>> buf; + buf.push_back ({seg.first, seg.second}); + if (!cb (CanonicalPath (buf))) + return; + } + } + size_t size () const { return segs.size (); } NodeId get_id () const diff --git a/gcc/testsuite/rust/execute/torture/trait1.rs b/gcc/testsuite/rust/execute/torture/trait1.rs new file mode 100644 index 0000000..dc3cc47 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait1.rs @@ -0,0 +1,52 @@ +/* { dg-output "S::f\nT1::f\nT2::f\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct S; + +impl S { + fn f() { + unsafe { + let a = "S::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +trait T1 { + fn f() { + unsafe { + let a = "T1::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} +impl T1 for S {} + +trait T2 { + fn f() { + unsafe { + let a = "T2::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} +impl T2 for S {} + +fn main() -> i32 { + S::f(); + <S as T1>::f(); + <S as T2>::f(); + + 0 +} |