From ecb777cc8df55a024add203e858486eadcc3aa62 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 15 Sep 2021 20:47:03 +0100 Subject: Add building blocks for Dynamic object types This is the stub implementation for dynamic object types within the type system. More work is needed to actually support dynamic trait objects. The next change requires us to support type coercions in for arguments to functions such as a fat-reference to a type being coerced into this dynamic trait object for dynamic dispatch. Addresses: #197 --- gcc/rust/backend/rust-compile-context.h | 2 + gcc/rust/backend/rust-compile-tyty.h | 2 + gcc/rust/typecheck/rust-hir-const-fold.h | 2 + gcc/rust/typecheck/rust-hir-type-check-type.cc | 16 ++++++ gcc/rust/typecheck/rust-hir-type-check-type.h | 2 + gcc/rust/typecheck/rust-substitution-mapper.h | 4 ++ gcc/rust/typecheck/rust-tyty-call.h | 56 ++++++++++---------- gcc/rust/typecheck/rust-tyty-cast.h | 38 ++++++++++++++ gcc/rust/typecheck/rust-tyty-cmp.h | 56 ++++++++++++++++++++ gcc/rust/typecheck/rust-tyty-coercion.h | 57 ++++++++++++++++++++ gcc/rust/typecheck/rust-tyty-rules.h | 66 +++++++++++++++++++++++ gcc/rust/typecheck/rust-tyty-visitor.h | 2 + gcc/rust/typecheck/rust-tyty.cc | 73 ++++++++++++++++++++++++-- gcc/rust/typecheck/rust-tyty.h | 53 +++++++++++++++++-- 14 files changed, 394 insertions(+), 35 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 3a92c32..7d2f32d 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -610,6 +610,8 @@ public: translated = ctx->get_backend ()->unit_type (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } + private: TyTyResolveCompile (Context *ctx) : ctx (ctx), translated (nullptr) {} diff --git a/gcc/rust/backend/rust-compile-tyty.h b/gcc/rust/backend/rust-compile-tyty.h index 1a5747a..40b297c 100644 --- a/gcc/rust/backend/rust-compile-tyty.h +++ b/gcc/rust/backend/rust-compile-tyty.h @@ -237,6 +237,8 @@ public: translated = backend->unit_type (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } + private: TyTyCompile (::Backend *backend) : backend (backend), translated (nullptr), diff --git a/gcc/rust/typecheck/rust-hir-const-fold.h b/gcc/rust/typecheck/rust-hir-const-fold.h index 1bff7ef..1466434 100644 --- a/gcc/rust/typecheck/rust-hir-const-fold.h +++ b/gcc/rust/typecheck/rust-hir-const-fold.h @@ -191,6 +191,8 @@ public: void visit (TyTy::NeverType &) override { gcc_unreachable (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } + private: ConstFoldType (::Backend *backend) : backend (backend), translated (backend->error_type ()) diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index b54a403..c660521 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -221,5 +221,21 @@ TypeCheckType::resolve_segments ( gcc_unreachable (); } +void +TypeCheckType::visit (HIR::TraitObjectTypeOneBound &type) +{ + std::vector specified_bounds; + + HIR::TraitBound &trait_bound = type.get_trait_bound (); + TraitReference *trait = resolve_trait_path (trait_bound.get_path ()); + TyTy::TypeBoundPredicate predicate (trait->get_mappings ().get_defid (), + trait_bound.get_locus ()); + + specified_bounds.push_back (std::move (predicate)); + + translated = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), + std::move (specified_bounds)); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index c02a369..1f97a4e 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -146,6 +146,8 @@ public: TyTy::InferType::InferTypeKind::GENERAL); } + void visit (HIR::TraitObjectTypeOneBound &type) override; + private: TypeCheckType (std::vector *subst_mappings) : TypeCheckBase (), subst_mappings (subst_mappings), translated (nullptr) diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index 28cbeb8..13496ff 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -137,6 +137,7 @@ public: void visit (TyTy::ParamType &) override { gcc_unreachable (); } void visit (TyTy::StrType &) override { gcc_unreachable (); } void visit (TyTy::NeverType &) override { gcc_unreachable (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } private: SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus) @@ -230,6 +231,7 @@ public: void visit (TyTy::CharType &) override { gcc_unreachable (); } void visit (TyTy::StrType &) override { gcc_unreachable (); } void visit (TyTy::NeverType &) override { gcc_unreachable (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } private: SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings) @@ -288,6 +290,7 @@ public: void visit (TyTy::NeverType &) override { gcc_unreachable (); } void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } void visit (TyTy::ProjectionType &) override { gcc_unreachable (); } + void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } private: SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver) @@ -339,6 +342,7 @@ public: void visit (TyTy::NeverType &) override {} void visit (TyTy::PlaceholderType &) override {} void visit (TyTy::ProjectionType &) override {} + void visit (TyTy::DynamicObjectType &) override {} private: GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {} diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h index 4e74e59..906110a 100644 --- a/gcc/rust/typecheck/rust-tyty-call.h +++ b/gcc/rust/typecheck/rust-tyty-call.h @@ -39,24 +39,25 @@ public: return checker.resolved; } - void visit (InferType &type) override { gcc_unreachable (); } - void visit (TupleType &type) override { gcc_unreachable (); } - void visit (ArrayType &type) override { gcc_unreachable (); } - void visit (BoolType &type) override { gcc_unreachable (); } - void visit (IntType &type) override { gcc_unreachable (); } - void visit (UintType &type) override { gcc_unreachable (); } - void visit (FloatType &type) override { gcc_unreachable (); } - void visit (USizeType &type) override { gcc_unreachable (); } - void visit (ISizeType &type) override { gcc_unreachable (); } - void visit (ErrorType &type) override { gcc_unreachable (); } - void visit (CharType &type) override { gcc_unreachable (); } - void visit (ReferenceType &type) override { gcc_unreachable (); } - void visit (PointerType &type) override { gcc_unreachable (); } + void visit (InferType &) override { gcc_unreachable (); } + void visit (TupleType &) override { gcc_unreachable (); } + void visit (ArrayType &) override { gcc_unreachable (); } + void visit (BoolType &) override { gcc_unreachable (); } + void visit (IntType &) override { gcc_unreachable (); } + void visit (UintType &) override { gcc_unreachable (); } + void visit (FloatType &) override { gcc_unreachable (); } + void visit (USizeType &) override { gcc_unreachable (); } + void visit (ISizeType &) override { gcc_unreachable (); } + void visit (ErrorType &) override { gcc_unreachable (); } + void visit (CharType &) override { gcc_unreachable (); } + void visit (ReferenceType &) override { gcc_unreachable (); } + void visit (PointerType &) override { gcc_unreachable (); } void visit (ParamType &) override { gcc_unreachable (); } void visit (StrType &) override { gcc_unreachable (); } void visit (NeverType &) override { gcc_unreachable (); } void visit (PlaceholderType &) override { gcc_unreachable (); } void visit (ProjectionType &) override { gcc_unreachable (); } + void visit (DynamicObjectType &) override { gcc_unreachable (); } // tuple-structs void visit (ADTType &type) override; @@ -89,25 +90,26 @@ public: return checker.resolved; } - void visit (InferType &type) override { gcc_unreachable (); } - void visit (TupleType &type) override { gcc_unreachable (); } - void visit (ArrayType &type) override { gcc_unreachable (); } - void visit (BoolType &type) override { gcc_unreachable (); } - void visit (IntType &type) override { gcc_unreachable (); } - void visit (UintType &type) override { gcc_unreachable (); } - void visit (FloatType &type) override { gcc_unreachable (); } - void visit (USizeType &type) override { gcc_unreachable (); } - void visit (ISizeType &type) override { gcc_unreachable (); } - void visit (ErrorType &type) override { gcc_unreachable (); } - void visit (ADTType &type) override { gcc_unreachable (); }; - void visit (CharType &type) override { gcc_unreachable (); } - void visit (ReferenceType &type) override { gcc_unreachable (); } - void visit (PointerType &type) override { gcc_unreachable (); } + void visit (InferType &) override { gcc_unreachable (); } + void visit (TupleType &) override { gcc_unreachable (); } + void visit (ArrayType &) override { gcc_unreachable (); } + void visit (BoolType &) override { gcc_unreachable (); } + void visit (IntType &) override { gcc_unreachable (); } + void visit (UintType &) override { gcc_unreachable (); } + void visit (FloatType &) override { gcc_unreachable (); } + void visit (USizeType &) override { gcc_unreachable (); } + void visit (ISizeType &) override { gcc_unreachable (); } + void visit (ErrorType &) override { gcc_unreachable (); } + void visit (ADTType &) override { gcc_unreachable (); }; + void visit (CharType &) override { gcc_unreachable (); } + void visit (ReferenceType &) override { gcc_unreachable (); } + void visit (PointerType &) override { gcc_unreachable (); } void visit (ParamType &) override { gcc_unreachable (); } void visit (StrType &) override { gcc_unreachable (); } void visit (NeverType &) override { gcc_unreachable (); } void visit (PlaceholderType &) override { gcc_unreachable (); } void visit (ProjectionType &) override { gcc_unreachable (); } + void visit (DynamicObjectType &) 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 51c9791..fa50992 100644 --- a/gcc/rust/typecheck/rust-tyty-cast.h +++ b/gcc/rust/typecheck/rust-tyty-cast.h @@ -318,6 +318,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (DynamicObjectType &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 ()), @@ -566,6 +577,19 @@ public: BaseCastRules::visit (type); } + void visit (DynamicObjectType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + resolved = type.clone (); + return; + } + + BaseCastRules::visit (type); + } + private: BaseType *get_base () override { return base; } @@ -1273,6 +1297,20 @@ private: PlaceholderType *base; }; +class DynamicCastRules : public BaseCastRules +{ + using Rust::TyTy::BaseCastRules::visit; + +public: + DynamicCastRules (DynamicObjectType *base) : BaseCastRules (base), base (base) + {} + +private: + BaseType *get_base () override { return base; } + + DynamicObjectType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index 100e384..030f702 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -375,6 +375,22 @@ public: ok = true; } + virtual void visit (const DynamicObjectType &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 ()); + } + } + protected: BaseCmp (const BaseType *base, bool emit_errors) : mappings (Analysis::Mappings::get ()), @@ -622,6 +638,19 @@ public: BaseCmp::visit (type); } + void visit (const DynamicObjectType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + private: const BaseType *get_base () const override { return base; } const InferType *base; @@ -1231,6 +1260,33 @@ private: const PlaceholderType *base; }; +class DynamicCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + DynamicCmp (const DynamicObjectType *base, bool emit_errors) + : BaseCmp (base, emit_errors), base (base) + {} + + void visit (const DynamicObjectType &type) override + { + if (base->num_specified_bounds () != type.num_specified_bounds ()) + { + BaseCmp::visit (type); + return; + } + + Location ref_locus = mappings->lookup_location (type.get_ref ()); + ok = base->bounds_compatible (type, ref_locus, false); + } + +private: + const BaseType *get_base () const override { return base; } + + const DynamicObjectType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h index f12ffb4..2d59e88 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -331,6 +331,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (DynamicObjectType &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 ()), @@ -580,6 +591,19 @@ public: BaseCoercionRules::visit (type); } + void visit (DynamicObjectType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + resolved = type.clone (); + return; + } + + BaseCoercionRules::visit (type); + } + private: BaseType *get_base () override { return base; } @@ -1308,6 +1332,39 @@ private: PlaceholderType *base; }; +class DynamicCoercionRules : public BaseCoercionRules +{ + using Rust::TyTy::BaseCoercionRules::visit; + +public: + DynamicCoercionRules (DynamicObjectType *base) + : BaseCoercionRules (base), base (base) + {} + + void visit (DynamicObjectType &type) override + { + if (base->num_specified_bounds () != type.num_specified_bounds ()) + { + BaseCoercionRules::visit (type); + return; + } + + Location ref_locus = mappings->lookup_location (type.get_ref ()); + if (!base->bounds_compatible (type, ref_locus, true)) + { + BaseCoercionRules::visit (type); + return; + } + + resolved = base->clone (); + } + +private: + BaseType *get_base () override { return base; } + + DynamicObjectType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index db7d8c0..62689cf 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -353,6 +353,17 @@ public: type.as_string ().c_str ()); } + virtual void visit (DynamicObjectType &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 ()), @@ -601,6 +612,19 @@ public: BaseRules::visit (type); } + void visit (DynamicObjectType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + resolved = type.clone (); + return; + } + + BaseRules::visit (type); + } + private: BaseType *get_base () override { return base; } @@ -1314,6 +1338,48 @@ private: PlaceholderType *base; }; +class DynamicRules : public BaseRules +{ + using Rust::TyTy::BaseRules::visit; + +public: + DynamicRules (DynamicObjectType *base) : BaseRules (base), base (base) {} + + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + } + + void visit (DynamicObjectType &type) override + { + if (base->num_specified_bounds () != type.num_specified_bounds ()) + { + BaseRules::visit (type); + return; + } + + Location ref_locus = mappings->lookup_location (type.get_ref ()); + if (!base->bounds_compatible (type, ref_locus, true)) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + } + +private: + BaseType *get_base () override { return base; } + + DynamicObjectType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h index 0e9a58b..a51edf4 100644 --- a/gcc/rust/typecheck/rust-tyty-visitor.h +++ b/gcc/rust/typecheck/rust-tyty-visitor.h @@ -48,6 +48,7 @@ public: virtual void visit (NeverType &type) = 0; virtual void visit (PlaceholderType &type) = 0; virtual void visit (ProjectionType &type) = 0; + virtual void visit (DynamicObjectType &type) = 0; }; class TyConstVisitor @@ -74,6 +75,7 @@ public: virtual void visit (const NeverType &type) = 0; virtual void visit (const PlaceholderType &type) = 0; virtual void visit (const ProjectionType &type) = 0; + virtual void visit (const DynamicObjectType &type) = 0; }; } // namespace TyTy diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index ef981cc..69fb8c4 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -63,7 +63,8 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const } bool -BaseType::bounds_compatible (const BaseType &other, Location locus) const +BaseType::bounds_compatible (const BaseType &other, Location locus, + bool emit_error) const { std::vector> unsatisfied_bounds; @@ -89,8 +90,9 @@ BaseType::bounds_compatible (const BaseType &other, Location locus) const missing_preds += ", "; } - rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied", - other.get_name ().c_str (), missing_preds.c_str ()); + if (emit_error) + rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied", + other.get_name ().c_str (), missing_preds.c_str ()); } return unsatisfied_bounds.size () == 0; @@ -2257,6 +2259,71 @@ ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings) return projection; } +void +DynamicObjectType::accept_vis (TyVisitor &vis) +{ + vis.visit (*this); +} + +void +DynamicObjectType::accept_vis (TyConstVisitor &vis) const +{ + vis.visit (*this); +} + +std::string +DynamicObjectType::as_string () const +{ + return "dyn [" + raw_bounds_as_string () + "]"; +} + +BaseType * +DynamicObjectType::unify (BaseType *other) +{ + DynamicRules r (this); + return r.unify (other); +} + +bool +DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const +{ + DynamicCmp r (this, emit_errors); + return r.can_eq (other); +} + +BaseType * +DynamicObjectType::coerce (BaseType *other) +{ + DynamicCoercionRules r (this); + return r.coerce (other); +} + +BaseType * +DynamicObjectType::cast (BaseType *other) +{ + DynamicCastRules r (this); + return r.cast (other); +} + +BaseType * +DynamicObjectType::clone () const +{ + return new DynamicObjectType (get_ref (), get_ty_ref (), specified_bounds, + get_combined_refs ()); +} + +bool +DynamicObjectType::is_equal (const BaseType &other) const +{ + if (get_kind () != other.get_kind ()) + return false; + + if (num_specified_bounds () != other.num_specified_bounds ()) + return false; + + return bounds_compatible (other, Location (), false); +} + // rust-tyty-call.h void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index a7eb132..90057de 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -57,6 +57,7 @@ enum TypeKind NEVER, PLACEHOLDER, PROJECTION, + DYNAMIC, // there are more to add... ERROR }; @@ -128,6 +129,9 @@ public: case TypeKind::PROJECTION: return "Projection"; + case TypeKind::DYNAMIC: + return "Dynamic"; + case TypeKind::ERROR: return "ERROR"; } @@ -173,13 +177,20 @@ public: return specified_bounds; } - std::string bounds_as_string () const + size_t num_specified_bounds () const { return specified_bounds.size (); } + + std::string raw_bounds_as_string () const { std::string buf; for (auto &b : specified_bounds) - buf += b.as_string () + ", "; + buf += b.as_string () + " + "; + + return buf; + } - return "bounds:[" + buf + "]"; + std::string bounds_as_string () const + { + return "bounds:[" + raw_bounds_as_string () + "]"; } protected: @@ -253,7 +264,8 @@ public: bool satisfies_bound (const TypeBoundPredicate &predicate) const; - bool bounds_compatible (const BaseType &other, Location locus) const; + bool bounds_compatible (const BaseType &other, Location locus, + bool emit_error) const; void inherit_bounds (const BaseType &other); @@ -608,7 +620,7 @@ public: } else { - if (!param->bounds_compatible (*type, locus)) + if (!param->bounds_compatible (*type, locus, true)) return; } @@ -1813,6 +1825,37 @@ private: DefId item; }; +class DynamicObjectType : public BaseType +{ +public: + DynamicObjectType (HirId ref, + std::vector specified_bounds, + std::set refs = std::set ()) + : BaseType (ref, ref, TypeKind::DYNAMIC, specified_bounds, refs) + {} + + DynamicObjectType (HirId ref, HirId ty_ref, + std::vector specified_bounds, + std::set refs = std::set ()) + : BaseType (ref, ty_ref, TypeKind::DYNAMIC, specified_bounds, refs) + {} + + 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; + bool is_equal (const BaseType &other) const override; + + BaseType *clone () const final override; + + std::string get_name () const override final { return as_string (); } +}; + } // namespace TyTy } // namespace Rust -- cgit v1.1 From e29a8a4172ae5c4f85d0e21d7edfaf934744c9fb Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 14:15:31 +0100 Subject: Cleanup error handling for CallExpr Call Expressions need to type check the argument passing but the type system will return TyTy::Error nodes, it used to return nullptr about a year ago. Returning error nodes are safer and more flexible for detailed error handling and diagnostics. Addresses: #539 --- gcc/rust/typecheck/rust-tyty.cc | 16 ++++++++-------- gcc/testsuite/rust/compile/tuple_struct3.rs | 6 +++++- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 69fb8c4..dd33975 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2352,14 +2352,14 @@ TypeCheckCallExpr::visit (ADTType &type) BaseType *field_tyty = field->get_field_type (); BaseType *arg = Resolver::TypeCheckExpr::Resolve (p, false); - if (arg == nullptr) + if (arg->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (p->get_locus (), "failed to resolve argument type"); return false; } auto res = field_tyty->unify (arg); - if (res == nullptr) + if (res->get_kind () == TyTy::TypeKind::ERROR) { return false; } @@ -2407,7 +2407,7 @@ TypeCheckCallExpr::visit (FnType &type) size_t i = 0; call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); - if (argument_expr_tyty == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "failed to resolve type for argument expr in CallExpr"); @@ -2421,7 +2421,7 @@ TypeCheckCallExpr::visit (FnType &type) { auto fnparam = type.param_at (i); resolved_argument_type = fnparam.second->unify (argument_expr_tyty); - if (resolved_argument_type == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "Type Resolution failure on parameter"); @@ -2472,7 +2472,7 @@ TypeCheckCallExpr::visit (FnPtr &type) call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { auto fnparam = type.param_at (i); auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); - if (argument_expr_tyty == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "failed to resolve type for argument expr in CallExpr"); @@ -2480,7 +2480,7 @@ TypeCheckCallExpr::visit (FnPtr &type) } auto resolved_argument_type = fnparam->unify (argument_expr_tyty); - if (resolved_argument_type == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "Type Resolution failure on parameter"); @@ -2523,7 +2523,7 @@ TypeCheckMethodCallExpr::visit (FnType &type) call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { auto fnparam = type.param_at (i); auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); - if (argument_expr_tyty == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "failed to resolve type for argument expr in CallExpr"); @@ -2531,7 +2531,7 @@ TypeCheckMethodCallExpr::visit (FnType &type) } auto resolved_argument_type = fnparam.second->unify (argument_expr_tyty); - if (resolved_argument_type == nullptr) + if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), "Type Resolution failure on parameter"); diff --git a/gcc/testsuite/rust/compile/tuple_struct3.rs b/gcc/testsuite/rust/compile/tuple_struct3.rs index c52a610..1af72a2 100644 --- a/gcc/testsuite/rust/compile/tuple_struct3.rs +++ b/gcc/testsuite/rust/compile/tuple_struct3.rs @@ -1,5 +1,9 @@ struct Foo(i32, i32, bool); fn main() { - let c = Foo(1, 2f32, true); // { dg-error "expected .i32. got .f32." } + let c = Foo(1, 2f32, true); + // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 } + // { dg-error "unexpected number of arguments 1 expected 3" "" { target *-*-* } .-2 } + // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-3 } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-4 } } -- cgit v1.1 From 135807db03756de55e6368b07a9884134160867e Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 14:29:02 +0100 Subject: When calling functions the arguments are a coercion site This changes all type checking of arguments to function calls to be coercion sites instead of unifications. This allows for cases like mutable pointers being coerced to immutable reference for example. --- gcc/rust/typecheck/rust-tyty-coercion.h | 31 +++++++++++++++++++++++++++++++ gcc/rust/typecheck/rust-tyty.cc | 8 ++++---- 2 files changed, 35 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h index 2d59e88..5ab8542 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -1326,6 +1326,37 @@ public: : BaseCoercionRules (base), base (base) {} + BaseType *coerce (BaseType *other) override final + { + if (!base->can_resolve ()) + return BaseCoercionRules::coerce (other); + + BaseType *lookup = base->resolve (); + return lookup->unify (other); + } + + void visit (PlaceholderType &type) override + { + if (base->get_symbol ().compare (type.get_symbol ()) != 0) + { + BaseCoercionRules::visit (type); + return; + } + + resolved = type.clone (); + } + + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseCoercionRules::visit (type); + return; + } + + resolved = base->clone (); + } + private: BaseType *get_base () override { return base; } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index dd33975..bfe1043 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2358,7 +2358,7 @@ TypeCheckCallExpr::visit (ADTType &type) return false; } - auto res = field_tyty->unify (arg); + auto res = field_tyty->coerce (arg); if (res->get_kind () == TyTy::TypeKind::ERROR) { return false; @@ -2420,7 +2420,7 @@ TypeCheckCallExpr::visit (FnType &type) if (i < type.num_params ()) { auto fnparam = type.param_at (i); - resolved_argument_type = fnparam.second->unify (argument_expr_tyty); + resolved_argument_type = fnparam.second->coerce (argument_expr_tyty); if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), @@ -2479,7 +2479,7 @@ TypeCheckCallExpr::visit (FnPtr &type) return false; } - auto resolved_argument_type = fnparam->unify (argument_expr_tyty); + auto resolved_argument_type = fnparam->coerce (argument_expr_tyty); if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), @@ -2530,7 +2530,7 @@ TypeCheckMethodCallExpr::visit (FnType &type) return false; } - auto resolved_argument_type = fnparam.second->unify (argument_expr_tyty); + auto resolved_argument_type = fnparam.second->coerce (argument_expr_tyty); if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (param->get_locus (), -- cgit v1.1 From 26fe2f57bc1e3e01f29aa07c6e880f76d929463c Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 14:38:54 +0100 Subject: remove some debug --- gcc/rust/typecheck/rust-hir-type-check-implitem.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 94674ad..daf515a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -424,9 +424,6 @@ public: trait_reference.get_name ().c_str ()); } - rust_debug_loc (type.get_locus (), "type-alias within impl block"); - lookup->debug (); - // its actually a projection, since we need a way to actually bind the // generic substitutions to the type itself TyTy::ProjectionType *projection = new TyTy::ProjectionType ( -- cgit v1.1 From d144eea86290e8efc700d8042e9b517158b9f916 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 15:59:31 +0100 Subject: Type coercions are recursive Reference types are covariants like arrays or pointers and thus this needs to be recurisve to support all coercions possible. Addresses: #197 --- gcc/rust/typecheck/rust-tyty-coercion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h index 5ab8542..d46f1d4 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -1130,7 +1130,7 @@ public: auto base_type = base->get_base (); auto other_base_type = type.get_base (); - TyTy::BaseType *base_resolved = base_type->unify (other_base_type); + TyTy::BaseType *base_resolved = base_type->coerce (other_base_type); if (base_resolved == nullptr || base_resolved->get_kind () == TypeKind::ERROR) { -- cgit v1.1 From d9a0a5f864b69c68d410a14e0aa7ccbaae7eb144 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 16:41:25 +0100 Subject: Allow for coercion of structures over to dynamic objects in type system This is the initial support for allowing a coercion of something like: ```rust let a = Foo(123); let b:&dyn Bound = &a; ``` The coercion will need to ensure that 'a' meets the specified bounds of the dynamic object. Addresses #197 --- gcc/rust/typecheck/rust-tyty-coercion.h | 11 +++++++++++ gcc/testsuite/rust/compile/traits9.rs | 13 +++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/rust/compile/traits9.rs (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h index d46f1d4..976997d 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -24,6 +24,7 @@ #include "rust-tyty-visitor.h" #include "rust-hir-map.h" #include "rust-hir-type-check.h" +#include "rust-hir-type-bounds.h" extern ::Backend * rust_get_backend (); @@ -1390,6 +1391,16 @@ public: resolved = base->clone (); } + void visit (ADTType &type) override + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + bool ok = base->bounds_compatible (type, ref_locus, true); + if (!ok) + return; + + resolved = base->clone (); + } + private: BaseType *get_base () override { return base; } diff --git a/gcc/testsuite/rust/compile/traits9.rs b/gcc/testsuite/rust/compile/traits9.rs new file mode 100644 index 0000000..e1aef539 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits9.rs @@ -0,0 +1,13 @@ +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +fn main() { + let a; + a = Foo(123); + + let b: &dyn Bar = &a; + // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { target *-*-* } .-1 } + // { dg-error "expected" "" { target *-*-* } .-2 } +} -- cgit v1.1 From aa019b251e9900e81e8b3ec258a4f1f340a91296 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 17:35:09 +0100 Subject: Default to TyTy::Error node on TypePath resolution failure We should insert the error node into the type context when we have a type error such that covariant types using TyVar can still work, and avoid the assertion to ensure something exists within the context for that id upon creation. --- gcc/rust/typecheck/rust-hir-type-check-type.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 1f97a4e..eb1c861 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -66,7 +66,8 @@ public: type->accept_vis (resolver); if (resolver.translated == nullptr) - return new TyTy::ErrorType (type->get_mappings ().get_hirid ()); + resolver.translated + = new TyTy::ErrorType (type->get_mappings ().get_hirid ()); resolver.context->insert_type (type->get_mappings (), resolver.translated); return resolver.translated; -- cgit v1.1 From c674e168ebc29c061a8a936e064c2e3d556ab326 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 17:41:01 +0100 Subject: Add object safety checks for dynamic objects You cannot create dynamic objects that contain non object safe trait items. This adds checks to ensure that all items are object safe so code generation does not need to care. see: https://doc.rust-lang.org/reference/items/traits.html#object-safety Addresses: #197 --- gcc/rust/hir/tree/rust-hir-item.h | 2 ++ gcc/rust/typecheck/rust-hir-trait-ref.h | 49 ++++++++++++++++++++++++-- gcc/rust/typecheck/rust-hir-trait-resolve.cc | 30 ++++++++++++++++ gcc/rust/typecheck/rust-hir-trait-resolve.h | 5 ++- gcc/rust/typecheck/rust-hir-type-check-type.cc | 11 +++--- gcc/rust/typecheck/rust-tyty-bounds.cc | 8 +++++ gcc/rust/typecheck/rust-tyty.h | 4 +++ gcc/testsuite/rust/compile/traits10.rs | 16 +++++++++ gcc/testsuite/rust/compile/traits11.rs | 20 +++++++++++ 9 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/rust/compile/traits10.rs create mode 100644 gcc/testsuite/rust/compile/traits11.rs (limited to 'gcc') diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 0b2cf10..8cd7a01 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2264,6 +2264,8 @@ public: TraitFunctionDecl &get_decl () { return decl; } + const TraitFunctionDecl &get_decl () const { return decl; } + bool has_block_defined () const { return block_expr != nullptr; } std::unique_ptr &get_block_expr () diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index f05ff0c..2b5b78c 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -143,6 +143,8 @@ public: void associated_type_reset (); + bool is_object_safe () const; + private: TyTy::ErrorType *get_error () const { @@ -179,8 +181,10 @@ class TraitReference { public: TraitReference (const HIR::Trait *hir_trait_ref, - std::vector item_refs) - : hir_trait_ref (hir_trait_ref), item_refs (item_refs) + std::vector item_refs, + std::vector super_traits) + : hir_trait_ref (hir_trait_ref), item_refs (item_refs), + super_traits (super_traits) {} TraitReference (TraitReference const &other) @@ -198,7 +202,7 @@ public: TraitReference (TraitReference &&other) = default; TraitReference &operator= (TraitReference &&other) = default; - static TraitReference error () { return TraitReference (nullptr, {}); } + static TraitReference error () { return TraitReference (nullptr, {}, {}); } bool is_error () const { return hir_trait_ref == nullptr; } @@ -323,9 +327,48 @@ public: return this_id == other_id; } + const std::vector get_super_traits () const + { + return super_traits; + } + + bool is_object_safe (bool emit_error, Location locus) const + { + // https: // doc.rust-lang.org/reference/items/traits.html#object-safety + std::vector non_object_super_traits; + for (auto &item : super_traits) + { + if (!item->is_object_safe (false, Location ())) + non_object_super_traits.push_back (item); + } + + std::vector non_object_safe_items; + for (auto &item : get_trait_items ()) + { + if (!item.is_object_safe ()) + non_object_safe_items.push_back (&item); + } + + bool is_safe + = non_object_super_traits.empty () && non_object_safe_items.empty (); + if (emit_error && !is_safe) + { + RichLocation r (locus); + for (auto &item : non_object_super_traits) + r.add_range (item->get_locus ()); + for (auto &item : non_object_safe_items) + r.add_range (item->get_locus ()); + + rust_error_at (r, "trait bound is not object safe"); + } + + return is_safe; + } + private: const HIR::Trait *hir_trait_ref; std::vector item_refs; + std::vector super_traits; }; class AssociatedImplTrait diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index be58840..cee6999 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -193,6 +193,36 @@ TraitItemReference::get_parent_trait_mappings () const return trait->get_mappings (); } +bool +TraitItemReference::is_object_safe () const +{ + // https://doc.rust-lang.org/reference/items/traits.html#object-safety + switch (get_trait_item_type ()) + { + case TraitItemReference::TraitItemType::FN: { + // lets be boring and just check that this is indeed a method will do + // for now + const HIR::TraitItem *item = get_hir_trait_item (); + const HIR::TraitItemFunc *fn + = static_cast (item); + return fn->get_decl ().is_method (); + } + + // constants are not available via dyn dispatch and so is not object safe + case TraitItemReference::TraitItemType::CONST: + return false; + + // types are object safe since they are not available via dyn dispatch + case TraitItemReference::TraitItemType::TYPE: + return true; + + // this is just an error so lets just fail it + case TraitItemReference::TraitItemType::ERROR: + return false; + } + return false; +} + TyTy::BaseType * AssociatedImplTrait::get_projected_type ( const TraitItemReference *trait_item_ref, TyTy::BaseType *receiver, HirId ref, diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index b0e2c0d..a32b4da 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -153,6 +153,7 @@ private: TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (), trait_reference->get_locus ())); + std::vector super_traits; if (trait_reference->has_type_param_bounds ()) { for (auto &bound : trait_reference->get_type_param_bounds ()) @@ -170,6 +171,7 @@ private: trait->get_mappings ().get_defid (), bound->get_locus ()); specified_bounds.push_back (std::move (predicate)); + super_traits.push_back (predicate.get ()); } } } @@ -189,7 +191,8 @@ private: item_refs.push_back (std::move (trait_item_ref)); } - TraitReference trait_object (trait_reference, item_refs); + TraitReference trait_object (trait_reference, item_refs, + std::move (super_traits)); context->insert_trait_reference ( trait_reference->get_mappings ().get_defid (), std::move (trait_object)); diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index c660521..7ad6d03 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -231,10 +231,13 @@ TypeCheckType::visit (HIR::TraitObjectTypeOneBound &type) TyTy::TypeBoundPredicate predicate (trait->get_mappings ().get_defid (), trait_bound.get_locus ()); - specified_bounds.push_back (std::move (predicate)); - - translated = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), - std::move (specified_bounds)); + if (predicate.is_object_safe (true, type.get_locus ())) + { + specified_bounds.push_back (std::move (predicate)); + translated + = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), + std::move (specified_bounds)); + } } } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 1bd7865..196a6ca 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -91,5 +91,13 @@ TypeBoundPredicate::get_name () const return get ()->get_name (); } +bool +TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const +{ + const Resolver::TraitReference *trait = get (); + rust_assert (trait != nullptr); + return trait->is_object_safe (emit_error, locus); +} + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 90057de..040831e 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -154,6 +154,10 @@ public: std::string get_name () const; + // check that this predicate is object-safe see: + // https://doc.rust-lang.org/reference/items/traits.html#object-safety + bool is_object_safe (bool emit_error, Location locus) const; + private: DefId reference; Location locus; diff --git a/gcc/testsuite/rust/compile/traits10.rs b/gcc/testsuite/rust/compile/traits10.rs new file mode 100644 index 0000000..a4622b2 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits10.rs @@ -0,0 +1,16 @@ +struct Foo(i32); + +trait Bar { + const A: i32 = 123; + fn B(); + fn C(&self); +} + +pub fn main() { + let a; + a = Foo(123); + + let b: &dyn Bar = &a; + // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 } + // { dg-error "expected" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/traits11.rs b/gcc/testsuite/rust/compile/traits11.rs new file mode 100644 index 0000000..bf69ff0 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits11.rs @@ -0,0 +1,20 @@ +struct Foo(i32); + +trait A { + const A: i32 = 123; + fn B(); + fn C(&self); +} + +trait B: A { + fn test(&self); +} + +pub fn main() { + let a; + a = Foo(123); + + let b: &dyn B = &a; + // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 } + // { dg-error "expected" "" { target *-*-* } .-2 } +} -- cgit v1.1 From a6e15ff5f052801180b3e56c4579ea555f2f0c50 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 17:51:23 +0100 Subject: Add method resolution to Dynamic objects Support method resolution via probe of the type bound on the dynamic objects. This acts the same way as when we probe for methods like this: ```rust trait Foo { fn bar(&self); } fn test(a:T) { a.bar(); } ``` Addresses: #197 --- gcc/rust/typecheck/rust-hir-type-check-expr.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 07d4f90..fe8973a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -227,10 +227,13 @@ public: // which is simple. There will need to be adjustments to ensure we can turn // the receiver into borrowed references etc - bool reciever_is_generic = root->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC; + + bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn; bool probe_bounds = true; - bool probe_impls = !reciever_is_generic; - bool ignore_mandatory_trait_items = !reciever_is_generic; + bool probe_impls = !receiver_is_generic; + bool ignore_mandatory_trait_items = !receiver_is_generic; auto candidates = PathProbeType::Probe (root, expr.get_method_name ().get_segment (), @@ -345,7 +348,7 @@ public: } } - if (!reciever_is_generic) + if (!receiver_is_type_param) { // apply any remaining generic arguments if (expr.get_method_name ().has_generic_args ()) -- cgit v1.1 From fabaf7d6caf919ceaa05f2db4260fa897864d517 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Fri, 17 Sep 2021 18:05:01 +0100 Subject: Initial Dynamic dispatch support This is the first pass at implementing dynamic dispatch, it creates a vtable object and trait object to store the vtable and reciever. The method resolution during type checking acts the same as if it was a generic type bound method call. This detects this case during code generation to access the dynamic object appropriately to get the fnptr and call it with the stored reciever. Fixes: #197 --- gcc/rust/backend/rust-compile-base.h | 13 ++ gcc/rust/backend/rust-compile-context.h | 70 +++++++- gcc/rust/backend/rust-compile-stmt.h | 12 ++ gcc/rust/backend/rust-compile.cc | 255 +++++++++++++++++++++++++-- gcc/rust/typecheck/rust-hir-trait-ref.h | 1 + gcc/rust/typecheck/rust-tyty-bounds.cc | 11 +- gcc/rust/typecheck/rust-tyty.cc | 36 ++++ gcc/rust/typecheck/rust-tyty.h | 17 +- gcc/testsuite/rust/execute/torture/trait5.rs | 41 +++++ 9 files changed, 427 insertions(+), 29 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/trait5.rs (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index 5a26862..4a81061 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -200,6 +200,19 @@ protected: bool compile_locals_for_block (Resolver::Rib &rib, Bfunction *fndecl, std::vector &locals); + + Bexpression *coercion_site (Bexpression *compiled_ref, TyTy::BaseType *actual, + TyTy::BaseType *expected, Location locus); + + Bexpression *coerce_to_dyn_object (Bexpression *compiled_ref, + TyTy::BaseType *actual, + TyTy::BaseType *expected, + TyTy::DynamicObjectType *ty, + Location locus); + + Bexpression * + compute_address_for_trait_item (const Resolver::TraitItemReference *ref, + TyTy::BaseType *receiver); }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 7d2f32d..7a4344e 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -343,9 +343,10 @@ private: class TyTyResolveCompile : public TyTy::TyVisitor { public: - static ::Btype *compile (Context *ctx, TyTy::BaseType *ty) + static ::Btype *compile (Context *ctx, TyTy::BaseType *ty, + bool trait_object_mode = false) { - TyTyResolveCompile compiler (ctx); + TyTyResolveCompile compiler (ctx, trait_object_mode); ty->accept_vis (compiler); return compiler.translated; } @@ -378,7 +379,8 @@ public: if (!type.get_return_type ()->is_unit ()) { auto hir_type = type.get_return_type (); - auto ret = TyTyResolveCompile::compile (ctx, hir_type); + auto ret + = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode); results.push_back (Backend::Btyped_identifier ( "_", ret, ctx->get_mappings ()->lookup_location (hir_type->get_ref ()))); @@ -388,7 +390,7 @@ public: { auto param_tyty = param_pair.second; auto compiled_param_type - = TyTyResolveCompile::compile (ctx, param_tyty); + = TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode); auto compiled_param = Backend::Btyped_identifier ( param_pair.first->as_string (), compiled_param_type, @@ -429,7 +431,6 @@ public: if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type)) return; - // create implicit struct std::vector fields; for (size_t i = 0; i < type.num_fields (); i++) { @@ -570,7 +571,7 @@ public: void visit (TyTy::ReferenceType &type) override { Btype *base_compiled_type - = TyTyResolveCompile::compile (ctx, type.get_base ()); + = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); if (type.is_mutable ()) { translated = ctx->get_backend ()->reference_type (base_compiled_type); @@ -585,7 +586,7 @@ public: void visit (TyTy::PointerType &type) override { Btype *base_compiled_type - = TyTyResolveCompile::compile (ctx, type.get_base ()); + = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); if (type.is_mutable ()) { translated = ctx->get_backend ()->pointer_type (base_compiled_type); @@ -610,12 +611,63 @@ public: translated = ctx->get_backend ()->unit_type (); } - void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } + void visit (TyTy::DynamicObjectType &type) override + { + if (trait_object_mode) + { + translated = ctx->get_backend ()->integer_type ( + true, ctx->get_backend ()->get_pointer_size ()); + return; + } + + if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type)) + return; + + // create implicit struct + auto items = type.get_object_items (); + std::vector fields; + + Btype *uint = ctx->get_backend ()->integer_type ( + true, ctx->get_backend ()->get_pointer_size ()); + Btype *uintptr_ty = ctx->get_backend ()->pointer_type (uint); + + Backend::Btyped_identifier f ("__receiver_trait_obj_ptr", uintptr_ty, + ctx->get_mappings ()->lookup_location ( + type.get_ty_ref ())); + fields.push_back (std::move (f)); + + for (size_t i = 0; i < items.size (); i++) + { + // mrustc seems to make a vtable consisting of uintptr's + Btype *uint = ctx->get_backend ()->integer_type ( + true, ctx->get_backend ()->get_pointer_size ()); + Btype *uintptr_ty = ctx->get_backend ()->pointer_type (uint); + + Backend::Btyped_identifier f ("__" + std::to_string (i), uintptr_ty, + ctx->get_mappings ()->lookup_location ( + type.get_ty_ref ())); + fields.push_back (std::move (f)); + } + + Btype *type_record = ctx->get_backend ()->struct_type (fields); + Btype *named_struct + = ctx->get_backend ()->named_type (type.get_name (), type_record, + ctx->get_mappings ()->lookup_location ( + type.get_ty_ref ())); + + ctx->push_type (named_struct); + translated = named_struct; + + ctx->insert_compiled_type (type.get_ty_ref (), named_struct, &type); + } private: - TyTyResolveCompile (Context *ctx) : ctx (ctx), translated (nullptr) {} + TyTyResolveCompile (Context *ctx, bool trait_object_mode) + : ctx (ctx), trait_object_mode (trait_object_mode), translated (nullptr) + {} Context *ctx; + bool trait_object_mode; ::Btype *translated; }; diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust-compile-stmt.h index 73f6f22..e3fa697 100644 --- a/gcc/rust/backend/rust-compile-stmt.h +++ b/gcc/rust/backend/rust-compile-stmt.h @@ -58,6 +58,7 @@ public: if (!ctx->get_tyctx ()->lookup_type (stmt.get_mappings ().get_hirid (), &ty)) { + // FIXME this should be an assertion instead rust_fatal_error (stmt.get_locus (), "failed to lookup variable declaration type"); return; @@ -66,15 +67,26 @@ public: Bvariable *var = nullptr; if (!ctx->lookup_var_decl (stmt.get_mappings ().get_hirid (), &var)) { + // FIXME this should be an assertion instead and use error mark node rust_fatal_error (stmt.get_locus (), "failed to lookup compiled variable declaration"); return; } Bexpression *init = CompileExpr::Compile (stmt.get_init_expr (), ctx); + // FIXME use error_mark_node, check that CompileExpr returns error_mark_node + // on failure and make this an assertion if (init == nullptr) return; + TyTy::BaseType *actual = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual); + rust_assert (ok); + + TyTy::BaseType *expected = ty; + init = coercion_site (init, actual, expected, stmt.get_locus ()); + auto fnctx = ctx->peek_fn (); if (ty->is_unit ()) { diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index f0e26dc..58c679f 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -108,6 +108,9 @@ CompileExpr::visit (HIR::CallExpr &expr) void CompileExpr::visit (HIR::MethodCallExpr &expr) { + // method receiver + Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx); + // lookup the resolved name NodeId resolved_node_id = UNKNOWN_NODEID; if (!ctx->get_resolver ()->lookup_resolved_name ( @@ -134,6 +137,110 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *fntype = static_cast (lookup_fntype); + TyTy::BaseType *receiver = nullptr; + ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (), + &receiver); + rust_assert (ok); + + bool is_dyn_dispatch + = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC; + bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM; + if (is_generic_receiver) + { + TyTy::ParamType *p = static_cast (receiver); + receiver = p->resolve (); + } + + if (is_dyn_dispatch) + { + TyTy::DynamicObjectType *dyn + = static_cast (receiver->get_root ()); + + size_t offs = 0; + const Resolver::TraitItemReference *ref = nullptr; + for (auto &item : dyn->get_object_items ()) + { + auto t = item->get_tyty (); + rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF); + auto ft = static_cast (t); + + if (ft->get_id () == fntype->get_id ()) + { + ref = item; + break; + } + offs++; + } + + if (ref == nullptr) + { + translated = ctx->get_backend ()->error_expression (); + return; + } + + // get any indirection sorted out + auto receiver_ref = self; + if (receiver->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r + = static_cast (receiver); + auto indirect_ty = r->get_base (); + Btype *indrect_compiled_tyty + = TyTyResolveCompile::compile (ctx, indirect_ty); + + Bexpression *indirect + = ctx->get_backend ()->indirect_expression (indrect_compiled_tyty, + receiver_ref, true, + expr.get_locus ()); + receiver_ref = indirect; + } + + // access the offs + 1 for the fnptr and offs=0 for the reciever obj + Bexpression *self_argument + = ctx->get_backend ()->struct_field_expression (receiver_ref, 0, + expr.get_locus ()); + + // access the vtable for the fn + Bexpression *fn_vtable_access + = ctx->get_backend ()->struct_field_expression (receiver_ref, offs + 1, + expr.get_locus ()); + + // cast it to the correct fntype + Btype *expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true); + Bexpression *fn_convert_expr + = ctx->get_backend ()->convert_expression (expected_fntype, + fn_vtable_access, + expr.get_locus ()); + + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + + Bvariable *fn_convert_expr_tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, expected_fntype, fn_convert_expr, + is_address_taken, expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + + std::vector args; + args.push_back (self_argument); + expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool { + Bexpression *compiled_expr = CompileExpr::Compile (p, ctx); + rust_assert (compiled_expr != nullptr); + args.push_back (compiled_expr); + return true; + }); + + Bexpression *fn_expr + = ctx->get_backend ()->var_expression (fn_convert_expr_tmp, + expr.get_locus ()); + + translated + = ctx->get_backend ()->call_expression (fnctx.fndecl, fn_expr, args, + nullptr, expr.get_locus ()); + return; + } + // lookup compiled functions Bfunction *fn = nullptr; if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) @@ -157,17 +264,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) trait->get_mappings ().get_defid (), &trait_ref); rust_assert (ok); - TyTy::BaseType *receiver = nullptr; - ok = ctx->get_tyctx ()->lookup_receiver ( - expr.get_mappings ().get_hirid (), &receiver); - rust_assert (ok); - - if (receiver->get_kind () == TyTy::TypeKind::PARAM) - { - TyTy::ParamType *p = static_cast (receiver); - receiver = p->resolve (); - } - // the type resolver can only resolve type bounds to their trait // item so its up to us to figure out if this path should resolve // to an trait-impl-block-item or if it can be defaulted to the @@ -290,10 +386,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) std::vector args; - // method receiver - Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx); - rust_assert (self != nullptr); - // lookup the autoderef mappings std::vector *adjustments = nullptr; ok = ctx->get_tyctx ()->lookup_autoderef_mappings ( @@ -579,5 +671,138 @@ HIRCompileBase::compile_locals_for_block (Resolver::Rib &rib, Bfunction *fndecl, return true; } + +Bexpression * +HIRCompileBase::coercion_site (Bexpression *compiled_ref, + TyTy::BaseType *actual, TyTy::BaseType *expected, + Location locus) +{ + auto root_actual_kind = actual->get_root ()->get_kind (); + auto root_expected_kind = expected->get_root ()->get_kind (); + + if (root_expected_kind == TyTy::TypeKind::DYNAMIC + && root_actual_kind != TyTy::TypeKind::DYNAMIC) + { + TyTy::DynamicObjectType *dyn + = static_cast (expected->get_root ()); + return coerce_to_dyn_object (compiled_ref, actual, expected, dyn, locus); + } + + return compiled_ref; +} + +Bexpression * +HIRCompileBase::coerce_to_dyn_object (Bexpression *compiled_ref, + TyTy::BaseType *actual, + TyTy::BaseType *expected, + TyTy::DynamicObjectType *ty, + Location locus) +{ + Btype *dynamic_object = TyTyResolveCompile::compile (ctx, ty); + + //' this assumes ordering and current the structure is + // __trait_object_ptr + // [list of function ptrs] + + std::vector vals; + vals.push_back (compiled_ref); + for (auto &item : ty->get_object_items ()) + { + // compute the address of each method item + auto address = compute_address_for_trait_item (item, actual->get_root ()); + vals.push_back (address); + } + + Bexpression *constructed_trait_object + = ctx->get_backend ()->constructor_expression (dynamic_object, vals, -1, + + locus); + + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + + Bvariable *dyn_tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, dynamic_object, constructed_trait_object, + is_address_taken, locus, &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + + // FIXME this needs to be more generic to apply any covariance + + auto e = expected; + std::vector adjustments; + while (e->get_kind () == TyTy::TypeKind::REF) + { + auto r = static_cast (e); + e = r->get_base (); + + if (r->is_mutable ()) + adjustments.push_back ( + Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::MUT_REF, + e)); + else + adjustments.push_back ( + Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::IMM_REF, + e)); + } + + auto resulting_dyn_object_ref + = ctx->get_backend ()->var_expression (dyn_tmp, locus); + for (auto it = adjustments.rbegin (); it != adjustments.rend (); it++) + { + bool ok + = it->get_type () == Resolver::Adjustment::AdjustmentType::IMM_REF + || it->get_type () == Resolver::Adjustment::AdjustmentType::MUT_REF; + rust_assert (ok); + + resulting_dyn_object_ref + = ctx->get_backend ()->address_expression (resulting_dyn_object_ref, + locus); + } + return resulting_dyn_object_ref; +} + +Bexpression * +HIRCompileBase::compute_address_for_trait_item ( + const Resolver::TraitItemReference *trait_item_ref, TyTy::BaseType *receiver) +{ + TyTy::BaseType *item_type = trait_item_ref->get_tyty (); + rust_assert (item_type->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fntype = static_cast (item_type); + + auto root = receiver->get_root (); + HIR::PathIdentSegment segment_name (trait_item_ref->get_identifier ()); + std::vector candidates + = Resolver::PathProbeType::Probe (root, segment_name, true, false, true); + + // FIXME for default trait item resolution + // + // if (candidates.size () == 0) + // { + // rust_assert (trait_item_ref->is_optional ()); // has definition + // + // CompileTraitItem::Compile (self_type, + // trait_item_ref->get_hir_trait_item (), ctx, + // fntype); + // if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) + // { + // return ctx->get_backend ()->error_expression (); + // } + // } + + rust_assert (!candidates.empty ()); + rust_assert (candidates.size () == 1); + + Resolver::PathProbeCandidate *candidate = &candidates.at (0); + rust_assert (candidate->is_impl_candidate ()); + + HIR::ImplItem *impl_item = candidate->item.impl.impl_item; + + return CompileInherentImplItem::Compile (receiver->get_root (), impl_item, + ctx, true, fntype, true, + Location () /* FIXME */); +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 2b5b78c..0b64a36 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -177,6 +177,7 @@ private: }; // this wraps up the HIR::Trait so we can do analysis on it + class TraitReference { public: diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 196a6ca..5f69deb 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -88,7 +88,16 @@ TypeBoundPredicate::get () const std::string TypeBoundPredicate::get_name () const { - return get ()->get_name (); + auto mappings = Analysis::Mappings::get (); + auto trait = get (); + auto nodeid = trait->get_mappings ().get_nodeid (); + + const Resolver::CanonicalPath *p = nullptr; + if (mappings->lookup_canonical_path (mappings->get_current_crate (), nodeid, + &p)) + return p->get (); + + return trait->get_name (); } bool diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index bfe1043..f4ce501 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2312,6 +2312,13 @@ DynamicObjectType::clone () const get_combined_refs ()); } +std::string +DynamicObjectType::get_name () const +{ + std::string bounds = "[" + raw_bounds_as_string () + "]"; + return "dyn " + bounds; +} + bool DynamicObjectType::is_equal (const BaseType &other) const { @@ -2324,6 +2331,35 @@ DynamicObjectType::is_equal (const BaseType &other) const return bounds_compatible (other, Location (), false); } +const std::vector +DynamicObjectType::get_object_items () const +{ + std::vector items; + for (auto &bound : get_specified_bounds ()) + { + const Resolver::TraitReference *trait = bound.get (); + for (auto &item : trait->get_trait_items ()) + { + if (item.get_trait_item_type () + == Resolver::TraitItemReference::TraitItemType::FN + && item.is_object_safe ()) + items.push_back (&item); + } + + for (auto &super_trait : trait->get_super_traits ()) + { + for (auto &item : super_trait->get_trait_items ()) + { + if (item.get_trait_item_type () + == Resolver::TraitItemReference::TraitItemType::FN + && item.is_object_safe ()) + items.push_back (&item); + } + } + } + return items; +} + // rust-tyty-call.h void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 040831e..7ab2b2c 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -26,8 +26,10 @@ #include "rust-abi.h" namespace Rust { + namespace Resolver { class TraitReference; +class TraitItemReference; class AssociatedImplTrait; } // namespace Resolver @@ -186,9 +188,12 @@ public: std::string raw_bounds_as_string () const { std::string buf; - for (auto &b : specified_bounds) - buf += b.as_string () + " + "; - + for (size_t i = 0; i < specified_bounds.size (); i++) + { + const TypeBoundPredicate &b = specified_bounds.at (i); + bool has_next = (i + 1) < specified_bounds.size (); + buf += b.get_name () + (has_next ? " + " : ""); + } return buf; } @@ -1857,7 +1862,11 @@ public: BaseType *clone () const final override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; + + // this returns a flat list of items including super trait bounds + const std::vector + get_object_items () const; }; } // namespace TyTy diff --git a/gcc/testsuite/rust/execute/torture/trait5.rs b/gcc/testsuite/rust/execute/torture/trait5.rs new file mode 100644 index 0000000..f25784a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait5.rs @@ -0,0 +1,41 @@ +/* { dg-output "123\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +impl Bar for Foo { + fn baz(&self) { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn static_dispatch(t: &T) { + t.baz(); +} + +fn dynamic_dispatch(t: &dyn Bar) { + t.baz(); +} + +fn main() -> i32 { + let a = &Foo(123); + static_dispatch(a); + + let b: &dyn Bar = a; + dynamic_dispatch(b); + + 0 +} -- cgit v1.1