diff options
Diffstat (limited to 'gcc')
49 files changed, 2148 insertions, 315 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index f4bc9ea..7ed380e 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -80,6 +80,8 @@ GRS_OBJS = \ rust/rust-tyty.o \ rust/rust-tyctx.o \ rust/rust-tyty-bounds.o \ + rust/rust-hir-type-check-util.o \ + rust/rust-hir-trait-resolve.o \ rust/rust-hir-const-fold.o \ rust/rust-lint-marklive.o \ $(END) diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 011ac3e..74ea795 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -771,11 +771,9 @@ struct QualifiedPathType { private: std::unique_ptr<Type> type_to_invoke_on; - - // bool has_as_clause; TypePath trait_path; - Location locus; + NodeId node_id; public: // Constructor @@ -783,13 +781,15 @@ public: Location locus = Location (), TypePath trait_path = TypePath::create_error ()) : type_to_invoke_on (std::move (invoke_on_type)), - trait_path (std::move (trait_path)), locus (locus) + trait_path (std::move (trait_path)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType (QualifiedPathType const &other) : trait_path (other.trait_path), locus (other.locus) { + node_id = other.node_id; // guard to prevent null dereference if (other.type_to_invoke_on != nullptr) type_to_invoke_on = other.type_to_invoke_on->clone_type (); @@ -801,6 +801,7 @@ public: // overload assignment operator to use custom clone method QualifiedPathType &operator= (QualifiedPathType const &other) { + node_id = other.node_id; trait_path = other.trait_path; locus = other.locus; @@ -846,6 +847,8 @@ public: rust_assert (has_as_clause ()); return trait_path; } + + NodeId get_node_id () const { return node_id; } }; /* AST node representing a qualified path-in-expression pattern (path that @@ -855,6 +858,7 @@ class QualifiedPathInExpression : public PathPattern, public PathExpr std::vector<Attribute> outer_attrs; QualifiedPathType path_type; Location locus; + NodeId _node_id; public: std::string as_string () const override; @@ -864,7 +868,8 @@ public: std::vector<Attribute> outer_attrs, Location locus) : PathPattern (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), - path_type (std::move (qual_path_type)), locus (locus) + path_type (std::move (qual_path_type)), locus (locus), + _node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} /* TODO: maybe make a shortcut constructor that has QualifiedPathType elements @@ -907,6 +912,8 @@ public: outer_attrs = std::move (new_attrs); } + NodeId get_node_id () const override { return _node_id; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 8007c2f..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, @@ -336,7 +336,12 @@ public: void visit (TyTy::InferType &) override { gcc_unreachable (); } - void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } + + void visit (TyTy::PlaceholderType &type) override + { + type.resolve ()->accept_vis (*this); + } void visit (TyTy::ParamType ¶m) override { 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 7608599..7337154 100644 --- a/gcc/rust/backend/rust-compile-implitem.h +++ b/gcc/rust/backend/rust-compile-implitem.h @@ -297,6 +297,220 @@ private: TyTy::BaseType *concrete; }; +class CompileTraitItem : public HIRCompileBase +{ + using Rust::Compile::HIRCompileBase::visit; + +public: + static void Compile (TyTy::BaseType *self, HIR::TraitItem *item, Context *ctx, + TyTy::BaseType *concrete) + { + CompileTraitItem compiler (self, ctx, concrete); + item->accept_vis (compiler); + } + + void visit (HIR::TraitItemFunc &func) override + { + rust_assert (func.has_block_defined ()); + + rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fntype = static_cast<TyTy::FnType *> (concrete); + + // items can be forward compiled which means we may not need to invoke this + // code. We might also have already compiled this generic function as well. + Bfunction *lookup = nullptr; + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup)) + { + // has this been added to the list then it must be finished + if (ctx->function_completed (lookup)) + { + Bfunction *dummy = nullptr; + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) + { + ctx->insert_function_decl (fntype->get_ty_ref (), lookup, + fntype); + } + return; + } + } + + if (fntype->has_subsititions_defined ()) + { + // override the Hir Lookups for the substituions in this context + fntype->override_context (); + } + + // convert to the actual function type + ::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); + + HIR::TraitFunctionDecl &function = func.get_decl (); + unsigned int flags = 0; + + const Resolver::CanonicalPath *canonical_path = nullptr; + rust_assert (ctx->get_mappings ()->lookup_canonical_path ( + func.get_mappings ().get_crate_num (), func.get_mappings ().get_nodeid (), + &canonical_path)); + + std::string fn_identifier = canonical_path->get (); + std::string asm_name = ctx->mangle_item (fntype, *canonical_path); + + Bfunction *fndecl + = ctx->get_backend ()->function (compiled_fn_type, fn_identifier, + asm_name, flags, func.get_locus ()); + ctx->insert_function_decl (fntype->get_ty_ref (), fndecl, fntype); + + // setup the params + TyTy::BaseType *tyret = fntype->get_return_type (); + std::vector<Bvariable *> param_vars; + + if (function.is_method ()) + { + // insert self + TyTy::BaseType *self_tyty_lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + function.get_self ().get_mappings ().get_hirid (), + &self_tyty_lookup)) + { + rust_error_at (function.get_self ().get_locus (), + "failed to lookup self param type"); + return; + } + + Btype *self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup); + if (self_type == nullptr) + { + rust_error_at (function.get_self ().get_locus (), + "failed to compile self param type"); + return; + } + + Bvariable *compiled_self_param + = CompileSelfParam::compile (ctx, fndecl, function.get_self (), + self_type, + function.get_self ().get_locus ()); + if (compiled_self_param == nullptr) + { + rust_error_at (function.get_self ().get_locus (), + "failed to compile self param variable"); + return; + } + + param_vars.push_back (compiled_self_param); + ctx->insert_var_decl (function.get_self ().get_mappings ().get_hirid (), + compiled_self_param); + } + + // offset from + 1 for the TyTy::FnType being used when this is a method to + // skip over Self on the FnType + size_t i = function.is_method () ? 1 : 0; + for (auto referenced_param : function.get_function_params ()) + { + auto tyty_param = fntype->param_at (i); + auto param_tyty = tyty_param.second; + + auto compiled_param_type + = TyTyResolveCompile::compile (ctx, param_tyty); + if (compiled_param_type == nullptr) + { + rust_error_at (referenced_param.get_locus (), + "failed to compile parameter type"); + return; + } + + Location param_locus + = ctx->get_mappings ()->lookup_location (param_tyty->get_ref ()); + Bvariable *compiled_param_var + = CompileFnParam::compile (ctx, fndecl, &referenced_param, + compiled_param_type, param_locus); + if (compiled_param_var == nullptr) + { + rust_error_at (param_locus, "Failed to compile parameter variable"); + return; + } + + param_vars.push_back (compiled_param_var); + + ctx->insert_var_decl (referenced_param.get_mappings ().get_hirid (), + compiled_param_var); + i++; + } + + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) + { + rust_fatal_error (func.get_locus (), + "failed to setup parameter variables"); + return; + } + + // lookup locals + auto block_expr = func.get_block_expr ().get (); + auto body_mappings = block_expr->get_mappings (); + + Resolver::Rib *rib = nullptr; + if (!ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), + &rib)) + { + rust_fatal_error (func.get_locus (), + "failed to setup locals per block"); + return; + } + + std::vector<Bvariable *> locals; + bool ok = compile_locals_for_block (*rib, fndecl, locals); + rust_assert (ok); + + Bblock *enclosing_scope = NULL; + HIR::BlockExpr *function_body = func.get_block_expr ().get (); + Location start_location = function_body->get_locus (); + Location end_location = function_body->get_closing_locus (); + + Bblock *code_block + = ctx->get_backend ()->block (fndecl, enclosing_scope, locals, + start_location, end_location); + ctx->push_block (code_block); + + Bvariable *return_address = nullptr; + if (function.has_return_type ()) + { + Btype *return_type = TyTyResolveCompile::compile (ctx, tyret); + + bool address_is_taken = false; + Bstatement *ret_var_stmt = nullptr; + + return_address = ctx->get_backend ()->temporary_variable ( + fndecl, code_block, return_type, NULL, address_is_taken, + func.get_locus (), &ret_var_stmt); + + ctx->add_statement (ret_var_stmt); + } + + ctx->push_fn (fndecl, return_address); + + compile_function_body (fndecl, func.get_block_expr (), + function.has_return_type ()); + + ctx->pop_block (); + auto body = ctx->get_backend ()->block_statement (code_block); + if (!ctx->get_backend ()->function_set_body (fndecl, body)) + { + rust_error_at (func.get_locus (), "failed to set body to function"); + return; + } + + ctx->pop_fn (); + ctx->push_function (fndecl); + } + +private: + CompileTraitItem (TyTy::BaseType *self, Context *ctx, + TyTy::BaseType *concrete) + : HIRCompileBase (ctx), self (self), concrete (concrete) + {} + + TyTy::BaseType *self; + TyTy::BaseType *concrete; +}; + } // namespace Compile } // namespace Rust 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 5f07a2a..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,24 +80,25 @@ 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); Bfunction *fn = nullptr; 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 ()) @@ -95,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 ()); @@ -114,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) @@ -129,17 +145,52 @@ 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) { // this means we are defaulting back to the trait_item if // possible - // TODO - gcc_unreachable (); + 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 { @@ -169,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); @@ -190,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-tyty.h b/gcc/rust/backend/rust-compile-tyty.h index 3ddc29a..1a5747a 100644 --- a/gcc/rust/backend/rust-compile-tyty.h +++ b/gcc/rust/backend/rust-compile-tyty.h @@ -50,6 +50,8 @@ public: void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } + void visit (TyTy::TupleType &type) override { if (type.num_fields () == 0) diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index b9b5084..baaccf0 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -181,8 +181,32 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) { // this means we are defaulting back to the trait_item if // possible - // TODO - gcc_unreachable (); + 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 + + TyTy::BaseType *self_type = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + expr.get_receiver ()->get_mappings ().get_hirid (), + &self_type)) + { + rust_error_at (expr.get_locus (), + "failed to resolve type for self param"); + return; + } + + CompileTraitItem::Compile (self_type, + trait_item_ref->get_hir_trait_item (), + ctx, fntype); + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) + { + translated = ctx->get_backend ()->error_expression (); + rust_error_at (expr.get_locus (), + "forward declaration was not compiled"); + return; + } } else { @@ -529,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 @@ -579,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/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index b1d0df3..07489f8 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -284,6 +284,9 @@ protected: HIR::Type *lower_type_no_bounds (AST::TypeNoBounds *type); HIR::TypeParamBound *lower_bound (AST::TypeParamBound *bound); + + HIR::QualifiedPathType + lower_qual_path_type (AST::QualifiedPathType &qual_path_type); }; } // namespace HIR diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index 1c48651..3415567 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -48,6 +48,28 @@ private: HIR::PathInExpression *translated; }; +class ASTLowerQualPathInExpression : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::QualifiedPathInExpression * + translate (AST::QualifiedPathInExpression *expr) + { + ASTLowerQualPathInExpression compiler; + expr->accept_vis (compiler); + rust_assert (compiler.translated); + return compiler.translated; + } + + void visit (AST::QualifiedPathInExpression &expr) override; + +private: + ASTLowerQualPathInExpression () : translated (nullptr) {} + + HIR::QualifiedPathInExpression *translated; +}; + class ASTLoweringExpr : public ASTLoweringBase { using Rust::HIR::ASTLoweringBase::visit; @@ -145,6 +167,11 @@ public: translated = ASTLowerPathInExpression::translate (&expr); } + void visit (AST::QualifiedPathInExpression &expr) override + { + translated = ASTLowerQualPathInExpression::translate (&expr); + } + void visit (AST::ReturnExpr &expr) override { terminated = true; diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h index cbc80d3..b2c7b13 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.h +++ b/gcc/rust/hir/rust-ast-lower-implitem.h @@ -354,10 +354,12 @@ public: std::move (function_params), std::move (return_type), std::move (where_clause)); - HIR::Expr *block_expr - = func.has_definition () - ? ASTLoweringExpr::translate (func.get_definition ().get ()) - : nullptr; + bool terminated = false; + std::unique_ptr<HIR::BlockExpr> block_expr + = func.has_definition () ? std::unique_ptr<HIR::BlockExpr> ( + ASTLoweringBlock::translate (func.get_definition ().get (), + &terminated)) + : nullptr; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, func.get_node_id (), @@ -366,13 +368,22 @@ public: HIR::TraitItemFunc *trait_item = new HIR::TraitItemFunc (mapping, std::move (decl), - std::unique_ptr<HIR::Expr> (block_expr), - func.get_outer_attrs (), func.get_locus ()); + std::move (block_expr), func.get_outer_attrs (), + func.get_locus ()); translated = trait_item; mappings->insert_hir_trait_item (mapping.get_crate_num (), mapping.get_hirid (), translated); mappings->insert_location (crate_num, mapping.get_hirid (), trait_item->get_locus ()); + + // add the mappings for the function params at the end + for (auto ¶m : trait_item->get_decl ().get_function_params ()) + { + mappings->insert_hir_param (mapping.get_crate_num (), + param.get_mappings ().get_hirid (), ¶m); + mappings->insert_location (crate_num, mapping.get_hirid (), + param.get_locus ()); + } } void visit (AST::TraitItemMethod &method) override @@ -423,10 +434,12 @@ public: std::move (function_params), std::move (return_type), std::move (where_clause)); - HIR::Expr *block_expr - = method.has_definition () - ? ASTLoweringExpr::translate (method.get_definition ().get ()) - : nullptr; + bool terminated = false; + std::unique_ptr<HIR::BlockExpr> block_expr + = method.has_definition () ? std::unique_ptr<HIR::BlockExpr> ( + ASTLoweringBlock::translate (method.get_definition ().get (), + &terminated)) + : nullptr; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, method.get_node_id (), @@ -435,13 +448,30 @@ public: HIR::TraitItemFunc *trait_item = new HIR::TraitItemFunc (mapping, std::move (decl), - std::unique_ptr<HIR::Expr> (block_expr), + std::move (block_expr), method.get_outer_attrs (), method.get_locus ()); translated = trait_item; mappings->insert_hir_trait_item (mapping.get_crate_num (), mapping.get_hirid (), translated); mappings->insert_location (crate_num, mapping.get_hirid (), trait_item->get_locus ()); + + // insert mappings for self + mappings->insert_hir_self_param (crate_num, + self_param.get_mappings ().get_hirid (), + &self_param); + mappings->insert_location (crate_num, + self_param.get_mappings ().get_hirid (), + self_param.get_locus ()); + + // add the mappings for the function params at the end + for (auto ¶m : trait_item->get_decl ().get_function_params ()) + { + mappings->insert_hir_param (mapping.get_crate_num (), + param.get_mappings ().get_hirid (), ¶m); + mappings->insert_location (crate_num, mapping.get_hirid (), + param.get_locus ()); + } } void visit (AST::TraitItemConst &constant) override diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index ed59777..e693799 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -282,6 +282,55 @@ ASTLowerPathInExpression::visit (AST::PathInExpression &expr) expr.opening_scope_resolution ()); } +HIR::QualifiedPathType +ASTLoweringBase::lower_qual_path_type (AST::QualifiedPathType &qualified_type) +{ + HIR::Type *type + = ASTLoweringType::translate (qualified_type.get_type ().get ()); + HIR::TypePath *trait + = qualified_type.has_as_clause () + ? ASTLowerTypePath::translate (qualified_type.get_as_type_path ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, qualified_type.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + return HIR::QualifiedPathType (mapping, std::unique_ptr<HIR::Type> (type), + std::unique_ptr<HIR::TypePath> (trait), + qualified_type.get_locus ()); +} + +void +ASTLowerQualPathInExpression::visit (AST::QualifiedPathInExpression &expr) +{ + HIR::QualifiedPathType qual_path_type + = lower_qual_path_type (expr.get_qualified_path_type ()); + + std::vector<HIR::PathExprSegment> path_segments; + expr.iterate_path_segments ([&] (AST::PathExprSegment &s) mutable -> bool { + path_segments.push_back (lower_path_expr_seg (s)); + + // insert the mappings for the segment + HIR::PathExprSegment *lowered_seg = &path_segments.back (); + mappings->insert_hir_path_expr_seg ( + lowered_seg->get_mappings ().get_crate_num (), + lowered_seg->get_mappings ().get_hirid (), lowered_seg); + return true; + }); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::QualifiedPathInExpression (mapping, qual_path_type, + std::move (path_segments), + expr.get_locus (), + expr.get_outer_attrs ()); +} + // rust-ast-lower-base.h std::vector<std::unique_ptr<HIR::GenericParam> > diff --git a/gcc/rust/hir/tree/rust-hir-full-test.cc b/gcc/rust/hir/tree/rust-hir-full-test.cc index dee2827..62262a2 100644 --- a/gcc/rust/hir/tree/rust-hir-full-test.cc +++ b/gcc/rust/hir/tree/rust-hir-full-test.cc @@ -1192,11 +1192,11 @@ std::string QualifiedPathType::as_string () const { std::string str ("<"); - str += type_to_invoke_on->as_string (); + str += type->as_string (); if (has_as_clause ()) { - str += " as " + trait_path.as_string (); + str += " as " + trait->as_string (); } return str + ">"; diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 32ee317..3ce1342 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2270,7 +2270,7 @@ class TraitItemFunc : public TraitItem { AST::AttrVec outer_attrs; TraitFunctionDecl decl; - std::unique_ptr<Expr> block_expr; + std::unique_ptr<BlockExpr> block_expr; Location locus; public: @@ -2278,8 +2278,8 @@ public: bool has_definition () const { return block_expr != nullptr; } TraitItemFunc (Analysis::NodeMapping mappings, TraitFunctionDecl decl, - std::unique_ptr<Expr> block_expr, AST::AttrVec outer_attrs, - Location locus) + std::unique_ptr<BlockExpr> block_expr, + AST::AttrVec outer_attrs, Location locus) : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), decl (std::move (decl)), block_expr (std::move (block_expr)), locus (locus) @@ -2291,7 +2291,7 @@ public: decl (other.decl), locus (other.locus) { if (other.block_expr != nullptr) - block_expr = other.block_expr->clone_expr (); + block_expr = other.block_expr->clone_block_expr (); } // Overloaded assignment operator to clone @@ -2303,7 +2303,7 @@ public: locus = other.locus; mappings = other.mappings; if (other.block_expr != nullptr) - block_expr = other.block_expr->clone_expr (); + block_expr = other.block_expr->clone_block_expr (); return *this; } @@ -2322,12 +2322,17 @@ public: bool has_block_defined () const { return block_expr != nullptr; } - std::unique_ptr<Expr> &get_block_expr () + std::unique_ptr<BlockExpr> &get_block_expr () { rust_assert (has_block_defined ()); return block_expr; } + const std::string trait_identifier () const override final + { + return decl.get_function_name (); + } + protected: // Clone function implementation as (not pure) virtual method TraitItemFunc *clone_trait_item_impl () const override @@ -2400,6 +2405,8 @@ public: return expr; } + const std::string trait_identifier () const override final { return name; } + protected: // Clone function implementation as (not pure) virtual method TraitItemConst *clone_trait_item_impl () const override @@ -2474,6 +2481,8 @@ public: return type_param_bounds; } + const std::string trait_identifier () const override final { return name; } + protected: // Clone function implementation as (not pure) virtual method TraitItemType *clone_trait_item_impl () const override diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 5d9f965..a8bbbb6 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -709,26 +709,26 @@ public: struct QualifiedPathType { private: - std::unique_ptr<Type> type_to_invoke_on; - - // bool has_as_clause; - TypePath trait_path; - + std::unique_ptr<Type> type; + std::unique_ptr<TypePath> trait; Location locus; + Analysis::NodeMapping mappings; public: // Constructor - QualifiedPathType (std::unique_ptr<Type> invoke_on_type, - Location locus = Location (), - TypePath trait_path = TypePath::create_error ()) - : type_to_invoke_on (std::move (invoke_on_type)), - trait_path (std::move (trait_path)), locus (locus) + QualifiedPathType (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, + std::unique_ptr<TypePath> trait, Location locus) + : type (std::move (type)), trait (std::move (trait)), locus (locus), + mappings (mappings) {} // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType (QualifiedPathType const &other) - : type_to_invoke_on (other.type_to_invoke_on->clone_type ()), - trait_path (other.trait_path), locus (other.locus) + : type (other.type->clone_type ()), + trait (other.has_as_clause () ? std::unique_ptr<HIR::TypePath> ( + new HIR::TypePath (*other.trait)) + : nullptr), + locus (other.locus), mappings (other.mappings) {} // default destructor @@ -737,9 +737,14 @@ public: // overload assignment operator to use custom clone method QualifiedPathType &operator= (QualifiedPathType const &other) { - type_to_invoke_on = other.type_to_invoke_on->clone_type (); - trait_path = other.trait_path; + type = other.type->clone_type (); locus = other.locus; + mappings = other.mappings; + trait + = other.has_as_clause () + ? std::unique_ptr<HIR::TypePath> (new HIR::TypePath (*other.trait)) + : nullptr; + return *this; } @@ -748,20 +753,21 @@ public: QualifiedPathType &operator= (QualifiedPathType &&other) = default; // Returns whether the qualified path type has a rebind as clause. - bool has_as_clause () const { return !trait_path.is_error (); } - - // Returns whether the qualified path type is in an error state. - bool is_error () const { return type_to_invoke_on == nullptr; } - - // Creates an error state qualified path type. - static QualifiedPathType create_error () - { - return QualifiedPathType (nullptr); - } + bool has_as_clause () const { return trait != nullptr; } std::string as_string () const; Location get_locus () const { return locus; } + + Analysis::NodeMapping get_mappings () const { return mappings; } + + std::unique_ptr<Type> &get_type () { return type; } + + std::unique_ptr<TypePath> &get_trait () + { + rust_assert (has_as_clause ()); + return trait; + } }; /* HIR node representing a qualified path-in-expression pattern (path that @@ -785,25 +791,15 @@ public: path_type (std::move (qual_path_type)), locus (locus) {} - /* TODO: maybe make a shortcut constructor that has QualifiedPathType elements - * as params */ - - // Returns whether qualified path in expression is in an error state. - bool is_error () const { return path_type.is_error (); } - - // Creates an error qualified path in expression. - static QualifiedPathInExpression create_error () - { - return QualifiedPathInExpression (Analysis::NodeMapping::get_error (), - QualifiedPathType::create_error (), - std::vector<PathExprSegment> ()); - } - Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } void accept_vis (HIRVisitor &vis) override; + QualifiedPathType &get_path_type () { return path_type; } + + Location get_locus () { return locus; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index 20408bb..b8acf1a 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -646,7 +646,9 @@ public: virtual void accept_vis (HIRVisitor &vis) = 0; - const Analysis::NodeMapping &get_mappings () const { return mappings; } + virtual const std::string trait_identifier () const = 0; + + const Analysis::NodeMapping get_mappings () const { return mappings; } }; class ImplItem diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index e7e37d4..c5f88f9 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -39,10 +39,22 @@ public: resolver.resolve_path (expr); } + static void go (AST::QualifiedPathInExpression *expr, NodeId parent) + { + ResolvePath resolver (parent); + resolver.resolve_path (expr); + } + private: ResolvePath (NodeId parent) : ResolverBase (parent) {} void resolve_path (AST::PathInExpression *expr); + + void resolve_path (AST::QualifiedPathInExpression *expr); + + void resolve_segments (CanonicalPath prefix, size_t offs, + std::vector<AST::PathExprSegment> &segs, + NodeId expr_node_id, Location expr_locus); }; class ResolveExpr : public ResolverBase @@ -75,6 +87,11 @@ public: ResolvePath::go (&expr, parent); } + void visit (AST::QualifiedPathInExpression &expr) override + { + ResolvePath::go (&expr, parent); + } + void visit (AST::ReturnExpr &expr) override { if (expr.has_returned_expr ()) diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 2c1de66..1239206 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -206,6 +206,19 @@ public: impl_type_seg); CanonicalPath impl_prefix = prefix.append (projection); + resolver->get_name_scope ().insert ( + impl_prefix, impl_block.get_node_id (), impl_block.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (impl_block.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + resolver->insert_new_definition (impl_block.get_node_id (), + Definition{impl_block.get_node_id (), + impl_block.get_node_id ()}); + resolver->insert_resolved_name (impl_block.get_node_id (), + impl_block.get_node_id ()); + for (auto &impl_item : impl_block.get_impl_items ()) ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); } diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 5b24816..5b6bb24 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -483,12 +483,13 @@ void ResolvePath::resolve_path (AST::PathInExpression *expr) { // resolve root segment first then apply segments in turn - AST::PathExprSegment &root_segment = expr->get_segments ().at (0); + std::vector<AST::PathExprSegment> &segs = expr->get_segments (); + AST::PathExprSegment &root_segment = segs.at (0); AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment (); bool segment_is_type = false; CanonicalPath root_seg_path - = CanonicalPath::new_seg (expr->get_node_id (), + = CanonicalPath::new_seg (root_segment.get_node_id (), root_ident_seg.as_string ()); // name scope first @@ -515,7 +516,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) { rust_error_at (expr->get_locus (), "Cannot find path %<%s%> in this scope", - expr->as_string ().c_str ()); + root_segment.as_string ().c_str ()); return; } @@ -531,7 +532,8 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } } - if (expr->is_single_segment ()) + bool is_single_segment = segs.size () == 1; + if (is_single_segment) { if (segment_is_type) resolver->insert_resolved_type (expr->get_node_id (), resolved_node); @@ -544,11 +546,97 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) return; } + resolve_segments (root_seg_path, 1, expr->get_segments (), + expr->get_node_id (), expr->get_locus ()); +} + +void +ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr) +{ + AST::QualifiedPathType &root_segment = expr->get_qualified_path_type (); + + bool canonicalize_type_with_generics = false; + ResolveType::go (&root_segment.get_as_type_path (), + root_segment.get_node_id (), + canonicalize_type_with_generics); + + ResolveType::go (root_segment.get_type ().get (), root_segment.get_node_id (), + canonicalize_type_with_generics); + + bool canonicalize_type_args = true; + bool type_resolve_generic_args = true; + + CanonicalPath impl_type_seg + = ResolveTypeToCanonicalPath::resolve (*root_segment.get_type ().get (), + canonicalize_type_args, + type_resolve_generic_args); + + CanonicalPath trait_type_seg + = ResolveTypeToCanonicalPath::resolve (root_segment.get_as_type_path (), + canonicalize_type_args, + type_resolve_generic_args); + CanonicalPath root_seg_path + = TraitImplProjection::resolve (root_segment.get_node_id (), trait_type_seg, + impl_type_seg); + bool segment_is_type = false; + + // name scope first + if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = false; + resolver->insert_resolved_name (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = true; + resolver->insert_resolved_type (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + else + { + rust_error_at (expr->get_locus (), + "Cannot find path %<%s%> in this scope", + root_segment.as_string ().c_str ()); + return; + } + + bool is_single_segment = expr->get_segments ().empty (); + if (is_single_segment) + { + if (segment_is_type) + resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + else + resolver->insert_resolved_name (expr->get_node_id (), resolved_node); + + resolver->insert_new_definition (expr->get_node_id (), + Definition{expr->get_node_id (), + parent}); + return; + } + + resolve_segments (root_seg_path, 0, expr->get_segments (), + expr->get_node_id (), expr->get_locus ()); +} + +void +ResolvePath::resolve_segments (CanonicalPath prefix, size_t offs, + std::vector<AST::PathExprSegment> &segs, + NodeId expr_node_id, Location expr_locus) +{ // we can attempt to resolve this path fully - CanonicalPath path = root_seg_path; - for (size_t i = 1; i < expr->get_segments ().size (); i++) + CanonicalPath path = prefix; + bool segment_is_type = false; + for (size_t i = offs; i < segs.size (); i++) { - AST::PathExprSegment &seg = expr->get_segments ().at (i); + AST::PathExprSegment &seg = segs.at (i); auto s = ResolvePathSegmentToCanonicalPath::resolve (seg); path = path.append (s); @@ -560,8 +648,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) { resolver->insert_resolved_name (seg.get_node_id (), resolved_node); resolver->insert_new_definition (seg.get_node_id (), - Definition{expr->get_node_id (), - parent}); + Definition{expr_node_id, parent}); } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) @@ -569,8 +656,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) segment_is_type = true; resolver->insert_resolved_type (seg.get_node_id (), resolved_node); resolver->insert_new_definition (seg.get_node_id (), - Definition{expr->get_node_id (), - parent}); + Definition{expr_node_id, parent}); } else { @@ -621,13 +707,12 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) if (resolved_node != UNKNOWN_NODEID) { if (segment_is_type) - resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + resolver->insert_resolved_type (expr_node_id, resolved_node); else - resolver->insert_resolved_name (expr->get_node_id (), resolved_node); + resolver->insert_resolved_name (expr_node_id, resolved_node); - resolver->insert_new_definition (expr->get_node_id (), - Definition{expr->get_node_id (), - parent}); + resolver->insert_new_definition (expr_node_id, + Definition{expr_node_id, parent}); } } diff --git a/gcc/rust/typecheck/rust-hir-const-fold.h b/gcc/rust/typecheck/rust-hir-const-fold.h index 8efbb18..9e0450e 100644 --- a/gcc/rust/typecheck/rust-hir-const-fold.h +++ b/gcc/rust/typecheck/rust-hir-const-fold.h @@ -55,6 +55,8 @@ public: void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } + void visit (TyTy::TupleType &type) override { if (type.num_fields () == 0) diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 22b1074..f737141 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -51,6 +51,7 @@ struct PathProbeCandidate { const TraitReference *trait_ref; const TraitItemReference *item_ref; + HIR::ImplBlock *impl; }; CandidateType type; @@ -128,19 +129,22 @@ public: if (!probe_bounds) return probe.candidates; - std::vector<TraitReference *> probed_bounds + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds = TypeBoundsProbe::Probe (receiver); - std::vector<const TraitReference *> specified_bounds; + std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> + specified_bounds; for (const TyTy::TypeBoundPredicate &predicate : receiver->get_specified_bounds ()) { const TraitReference *trait_item = predicate.get (); - specified_bounds.push_back (trait_item); + + // FIXME lookup impl_block for this trait impl for this receiver + specified_bounds.push_back ({trait_item, nullptr}); } - std::vector<const TraitReference *> union_type_bounds - = probe.union_bounds (probed_bounds, specified_bounds); + std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> + union_type_bounds = probe.union_bounds (probed_bounds, specified_bounds); probe.process_traits_for_candidates (union_type_bounds, ignore_mandatory_trait_items); return probe.candidates; @@ -230,11 +234,15 @@ private: } void process_traits_for_candidates ( - const std::vector<const TraitReference *> traits, + const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> + traits, bool ignore_mandatory_trait_items) { - for (const TraitReference *trait_ref : traits) + for (auto &ref : traits) { + const TraitReference *trait_ref = ref.first; + HIR::ImplBlock *impl = ref.second; + const TraitItemReference *trait_item_ref = nullptr; if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref)) @@ -296,7 +304,7 @@ private: } PathProbeCandidate::TraitItemCandidate trait_item_candidate{ - trait_ref, trait_item_ref}; + trait_ref, trait_item_ref, impl}; PathProbeCandidate candidate{candidate_type, trait_item_tyty, trait_ref->get_locus (), @@ -312,24 +320,27 @@ private: current_impl (nullptr) {} - std::vector<const TraitReference *> - union_bounds (const std::vector</*const*/ TraitReference *> a, - const std::vector<const TraitReference *> b) const + std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> + union_bounds ( + const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>> + a, + const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b) + const { - std::map<DefId, const TraitReference *> mapper; - for (const TraitReference *ref : a) + std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper; + for (auto &ref : a) { - mapper.insert ({ref->get_mappings ().get_defid (), ref}); + mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); } - for (const TraitReference *ref : b) + for (auto &ref : b) { - mapper.insert ({ref->get_mappings ().get_defid (), ref}); + mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); } - std::vector<const TraitReference *> union_set; + std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set; for (auto it = mapper.begin (); it != mapper.end (); it++) { - union_set.push_back (it->second); + union_set.push_back ({it->second.first, it->second.second}); } return union_set; } diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 21a8beb..9d16e36 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -21,6 +21,7 @@ #include "rust-hir-full.h" #include "rust-tyty-visitor.h" +#include "rust-hir-type-check-util.h" namespace Rust { namespace Resolver { @@ -111,9 +112,11 @@ public: const HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; } + HIR::TraitItem *get_hir_trait_item () { return hir_trait_item; } + Location get_locus () const { return locus; } - const Analysis::NodeMapping &get_mappings () const + const Analysis::NodeMapping get_mappings () const { return hir_trait_item->get_mappings (); } @@ -146,6 +149,19 @@ public: return get_error (); } + Analysis::NodeMapping get_parent_trait_mappings () const; + + // this is called when the trait is completed resolution and gives the items a + // chance to run their specific type resolution passes. If we call their + // resolution on construction it can lead to a case where the trait being + // resolved recursively trying to resolve the trait itself infinitely since + // the trait will not be stored in its own map yet + void on_resolved (); + + void associated_type_set (TyTy::BaseType *ty); + + void associated_type_reset (); + private: TyTy::ErrorType *get_error () const { @@ -160,6 +176,11 @@ private: TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const; + bool is_item_resolved () const; + void resolve_item (HIR::TraitItemType &type); + void resolve_item (HIR::TraitItemConst &constant); + void resolve_item (HIR::TraitItemFunc &func); + std::string identifier; bool optional_flag; TraitItemType type; @@ -172,6 +193,7 @@ private: Resolver::TypeCheckContext *context; }; +// this wraps up the HIR::Trait so we can do analysis on it class TraitReference { public: @@ -233,6 +255,31 @@ public: return hir_trait_ref->get_mappings (); } + bool lookup_hir_trait_item (const HIR::TraitItem &item, + TraitItemReference **ref) + { + return lookup_trait_item (item.trait_identifier (), ref); + } + + bool lookup_trait_item (const std::string &ident, TraitItemReference **ref) + { + for (auto &item : item_refs) + { + if (ident.compare (item.get_identifier ()) == 0) + { + *ref = &item; + return true; + } + } + return false; + } + + bool lookup_hir_trait_item (const HIR::TraitItem &item, + const TraitItemReference **ref) const + { + return lookup_trait_item (item.trait_identifier (), ref); + } + bool lookup_trait_item (const std::string &ident, const TraitItemReference **ref) const { @@ -269,11 +316,60 @@ public: return item_refs; } + void on_resolved () + { + for (auto &item : item_refs) + { + item.on_resolved (); + } + } + + void clear_associated_types () + { + for (auto &item : item_refs) + { + bool is_assoc_type = item.get_trait_item_type () + == TraitItemReference::TraitItemType::TYPE; + if (is_assoc_type) + item.associated_type_reset (); + } + } + private: const HIR::Trait *hir_trait_ref; std::vector<TraitItemReference> item_refs; }; +class AssociatedImplTrait +{ +public: + AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl, + TyTy::BaseType *self, + Resolver::TypeCheckContext *context) + : trait (trait), impl (impl), self (self), context (context) + {} + + TraitReference *get_trait () { return trait; } + + HIR::ImplBlock *get_impl_block () { return impl; } + + TyTy::BaseType *get_self () { return self; } + + void setup_associated_types (); + + 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; + TyTy::BaseType *self; + Resolver::TypeCheckContext *context; +}; + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc new file mode 100644 index 0000000..cf3f2fb --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -0,0 +1,231 @@ +// Copyright (C) 2021 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-trait-resolve.h" +#include "rust-hir-type-check-expr.h" + +namespace Rust { +namespace Resolver { + +void +ResolveTraitItemToRef::visit (HIR::TraitItemType &type) +{ + // create trait-item-ref + Location locus = type.get_locus (); + bool is_optional = false; + std::string identifier = type.get_name (); + + resolved = TraitItemReference (identifier, is_optional, + TraitItemReference::TraitItemType::TYPE, &type, + self, substitutions, locus); +} + +void +ResolveTraitItemToRef::visit (HIR::TraitItemConst &cst) +{ + // create trait-item-ref + Location locus = cst.get_locus (); + bool is_optional = cst.has_expr (); + std::string identifier = cst.get_name (); + + resolved = TraitItemReference (identifier, is_optional, + TraitItemReference::TraitItemType::CONST, &cst, + self, substitutions, locus); +} + +void +ResolveTraitItemToRef::visit (HIR::TraitItemFunc &fn) +{ + // create trait-item-ref + Location locus = fn.get_locus (); + bool is_optional = fn.has_block_defined (); + std::string identifier = fn.get_decl ().get_function_name (); + + resolved = TraitItemReference (identifier, is_optional, + TraitItemReference::TraitItemType::FN, &fn, + self, substitutions, locus); +} + +// TraitItemReference items + +void +TraitItemReference::on_resolved () +{ + switch (type) + { + case CONST: + resolve_item (static_cast<HIR::TraitItemConst &> (*hir_trait_item)); + break; + + case TYPE: + resolve_item (static_cast<HIR::TraitItemType &> (*hir_trait_item)); + break; + + case FN: + resolve_item (static_cast<HIR::TraitItemFunc &> (*hir_trait_item)); + break; + + default: + break; + } +} + +void +TraitItemReference::resolve_item (HIR::TraitItemType &type) +{ + TyTy::BaseType *ty + = new TyTy::PlaceholderType (type.get_name (), + type.get_mappings ().get_hirid ()); + context->insert_type (type.get_mappings (), ty); +} + +void +TraitItemReference::resolve_item (HIR::TraitItemConst &constant) +{ + // TODO +} + +void +TraitItemReference::resolve_item (HIR::TraitItemFunc &func) +{ + if (!is_optional ()) + return; + + TyTy::BaseType *item_tyty = get_tyty (); + if (item_tyty->get_kind () == TyTy::TypeKind::ERROR) + return; + + // check the block and return types + rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF); + + // need to get the return type from this + TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (item_tyty); + auto expected_ret_tyty = resolved_fn_type->get_return_type (); + context->push_return_type (expected_ret_tyty); + + auto block_expr_ty + = TypeCheckExpr::Resolve (func.get_block_expr ().get (), false); + + context->pop_return_type (); + + if (block_expr_ty->get_kind () != TyTy::NEVER) + expected_ret_tyty->unify (block_expr_ty); +} + +void +TraitItemReference::associated_type_set (TyTy::BaseType *ty) +{ + rust_assert (get_trait_item_type () == TraitItemType::TYPE); + + TyTy::BaseType *item_ty = get_tyty (); + rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER); + TyTy::PlaceholderType *placeholder + = static_cast<TyTy::PlaceholderType *> (item_ty); + + placeholder->set_associated_type (ty->get_ref ()); +} + +void +TraitItemReference::associated_type_reset () +{ + rust_assert (get_trait_item_type () == TraitItemType::TYPE); + + TyTy::BaseType *item_ty = get_tyty (); + rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER); + TyTy::PlaceholderType *placeholder + = static_cast<TyTy::PlaceholderType *> (item_ty); + + placeholder->clear_associated_type (); +} + +void +AssociatedImplTrait::setup_associated_types () +{ + ImplTypeIterator iter (*impl, [&] (HIR::TypeAlias &type) { + TraitItemReference *resolved_trait_item = nullptr; + bool ok = trait->lookup_trait_item (type.get_new_type_name (), + &resolved_trait_item); + if (!ok) + return; + if (resolved_trait_item->get_trait_item_type () + != TraitItemReference::TraitItemType::TYPE) + return; + + TyTy::BaseType *lookup; + if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup)) + return; + + resolved_trait_item->associated_type_set (lookup); + }); + iter.go (); +} + +void +AssociatedImplTrait::reset_associated_types () +{ + trait->clear_associated_types (); +} + +Analysis::NodeMapping +TraitItemReference::get_parent_trait_mappings () const +{ + auto mappings = Analysis::Mappings::get (); + + HIR::Trait *trait + = mappings->lookup_trait_item_mapping (get_mappings ().get_hirid ()); + rust_assert (trait != nullptr); + + 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-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 1669a37..6874a3a 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -42,45 +42,11 @@ public: return resolver.resolved; } - void visit (HIR::TraitItemType &type) override - { - TyTy::BaseType *ty - = new TyTy::PlaceholderType (type.get_mappings ().get_hirid ()); - context->insert_type (type.get_mappings (), ty); - - // create trait-item-ref - Location locus = type.get_locus (); - bool is_optional = false; - std::string identifier = type.get_name (); - - resolved = TraitItemReference (identifier, is_optional, - TraitItemReference::TraitItemType::TYPE, - &type, self, substitutions, locus); - } + void visit (HIR::TraitItemType &type) override; - void visit (HIR::TraitItemConst &cst) override - { - // create trait-item-ref - Location locus = cst.get_locus (); - bool is_optional = cst.has_expr (); - std::string identifier = cst.get_name (); - - resolved = TraitItemReference (identifier, is_optional, - TraitItemReference::TraitItemType::CONST, - &cst, self, substitutions, locus); - } + void visit (HIR::TraitItemConst &cst) override; - void visit (HIR::TraitItemFunc &fn) override - { - // create trait-item-ref - Location locus = fn.get_locus (); - bool is_optional = fn.has_block_defined (); - std::string identifier = fn.get_decl ().get_function_name (); - - resolved = TraitItemReference (identifier, is_optional, - TraitItemReference::TraitItemType::FN, &fn, - self, substitutions, locus); - } + void visit (HIR::TraitItemFunc &fn) override; private: ResolveTraitItemToRef ( @@ -188,6 +154,11 @@ private: trait_reference->get_mappings ().get_defid (), &tref); rust_assert (ok); + // hook to allow the trait to resolve its optional item blocks, we cant + // resolve the blocks of functions etc because it can end up in a recursive + // loop of trying to resolve traits as required by the types + tref->on_resolved (); + return tref; } diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index ce694da..1ba6049 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -31,13 +31,28 @@ class TypeBoundsProbe : public TypeCheckBase using Rust::Resolver::TypeCheckBase::visit; public: - static std::vector<TraitReference *> Probe (const TyTy::BaseType *receiver) + static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> + Probe (const TyTy::BaseType *receiver) { TypeBoundsProbe probe (receiver); probe.scan (); return probe.trait_references; } + static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver, + TraitReference *ref) + { + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds + = Probe (receiver); + for (auto &bound : bounds) + { + TraitReference *b = bound.first; + if (b == ref) + return true; + } + return false; + } + private: void scan (); @@ -47,7 +62,7 @@ private: {} const TyTy::BaseType *receiver; - std::vector<TraitReference *> trait_references; + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index d39b2ee..e3347ea 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -28,6 +28,8 @@ #include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" #include "rust-hir-const-fold.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-type-bounds.h" namespace Rust { namespace Resolver { @@ -923,146 +925,168 @@ public: infered = resolved->get_field_type (); } - void visit (HIR::PathInExpression &expr) override + void visit (HIR::QualifiedPathInExpression &expr) override { - NodeId resolved_node_id = UNKNOWN_NODEID; + 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; - size_t offset = -1; - TyTy::BaseType *tyseg - = resolve_root_path (expr, &offset, &resolved_node_id); + 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 ()); + } - rust_assert (tyseg != nullptr); + // Resolve the trait now + TraitReference *trait_ref + = TraitResolver::Resolve (*qual_path_type.get_trait ().get ()); + if (trait_ref->is_error ()) + return; - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + // does this type actually implement this type-bound? + if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref)) return; - // this is the case where the name resolver has already fully resolved the - // name, which means all the work is already done. - bool name_resolved_fully = offset >= expr.get_num_segments (); + // then we need to look at the next segment to create perform the correct + // projection type + if (expr.get_segments ().empty ()) + return; - if (expr.get_num_segments () == 1) - { - Location locus = expr.get_segments ().back ().get_locus (); + // 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); - 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); - } + 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); - infered = tyseg; - return; - } + AssociatedImplTrait *lookup_associated = nullptr; + bool found_impl_trait + = context->lookup_associated_trait_impl (impl_block_id, + &lookup_associated); + rust_assert (found_impl_trait); - TyTy::BaseType *prev_segment = tyseg; - for (size_t i = offset; i < expr.get_num_segments (); i++) + 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) { - HIR::PathExprSegment &seg = expr.get_segments ().at (i); + rust_error_at (item_seg.get_locus (), "unknown associated item"); + return; + } + resolved_item_id = trait_item_ref->get_mappings ().get_defid (); - 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; + infered = lookup_associated->get_projected_type ( + trait_item_ref, root, item_seg.get_mappings ().get_hirid (), + item_seg.get_locus ()); - // probe the path - auto candidates - = PathProbeType::Probe (tyseg, 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) + // turbo-fish segment path::<ty> + if (item_seg.has_generic_args ()) + { + if (!infered->can_substitute ()) { - ReportMultipleCandidateError::Report (candidates, - seg.get_segment (), - seg.get_locus ()); + 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 ()); + } - auto &candidate = candidates.at (0); - prev_segment = tyseg; - tyseg = candidate.ty; + 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); - 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 (); - } + // 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 (seg.has_generic_args ()) + 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)) { - if (!tyseg->can_substitute ()) - { - rust_error_at (expr.get_locus (), - "substitutions not supported for %s", - tyseg->as_string ().c_str ()); - return; - } - - tyseg = SubstMapper::Resolve (tyseg, expr.get_locus (), - &seg.get_generic_args ()); - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; + rust_assert (path_resolved_id == root_resolved_node_id); } - } - - context->insert_receiver (expr.get_mappings ().get_hirid (), prev_segment); - if (tyseg->needs_generic_substitutions ()) - { - Location locus = expr.get_segments ().back ().get_locus (); - if (!prev_segment->needs_generic_substitutions ()) + // check the type scope + else if (resolver->lookup_resolved_type ( + expr.get_mappings ().get_nodeid (), &path_resolved_id)) { - 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); + rust_assert (path_resolved_id == root_resolved_node_id); } else { - tyseg = SubstMapper::InferSubst (tyseg, locus); + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + root_resolved_node_id); } - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; + context->insert_receiver (expr.get_mappings ().get_hirid (), root); + return; } - rust_assert (resolved_node_id != UNKNOWN_NODEID); + resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered, + expr.get_mappings (), expr.get_locus ()); + } - // 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 == resolved_node_id); - } - // check the type scope - else if (resolver->lookup_resolved_type (expr.get_mappings ().get_nodeid (), - &path_resolved_id)) + 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_assert (path_resolved_id == resolved_node_id); + rust_debug_loc (expr.get_locus (), "failed to resolve root_seg"); } - else if (!name_resolved_fully) + rust_assert (tyseg != nullptr); + + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + + if (expr.get_num_segments () == 1) { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); + 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; } - infered = tyseg; + resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg, + expr.get_mappings (), expr.get_locus ()); } void visit (HIR::LoopExpr &expr) override @@ -1353,6 +1377,136 @@ private: return root_tyty; } + 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; + } + bool validate_arithmetic_type (TyTy::BaseType *type, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 65088be..3d83523 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -383,8 +383,7 @@ public: trait_reference.get_name ().c_str ()); } - context->insert_type (resolved_trait_item.get_mappings (), - lookup->clone ()); + resolved_trait_item.associated_type_set (lookup); } void visit (HIR::Function &function) override diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 372171f..72da26d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -123,6 +123,19 @@ public: trait_reference->get_name ().c_str ()); } } + + if (is_trait_impl_block) + { + trait_reference->clear_associated_types (); + + AssociatedImplTrait associated (trait_reference, &impl_block, self, + context); + context->insert_associated_trait_impl ( + impl_block.get_mappings ().get_hirid (), std::move (associated)); + context->insert_associated_impl_mapping ( + trait_reference->get_mappings ().get_hirid (), self, + impl_block.get_mappings ().get_hirid ()); + } } void visit (HIR::Function &function) override diff --git a/gcc/rust/typecheck/rust-hir-type-check-util.cc b/gcc/rust/typecheck/rust-hir-type-check-util.cc new file mode 100644 index 0000000..82bd081 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-util.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2021 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-util.h" +#include "rust-hir-full.h" + +namespace Rust { +namespace Resolver { + +void +ImplTypeIterator::go () +{ + for (auto &item : impl.get_impl_items ()) + { + item->accept_vis (*this); + } +} + +void +ImplTypeIterator::visit (HIR::TypeAlias &alias) +{ + cb (alias); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-util.h b/gcc/rust/typecheck/rust-hir-type-check-util.h new file mode 100644 index 0000000..0ba07a1 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-util.h @@ -0,0 +1,216 @@ +// Copyright (C) 2021 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/>. + +#ifndef RUST_HIR_TYPE_CHECK_UTIL_H +#define RUST_HIR_TYPE_CHECK_UTIL_H + +#include <functional> +#include "rust-hir-visitor.h" + +namespace Rust { +namespace Resolver { + +class SimpleHirVisitor : public HIR::HIRVisitor +{ +public: + virtual ~SimpleHirVisitor () {} + + virtual void visit (HIR::IdentifierExpr &) override {} + virtual void visit (HIR::Lifetime &) override {} + virtual void visit (HIR::LifetimeParam &) override {} + virtual void visit (HIR::PathInExpression &) override {} + virtual void visit (HIR::TypePathSegment &) override {} + virtual void visit (HIR::TypePathSegmentGeneric &) override {} + virtual void visit (HIR::TypePathSegmentFunction &) override {} + virtual void visit (HIR::TypePath &) override {} + virtual void visit (HIR::QualifiedPathInExpression &) override {} + virtual void visit (HIR::QualifiedPathInType &) override {} + + virtual void visit (HIR::LiteralExpr &) override {} + virtual void visit (HIR::BorrowExpr &) override {} + virtual void visit (HIR::DereferenceExpr &) override {} + virtual void visit (HIR::ErrorPropagationExpr &) override {} + virtual void visit (HIR::NegationExpr &) override {} + virtual void visit (HIR::ArithmeticOrLogicalExpr &) override {} + virtual void visit (HIR::ComparisonExpr &) override {} + virtual void visit (HIR::LazyBooleanExpr &) override {} + virtual void visit (HIR::TypeCastExpr &) override {} + virtual void visit (HIR::AssignmentExpr &) override {} + + virtual void visit (HIR::GroupedExpr &) override {} + + virtual void visit (HIR::ArrayElemsValues &) override {} + virtual void visit (HIR::ArrayElemsCopied &) override {} + virtual void visit (HIR::ArrayExpr &) override {} + virtual void visit (HIR::ArrayIndexExpr &) override {} + virtual void visit (HIR::TupleExpr &) override {} + virtual void visit (HIR::TupleIndexExpr &) override {} + virtual void visit (HIR::StructExprStruct &) override {} + + virtual void visit (HIR::StructExprFieldIdentifier &) override {} + virtual void visit (HIR::StructExprFieldIdentifierValue &) override {} + + virtual void visit (HIR::StructExprFieldIndexValue &) override {} + virtual void visit (HIR::StructExprStructFields &) override {} + virtual void visit (HIR::StructExprStructBase &) override {} + virtual void visit (HIR::StructExprTuple &) override {} + virtual void visit (HIR::StructExprUnit &) override {} + + virtual void visit (HIR::EnumExprFieldIdentifier &) override {} + virtual void visit (HIR::EnumExprFieldIdentifierValue &) override {} + + virtual void visit (HIR::EnumExprFieldIndexValue &) override {} + virtual void visit (HIR::EnumExprStruct &) override {} + virtual void visit (HIR::EnumExprTuple &) override {} + virtual void visit (HIR::EnumExprFieldless &) override {} + virtual void visit (HIR::CallExpr &) override {} + virtual void visit (HIR::MethodCallExpr &) override {} + virtual void visit (HIR::FieldAccessExpr &) override {} + virtual void visit (HIR::ClosureExprInner &) override {} + virtual void visit (HIR::BlockExpr &) override {} + virtual void visit (HIR::ClosureExprInnerTyped &) override {} + virtual void visit (HIR::ContinueExpr &) override {} + virtual void visit (HIR::BreakExpr &) override {} + virtual void visit (HIR::RangeFromToExpr &) override {} + virtual void visit (HIR::RangeFromExpr &) override {} + virtual void visit (HIR::RangeToExpr &) override {} + virtual void visit (HIR::RangeFullExpr &) override {} + virtual void visit (HIR::RangeFromToInclExpr &) override {} + virtual void visit (HIR::RangeToInclExpr &) override {} + virtual void visit (HIR::ReturnExpr &) override {} + virtual void visit (HIR::UnsafeBlockExpr &) override {} + virtual void visit (HIR::LoopExpr &) override {} + virtual void visit (HIR::WhileLoopExpr &) override {} + virtual void visit (HIR::WhileLetLoopExpr &) override {} + virtual void visit (HIR::ForLoopExpr &) override {} + virtual void visit (HIR::IfExpr &) override {} + virtual void visit (HIR::IfExprConseqElse &) override {} + virtual void visit (HIR::IfExprConseqIf &) override {} + virtual void visit (HIR::IfExprConseqIfLet &) override {} + virtual void visit (HIR::IfLetExpr &) override {} + virtual void visit (HIR::IfLetExprConseqElse &) override {} + virtual void visit (HIR::IfLetExprConseqIf &) override {} + virtual void visit (HIR::IfLetExprConseqIfLet &) override {} + + virtual void visit (HIR::MatchExpr &) override {} + virtual void visit (HIR::AwaitExpr &) override {} + virtual void visit (HIR::AsyncBlockExpr &) override {} + + virtual void visit (HIR::TypeParam &) override {} + + virtual void visit (HIR::LifetimeWhereClauseItem &) override {} + virtual void visit (HIR::TypeBoundWhereClauseItem &) override {} + virtual void visit (HIR::ModuleBodied &) override {} + virtual void visit (HIR::ModuleNoBody &) override {} + virtual void visit (HIR::ExternCrate &) override {} + + virtual void visit (HIR::UseTreeGlob &) override {} + virtual void visit (HIR::UseTreeList &) override {} + virtual void visit (HIR::UseTreeRebind &) override {} + virtual void visit (HIR::UseDeclaration &) override {} + virtual void visit (HIR::Function &) override {} + virtual void visit (HIR::TypeAlias &) override {} + virtual void visit (HIR::StructStruct &) override {} + virtual void visit (HIR::TupleStruct &) override {} + virtual void visit (HIR::EnumItem &) override {} + virtual void visit (HIR::EnumItemTuple &) override {} + virtual void visit (HIR::EnumItemStruct &) override {} + virtual void visit (HIR::EnumItemDiscriminant &) override {} + virtual void visit (HIR::Enum &) override {} + virtual void visit (HIR::Union &) override {} + virtual void visit (HIR::ConstantItem &) override {} + virtual void visit (HIR::StaticItem &) override {} + virtual void visit (HIR::TraitItemFunc &) override {} + virtual void visit (HIR::TraitItemConst &) override {} + virtual void visit (HIR::TraitItemType &) override {} + virtual void visit (HIR::Trait &) override {} + virtual void visit (HIR::ImplBlock &) override {} + + virtual void visit (HIR::ExternalStaticItem &) override {} + virtual void visit (HIR::ExternalFunctionItem &) override {} + virtual void visit (HIR::ExternBlock &) override {} + + virtual void visit (HIR::LiteralPattern &) override {} + virtual void visit (HIR::IdentifierPattern &) override {} + virtual void visit (HIR::WildcardPattern &) override {} + + virtual void visit (HIR::RangePatternBoundLiteral &) override {} + virtual void visit (HIR::RangePatternBoundPath &) override {} + virtual void visit (HIR::RangePatternBoundQualPath &) override {} + virtual void visit (HIR::RangePattern &) override {} + virtual void visit (HIR::ReferencePattern &) override {} + + virtual void visit (HIR::StructPatternFieldTuplePat &) override {} + virtual void visit (HIR::StructPatternFieldIdentPat &) override {} + virtual void visit (HIR::StructPatternFieldIdent &) override {} + virtual void visit (HIR::StructPattern &) override {} + + virtual void visit (HIR::TupleStructItemsNoRange &) override {} + virtual void visit (HIR::TupleStructItemsRange &) override {} + virtual void visit (HIR::TupleStructPattern &) override {} + + virtual void visit (HIR::TuplePatternItemsMultiple &) override {} + virtual void visit (HIR::TuplePatternItemsRanged &) override {} + virtual void visit (HIR::TuplePattern &) override {} + virtual void visit (HIR::GroupedPattern &) override {} + virtual void visit (HIR::SlicePattern &) override {} + + virtual void visit (HIR::EmptyStmt &) override {} + virtual void visit (HIR::LetStmt &) override {} + virtual void visit (HIR::ExprStmtWithoutBlock &) override {} + virtual void visit (HIR::ExprStmtWithBlock &) override {} + + virtual void visit (HIR::TraitBound &) override {} + virtual void visit (HIR::ImplTraitType &) override {} + virtual void visit (HIR::TraitObjectType &) override {} + virtual void visit (HIR::ParenthesisedType &) override {} + virtual void visit (HIR::ImplTraitTypeOneBound &) override {} + virtual void visit (HIR::TraitObjectTypeOneBound &) override {} + virtual void visit (HIR::TupleType &) override {} + virtual void visit (HIR::NeverType &) override {} + virtual void visit (HIR::RawPointerType &) override {} + virtual void visit (HIR::ReferenceType &) override {} + virtual void visit (HIR::ArrayType &) override {} + virtual void visit (HIR::SliceType &) override {} + virtual void visit (HIR::InferredType &) override {} + virtual void visit (HIR::BareFunctionType &) override {} +}; + +class ImplTypeIterator : public SimpleHirVisitor +{ + using SimpleHirVisitor::visit; + +public: + ImplTypeIterator (HIR::ImplBlock &impl, + std::function<void (HIR::TypeAlias &alias)> cb) + : impl (impl), cb (cb) + {} + + void go (); + + void visit (HIR::TypeAlias &alias) override; + +private: + HIR::ImplBlock &impl; + std::function<void (HIR::TypeAlias &alias)> cb; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_TYPE_CHECK_UTIL_H diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index d834ad8..27b7f12 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -117,6 +117,70 @@ public: return true; } + void insert_associated_trait_impl (HirId id, AssociatedImplTrait &&associated) + { + rust_assert (associated_impl_traits.find (id) + == associated_impl_traits.end ()); + associated_impl_traits.emplace (id, std::move (associated)); + } + + bool lookup_associated_trait_impl (HirId id, AssociatedImplTrait **associated) + { + auto it = associated_impl_traits.find (id); + if (it == associated_impl_traits.end ()) + return false; + + *associated = &it->second; + return true; + } + + void insert_associated_type_mapping (HirId id, HirId mapping) + { + associated_type_mappings[id] = mapping; + } + + void clear_associated_type_mapping (HirId id) + { + associated_type_mappings[id] = UNKNOWN_HIRID; + } + + HirId lookup_associated_type_mapping (HirId id, HirId default_value) + { + auto it = associated_type_mappings.find (id); + if (it == associated_type_mappings.end ()) + return default_value; + + return it->second; + } + + void insert_associated_impl_mapping (HirId trait_id, + const TyTy::BaseType *impl_type, + HirId impl_id) + { + auto it = associated_traits_to_impls.find (trait_id); + if (it == associated_traits_to_impls.end ()) + { + associated_traits_to_impls[trait_id] = {}; + } + + associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id}); + } + + HirId lookup_associated_impl_mapping_for_self (HirId trait_id, + const TyTy::BaseType *self) + { + auto it = associated_traits_to_impls.find (trait_id); + if (it == associated_traits_to_impls.end ()) + return UNKNOWN_HIRID; + + for (auto &item : it->second) + { + if (item.first->can_eq (self, false)) + return item.second; + } + return UNKNOWN_HIRID; + } + private: TypeCheckContext (); @@ -127,6 +191,13 @@ private: std::vector<TyTy::BaseType *> loop_type_stack; std::map<DefId, TraitReference> trait_context; std::map<HirId, TyTy::BaseType *> receiver_context; + std::map<HirId, AssociatedImplTrait> associated_impl_traits; + + // trait-id -> list of < self-tyty:impl-id> + std::map<HirId, std::vector<std::pair<const TyTy::BaseType *, HirId>>> + associated_traits_to_impls; + + std::map<HirId, HirId> associated_type_mappings; }; class TypeResolution diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index a3c00da..c7ea029 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -108,6 +108,7 @@ public: void visit (TyTy::StrType &) override { gcc_unreachable (); } void visit (TyTy::NeverType &) override { gcc_unreachable (); } void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } private: SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus) @@ -191,6 +192,7 @@ public: void visit (TyTy::StrType &) override { gcc_unreachable (); } void visit (TyTy::NeverType &) override { gcc_unreachable (); } void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } private: SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings) @@ -248,6 +250,7 @@ public: void visit (TyTy::StrType &) override { gcc_unreachable (); } void visit (TyTy::NeverType &) override { gcc_unreachable (); } void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } private: SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver) @@ -298,6 +301,7 @@ public: void visit (TyTy::StrType &) override {} void visit (TyTy::NeverType &) override {} void visit (TyTy::PlaceholderType &) override {} + void visit (TyTy::ProjectionType &) override {} private: GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {} diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 008dc19..1bd7865 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -25,7 +25,8 @@ namespace Resolver { void TypeBoundsProbe::scan () { - std::vector<HIR::TypePath *> possible_trait_paths; + std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>> + possible_trait_paths; mappings->iterate_impl_blocks ( [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { // we are filtering for trait-impl-blocks @@ -42,16 +43,17 @@ TypeBoundsProbe::scan () if (!receiver->can_eq (impl_type, false)) return true; - possible_trait_paths.push_back (impl->get_trait_ref ().get ()); + possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl}); return true; }); - for (auto &trait_path : possible_trait_paths) + for (auto &path : possible_trait_paths) { + HIR::TypePath *trait_path = path.first; TraitReference *trait_ref = TraitResolver::Resolve (*trait_path); if (!trait_ref->is_error ()) - trait_references.push_back (trait_ref); + trait_references.push_back ({trait_ref, path.second}); } } diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h index 636d40b..4e74e59 100644 --- a/gcc/rust/typecheck/rust-tyty-call.h +++ b/gcc/rust/typecheck/rust-tyty-call.h @@ -56,6 +56,7 @@ public: void visit (StrType &) override { gcc_unreachable (); } void visit (NeverType &) override { gcc_unreachable (); } void visit (PlaceholderType &) override { gcc_unreachable (); } + void visit (ProjectionType &) override { gcc_unreachable (); } // tuple-structs void visit (ADTType &type) override; @@ -106,6 +107,7 @@ public: void visit (StrType &) override { gcc_unreachable (); } void visit (NeverType &) override { gcc_unreachable (); } void visit (PlaceholderType &) override { gcc_unreachable (); } + void visit (ProjectionType &) override { gcc_unreachable (); } // FIXME void visit (FnPtr &type) override { gcc_unreachable (); } diff --git a/gcc/rust/typecheck/rust-tyty-cast.h b/gcc/rust/typecheck/rust-tyty-cast.h index c457931..51c9791 100644 --- a/gcc/rust/typecheck/rust-tyty-cast.h +++ b/gcc/rust/typecheck/rust-tyty-cast.h @@ -307,6 +307,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (ProjectionType &type) override + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + Location base_locus = mappings->lookup_location (get_base ()->get_ref ()); + RichLocation r (ref_locus); + r.add_range (base_locus); + rust_error_at (r, "invalid cast [%s] to [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + protected: BaseCastRules (BaseType *base) : mappings (Analysis::Mappings::get ()), diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index 049a4b7..100e384 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -43,6 +43,16 @@ public: return ok; } } + else if (other->get_kind () == TypeKind::PLACEHOLDER) + { + const PlaceholderType *p = static_cast<const PlaceholderType *> (other); + if (p->can_resolve ()) + { + const BaseType *resolved = p->resolve (); + resolved->accept_vis (*this); + return ok; + } + } other->accept_vis (*this); return ok; @@ -337,6 +347,22 @@ public: } } + virtual void visit (const ProjectionType &type) override + { + ok = false; + if (emit_error_flag) + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + Location base_locus + = mappings->lookup_location (get_base ()->get_ref ()); + RichLocation r (ref_locus); + r.add_range (base_locus); + rust_error_at (r, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + } + virtual void visit (const PlaceholderType &type) override { // it is ok for types to can eq to a placeholder @@ -1149,43 +1175,55 @@ public: : BaseCmp (base, emit_errors), base (base) {} - virtual void visit (const TupleType &) override { ok = true; } + bool can_eq (const BaseType *other) override + { + if (!base->can_resolve ()) + return BaseCmp::can_eq (other); + + BaseType *lookup = base->resolve (); + return lookup->can_eq (other, emit_error_flag); + } + + void visit (const TupleType &) override { ok = true; } - virtual void visit (const ADTType &) override { ok = true; } + void visit (const ADTType &) override { ok = true; } - virtual void visit (const InferType &) override { ok = true; } + void visit (const InferType &) override { ok = true; } - virtual void visit (const FnType &) override { ok = true; } + void visit (const FnType &) override { ok = true; } - virtual void visit (const FnPtr &) override { ok = true; } + void visit (const FnPtr &) override { ok = true; } - virtual void visit (const ArrayType &) override { ok = true; } + void visit (const ArrayType &) override { ok = true; } - virtual void visit (const BoolType &) override { ok = true; } + void visit (const BoolType &) override { ok = true; } - virtual void visit (const IntType &) override { ok = true; } + void visit (const IntType &) override { ok = true; } - virtual void visit (const UintType &) override { ok = true; } + void visit (const UintType &) override { ok = true; } - virtual void visit (const USizeType &) override { ok = true; } + void visit (const USizeType &) override { ok = true; } - virtual void visit (const ISizeType &) override { ok = true; } + void visit (const ISizeType &) override { ok = true; } - virtual void visit (const FloatType &) override { ok = true; } + void visit (const FloatType &) override { ok = true; } - virtual void visit (const ErrorType &) override { ok = true; } + void visit (const ErrorType &) override { ok = true; } - virtual void visit (const CharType &) override { ok = true; } + void visit (const CharType &) override { ok = true; } - virtual void visit (const ReferenceType &) override { ok = true; } + void visit (const ReferenceType &) override { ok = true; } - virtual void visit (const ParamType &) override { ok = true; } + void visit (const ParamType &) override { ok = true; } - virtual void visit (const StrType &) override { ok = true; } + void visit (const StrType &) override { ok = true; } - virtual void visit (const NeverType &) override { ok = true; } + void visit (const NeverType &) override { ok = true; } - virtual void visit (const PlaceholderType &) override { ok = true; } + void visit (const PlaceholderType &type) override + { + ok = base->get_symbol ().compare (type.get_symbol ()) == 0; + } private: const BaseType *get_base () const override { return base; } diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h index f19871e..d30be7f 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -307,6 +307,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (ProjectionType &type) override + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + Location base_locus = mappings->lookup_location (get_base ()->get_ref ()); + RichLocation r (ref_locus); + r.add_range (base_locus); + rust_error_at (r, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + protected: BaseCoercionRules (BaseType *base) : mappings (Analysis::Mappings::get ()), diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index de9a5d9..4d0b977 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -68,6 +68,14 @@ public: other = p->resolve (); } } + else if (other->get_kind () == TypeKind::PLACEHOLDER) + { + PlaceholderType *p = static_cast<PlaceholderType *> (other); + if (p->can_resolve ()) + { + other = p->resolve (); + } + } other->accept_vis (*this); if (resolved->get_kind () == TyTy::TypeKind::ERROR) @@ -329,6 +337,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (ProjectionType &type) override + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + Location base_locus = mappings->lookup_location (get_base ()->get_ref ()); + RichLocation r (ref_locus); + r.add_range (base_locus); + rust_error_at (r, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + protected: BaseRules (BaseType *base) : mappings (Analysis::Mappings::get ()), @@ -1238,7 +1257,7 @@ class NeverRules : public BaseRules public: NeverRules (NeverType *base) : BaseRules (base), base (base) {} - virtual void visit (NeverType &type) override { resolved = type.clone (); } + void visit (NeverType &type) override { resolved = type.clone (); } private: BaseType *get_base () override { return base; } @@ -1253,6 +1272,37 @@ class PlaceholderRules : public BaseRules public: PlaceholderRules (PlaceholderType *base) : BaseRules (base), base (base) {} + BaseType *unify (BaseType *other) override final + { + if (!base->can_resolve ()) + return BaseRules::unify (other); + + BaseType *lookup = base->resolve (); + return lookup->unify (other); + } + + void visit (PlaceholderType &type) override + { + if (base->get_symbol ().compare (type.get_symbol ()) != 0) + { + BaseRules::visit (type); + return; + } + + resolved = type.clone (); + } + + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + } + private: BaseType *get_base () override { return base; } diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h index 66b11b9..0e9a58b 100644 --- a/gcc/rust/typecheck/rust-tyty-visitor.h +++ b/gcc/rust/typecheck/rust-tyty-visitor.h @@ -47,6 +47,7 @@ public: virtual void visit (StrType &type) = 0; virtual void visit (NeverType &type) = 0; virtual void visit (PlaceholderType &type) = 0; + virtual void visit (ProjectionType &type) = 0; }; class TyConstVisitor @@ -72,6 +73,7 @@ public: virtual void visit (const StrType &type) = 0; virtual void visit (const NeverType &type) = 0; virtual void visit (const PlaceholderType &type) = 0; + virtual void visit (const ProjectionType &type) = 0; }; } // namespace TyTy diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 2d165c3..56fdafd 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -49,10 +49,10 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const return true; } - std::vector<Resolver::TraitReference *> probed - = Resolver::TypeBoundsProbe::Probe (this); - for (const Resolver::TraitReference *bound : probed) + auto probed = Resolver::TypeBoundsProbe::Probe (this); + for (auto &b : probed) { + const Resolver::TraitReference *bound = b.first; bool found = bound->get_mappings ().get_defid () == query->get_mappings ().get_defid (); if (found) @@ -2015,6 +2015,8 @@ NeverType::clone () const return new NeverType (get_ref (), get_ty_ref (), get_combined_refs ()); } +// placeholder type + void PlaceholderType::accept_vis (TyVisitor &vis) { @@ -2030,7 +2032,8 @@ PlaceholderType::accept_vis (TyConstVisitor &vis) const std::string PlaceholderType::as_string () const { - return "<placeholder>"; + return "<placeholder:" + (can_resolve () ? resolve ()->as_string () : "") + + ">"; } BaseType * @@ -2064,7 +2067,114 @@ PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const BaseType * PlaceholderType::clone () const { - return new PlaceholderType (get_ref (), get_ty_ref (), get_combined_refs ()); + return new PlaceholderType (get_symbol (), get_ref (), get_ty_ref (), + get_combined_refs ()); +} + +void +PlaceholderType::set_associated_type (HirId ref) +{ + auto context = Resolver::TypeCheckContext::get (); + context->insert_associated_type_mapping (get_ty_ref (), ref); +} + +void +PlaceholderType::clear_associated_type () +{ + auto context = Resolver::TypeCheckContext::get (); + context->clear_associated_type_mapping (get_ty_ref ()); +} + +bool +PlaceholderType::can_resolve () const +{ + auto context = Resolver::TypeCheckContext::get (); + HirId val + = context->lookup_associated_type_mapping (get_ty_ref (), UNKNOWN_HIRID); + return val != UNKNOWN_HIRID; +} + +BaseType * +PlaceholderType::resolve () const +{ + auto context = Resolver::TypeCheckContext::get (); + + rust_assert (can_resolve ()); + HirId val + = context->lookup_associated_type_mapping (get_ty_ref (), UNKNOWN_HIRID); + rust_assert (val != UNKNOWN_HIRID); + + return TyVar (val).get_tyty (); +} + +bool +PlaceholderType::is_equal (const BaseType &other) const +{ + if (get_kind () != other.get_kind ()) + { + if (!can_resolve ()) + return false; + + return resolve ()->is_equal (other); + } + + auto other2 = static_cast<const PlaceholderType &> (other); + return get_symbol ().compare (other2.get_symbol ()) == 0; +} + +// Projection type + +void +ProjectionType::accept_vis (TyVisitor &vis) +{ + vis.visit (*this); +} + +void +ProjectionType::accept_vis (TyConstVisitor &vis) const +{ + vis.visit (*this); +} + +std::string +ProjectionType::as_string () const +{ + return "<Projection>"; +} + +BaseType * +ProjectionType::unify (BaseType *other) +{ + gcc_unreachable (); + return nullptr; +} + +BaseType * +ProjectionType::coerce (BaseType *other) +{ + gcc_unreachable (); + return nullptr; +} + +BaseType * +ProjectionType::cast (BaseType *other) +{ + gcc_unreachable (); + return nullptr; +} + +bool +ProjectionType::can_eq (const BaseType *other, bool emit_errors) const +{ + gcc_unreachable (); + return false; +} + +BaseType * +ProjectionType::clone () const +{ + return new ProjectionType (get_ref (), get_ty_ref (), base, trait, item, + associated, get_combined_refs ()); } // rust-tyty-call.h @@ -2186,6 +2296,17 @@ TypeCheckCallExpr::visit (FnType &type) return; } + if (type.get_return_type ()->get_kind () == TyTy::TypeKind::PLACEHOLDER) + { + const TyTy::PlaceholderType *p + = static_cast<const TyTy::PlaceholderType *> (type.get_return_type ()); + if (p->can_resolve ()) + { + resolved = p->resolve ()->clone (); + return; + } + } + resolved = type.get_return_type ()->clone (); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index c1afa14..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 { @@ -54,6 +55,7 @@ enum TypeKind ISIZE, NEVER, PLACEHOLDER, + PROJECTION, // there are more to add... ERROR }; @@ -122,6 +124,9 @@ public: case TypeKind::PLACEHOLDER: return "Placeholder"; + case TypeKind::PROJECTION: + return "Projection"; + case TypeKind::ERROR: return "ERROR"; } @@ -1679,13 +1684,15 @@ public: class PlaceholderType : public BaseType { public: - PlaceholderType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::PLACEHOLDER, refs) + PlaceholderType (std::string symbol, HirId ref, + std::set<HirId> refs = std::set<HirId> ()) + : BaseType (ref, ref, TypeKind::PLACEHOLDER, refs), symbol (symbol) + {} - PlaceholderType (HirId ref, HirId ty_ref, + PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::PLACEHOLDER, refs) + : BaseType (ref, ty_ref, TypeKind::PLACEHOLDER, refs), symbol (symbol) {} void accept_vis (TyVisitor &vis) override; @@ -1703,6 +1710,62 @@ public: std::string get_name () const override final { return as_string (); } bool is_unit () const override { return true; } + + std::string get_symbol () const { return symbol; } + + void set_associated_type (HirId ref); + + void clear_associated_type (); + + bool can_resolve () const; + + BaseType *resolve () const; + + bool is_equal (const BaseType &other) const override; + +private: + std::string symbol; +}; + +class ProjectionType : public BaseType +{ +public: + ProjectionType (HirId ref, TyVar base, Resolver::TraitReference *trait, + DefId item, Resolver::AssociatedImplTrait *associated, + std::set<HirId> refs = std::set<HirId> ()) + : BaseType (ref, ref, TypeKind::PROJECTION, refs), base (base), + 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), associated (associated) + {} + + void accept_vis (TyVisitor &vis) override; + void accept_vis (TyConstVisitor &vis) const override; + + std::string as_string () const override; + + BaseType *unify (BaseType *other) override; + bool can_eq (const BaseType *other, bool emit_errors) const override final; + BaseType *coerce (BaseType *other) override; + BaseType *cast (BaseType *other) override; + + BaseType *clone () const final override; + + std::string get_name () const override final { return as_string (); } + + bool is_unit () const override { return false; } + +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/compile/torture/traits10.rs b/gcc/testsuite/rust/compile/torture/traits10.rs new file mode 100644 index 0000000..3e47b1b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits10.rs @@ -0,0 +1,32 @@ +trait Foo +where + Self: Sized, +{ + fn get(self) -> i32; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn test(self) -> i32 { + self.get() + } +} + +struct Bar(i32); +impl Foo for Bar { + fn get(self) -> i32 { + self.0 + } +} + +fn main() { + let a; + a = Bar(123); + + let b; + b = Bar::get(a); + + let a; + a = Bar(123); + + let b; + b = a.test(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits11.rs b/gcc/testsuite/rust/compile/torture/traits11.rs new file mode 100644 index 0000000..b5fc023 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits11.rs @@ -0,0 +1,32 @@ +trait Foo { + type A; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn test(a: Self::A) -> Self::A { + a + } +} + +struct Bar(i32); +impl Foo for Bar { + type A = i32; +} + +struct Baz(f32); +impl Foo for Baz { + type A = f32; +} + +fn main() { + let a; + a = Bar(123); + + let b; + b = Bar::test(a.0); + + let c; + c = Baz(123f32); + + let d; + d = Baz::test(c.0); +} diff --git a/gcc/testsuite/rust/compile/traits1.rs b/gcc/testsuite/rust/compile/traits1.rs index 30483b1..355064e 100644 --- a/gcc/testsuite/rust/compile/traits1.rs +++ b/gcc/testsuite/rust/compile/traits1.rs @@ -1,5 +1,6 @@ trait Foo { fn Bar() -> i32 {} + // { dg-error "expected .i32. got .()." "" { target *-*-* } .-1 } } struct Baz; diff --git a/gcc/testsuite/rust/compile/traits2.rs b/gcc/testsuite/rust/compile/traits2.rs index 08e6bd3..7357c22 100644 --- a/gcc/testsuite/rust/compile/traits2.rs +++ b/gcc/testsuite/rust/compile/traits2.rs @@ -1,5 +1,6 @@ trait Foo { fn Bar() -> i32 {} + // { dg-error "expected .i32. got .()." "" { target *-*-* } .-1 } } struct Baz; 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 +} |