From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id BFED8386DC68; Wed, 8 Jun 2022 12:28:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BFED8386DC68 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] Support Slices from rustc libcore 1.49.0 X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 69d6fddcbb9daba68087eb38bffa9953e01b4888 X-Git-Newrev: 0e686c0fe01ef29be1c08fb8440caf76c9fb66d9 Message-Id: <20220608122808.BFED8386DC68@sourceware.org> Date: Wed, 8 Jun 2022 12:28:08 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 12:28:08 -0000 https://gcc.gnu.org/g:0e686c0fe01ef29be1c08fb8440caf76c9fb66d9 commit 0e686c0fe01ef29be1c08fb8440caf76c9fb66d9 Author: Philip Herron Date: Fri Apr 8 15:18:23 2022 +0100 Support Slices from rustc libcore 1.49.0 This is unfortunatly a mega commit, in testing gccrs against the slice code which is highly generic stress tested our implementation of generics and poked the hole in or lack of support of generic higher ranked trait bounds and more specificily generic associated types. More refactoring is needed to eventually remove the setup_associated_types and replace it entirely with this new setup_associated_types2 which takes into account the trait bound receiver and its predicate. In order to support slices, the code in libcore defines an index lang item ```rust impl Index for [T] where I: SliceIndex<[T]>, { type Output = I::Output; fn index(&self, index: I) -> &I::Output { index.index(self) } } ``` This is the entry point where by the self here is a generic slice. So in our case we have: ```rust let a = [1, 2, 3, 4, 5]; let b = &a[1..3]; ``` 'a' is an array and b is our desired slice, so we must remember that from algebraic data type constructor. But our receiver is still an array, so in order to be able to call this index lang item we must 'unsize' our array (see #1045) this allows for method resolution to adjust an array into a FatPtr which is simply a struct containing reference to the array and the capacity (GCC MAX_DOMAIN) of the underlying array data type. So now we are able to infer the substituions for this index fn call to: ``` fn index(&self : [], index: Range) -> &I::Output->placeholder ``` The complex piece here is the Higher ranked trait bound: ``` where I: SliceIndex<[T]> ``` So in this method call no generic arguments are specified so we must try and infer the types. So during monomorphization the inference variables need to be recursively propogated into the higher ranked trait bound. So that the higher ranked trait bound looks like: ``` SliceIndex<[]> // like we seen earlier for the Self type ``` The monomorphization stage also needs to take into account the higher ranked trait bound's type which is 'I' and infered to be: Range. This is where specialization needs to occur. ```rust unsafe impl SliceIndex<[T]> for Range { type Output = [T]; unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { unsafe { let a: *const T = slice.as_ptr(); let b: *const T = a.add(self.start); slice_from_raw_parts(b, self.end - self.start) } } fn index(self, slice: &[T]) -> &[T] { unsafe { &*self.get_unchecked(slice) } } } ``` So now we need to compute the constrained type-parameters for this specialized impl block. And in this case is fairly simple: ``` impl SliceIndex<[T]> for Range vs I: SliceIndex<[]> and Range<> ``` Here we need to compute that T is , which is required since associated type Output is used in our original method call and this is generic which requires us to set it up but both the Self type or the trait bound here in this impl block could be generic so special care needs to be taken to compute this safely. Once the constrained types are computer we can also unify the Self types which specializes our original Range type into the correct Range that this trait bound expects. We used a callback here when we reusively pass down the SubstitutionArgumentMappings when any Parameter type is substitued we get a callback to hold a set of mappings in a generic way what generic types are being substituted. From all of this work this stressed our generics implementation to breaking point due to the use of the generic trait bound which was not supported and it also exposed many bugs in our implementation. This is why I feel it is best to keep this a large patch as so much of this patch will cause regressions if we don't keep it together. One of the main changes we have made is how we handle parameters substitution for example we might have a generic such as '&Y' but this gets substituted with Y=T which is a new type parameter. Before we used to directly just change this from &Y to &T which is correct but this looses context from the generic argument bindings. So now we maintain the information that &Y changes to &(Y=T) so that we see Y was substutued with T so that subsequent substitutions or inferences can change Y=?T and correctly map &Y to &(Y=T) to &(Y=?T). The other major piece which was changed during this patch was how we perform the method resolution on higher ranked trait bound calls where we compute the specified bound possible candidates once so that in the case: ``` trait Bar { fn baz(&self) } fn foo(a: &T) { a.baz() } ``` Here the type parameter T gets derefed to find the specified bound of Bar which contains the method baz. This means that we try calling baz with T vs &T which fails then we try the reference type T again. This results into two useless adjustments of indirection and referencing but GCC optimizes this away. Before this patch we computed the specified bound for each attempt which was wrong. Fixes #849 Diff: --- gcc/rust/backend/rust-compile-expr.cc | 19 +- gcc/rust/backend/rust-compile.cc | 18 +- gcc/rust/typecheck/rust-hir-dot-operator.cc | 64 +++---- gcc/rust/typecheck/rust-hir-dot-operator.h | 20 ++- gcc/rust/typecheck/rust-hir-trait-ref.h | 5 + gcc/rust/typecheck/rust-hir-trait-resolve.cc | 169 +++++++++++++++++- gcc/rust/typecheck/rust-hir-trait-resolve.h | 24 ++- gcc/rust/typecheck/rust-hir-type-check-expr.cc | 14 +- gcc/rust/typecheck/rust-hir-type-check-expr.h | 34 ++-- gcc/rust/typecheck/rust-hir-type-check-item.h | 2 + gcc/rust/typecheck/rust-hir-type-check-path.cc | 12 +- gcc/rust/typecheck/rust-substitution-mapper.cc | 18 +- gcc/rust/typecheck/rust-tyty-bounds.cc | 152 ++++++++++------ gcc/rust/typecheck/rust-tyty-cmp.h | 13 +- gcc/rust/typecheck/rust-tyty-coercion.h | 10 +- gcc/rust/typecheck/rust-tyty-rules.h | 15 +- gcc/rust/typecheck/rust-tyty.cc | 197 +++++++++++++-------- gcc/rust/typecheck/rust-tyty.h | 62 ++++--- gcc/testsuite/rust/compile/torture/traits19.rs | 33 ++++ gcc/testsuite/rust/execute/torture/slice-magic.rs | 106 +++++++++++ gcc/testsuite/rust/execute/torture/slice-magic2.rs | 106 +++++++++++ 21 files changed, 804 insertions(+), 289 deletions(-) diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 49a6f2f75bf..2128f25f296 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -747,8 +747,9 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, auto root = receiver->get_root (); std::vector candidates - = Resolver::PathProbeType::Probe (root, segment, true, false, true); - + = Resolver::PathProbeType::Probe (root, segment, true /* probe_impls */, + false /* probe_bounds */, + true /* ignore_mandatory_trait_items */); if (candidates.size () == 0) { // this means we are defaulting back to the trait_item if @@ -776,12 +777,22 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, rust_assert (candidates.size () == 1); auto &candidate = candidates.at (0); rust_assert (candidate.is_impl_candidate ()); + rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *candidate_call = static_cast (candidate.ty); HIR::ImplItem *impl_item = candidate.item.impl.impl_item; - if (!fntype->has_subsititions_defined ()) + if (!candidate_call->has_subsititions_defined ()) return CompileInherentImplItem::Compile (impl_item, ctx); - return CompileInherentImplItem::Compile (impl_item, ctx, fntype); + TyTy::BaseType *monomorphized = candidate_call; + if (candidate_call->needs_generic_substitutions ()) + { + TyTy::BaseType *infer_impl_call + = candidate_call->infer_substitions (expr_locus); + monomorphized = infer_impl_call->unify (fntype); + } + + return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized); } } diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index 9e2c5b32b17..bd782b00390 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -38,7 +38,6 @@ CompileCrate::~CompileCrate () {} void CompileCrate::Compile (HIR::Crate &crate, Context *ctx) - { CompileCrate c (crate, ctx); c.go (); @@ -383,26 +382,11 @@ HIRCompileBase::compute_address_for_trait_item ( = self_bound->lookup_associated_item (ref->get_identifier ()); rust_assert (!associated_self_item.is_error ()); - // apply any generic arguments from this predicate TyTy::BaseType *mono1 = associated_self_item.get_tyty_for_receiver (self); - TyTy::BaseType *mono2 = nullptr; - if (predicate->has_generic_args ()) - { - mono2 = associated_self_item.get_tyty_for_receiver ( - self, predicate->get_generic_args ()); - } - else - { - mono2 = associated_self_item.get_tyty_for_receiver (self); - } rust_assert (mono1 != nullptr); rust_assert (mono1->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *assocated_item_ty1 = static_cast (mono1); - rust_assert (mono2 != nullptr); - rust_assert (mono2->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *assocated_item_ty2 = static_cast (mono2); - // Lookup the impl-block for the associated impl_item if it exists HIR::Function *associated_function = nullptr; for (auto &impl_item : associated_impl_block->get_impl_items ()) @@ -434,7 +418,7 @@ HIRCompileBase::compute_address_for_trait_item ( { TyTy::SubstitutionArgumentMappings mappings = assocated_item_ty1->solve_missing_mappings_from_this ( - *assocated_item_ty2, *lookup_fntype); + *trait_item_fntype, *lookup_fntype); lookup_fntype = lookup_fntype->handle_substitions (mappings); } diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc index ce7c4e1028c..104bd16080e 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.cc +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -126,9 +126,11 @@ MethodResolver::Try (const TyTy::BaseType *r, PathProbeCandidate c = PathProbeCandidate::get_error (); const std::vector &specified_bounds = r->get_specified_bounds (); + const std::vector predicate_items + = get_predicate_items (segment_name, *r, specified_bounds); // 1. try raw - MethodResolver raw (*r, segment_name, specified_bounds); + MethodResolver raw (*r, segment_name, predicate_items); c = raw.select (); if (!c.is_error ()) { @@ -139,7 +141,7 @@ MethodResolver::Try (const TyTy::BaseType *r, TyTy::ReferenceType *r1 = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), Mutability::Imm); - MethodResolver imm_ref (*r1, segment_name, specified_bounds); + MethodResolver imm_ref (*r1, segment_name, predicate_items); c = imm_ref.select (); if (!c.is_error ()) { @@ -152,7 +154,7 @@ MethodResolver::Try (const TyTy::BaseType *r, TyTy::ReferenceType *r2 = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), Mutability::Mut); - MethodResolver mut_ref (*r2, segment_name, specified_bounds); + MethodResolver mut_ref (*r2, segment_name, predicate_items); c = mut_ref.select (); if (!c.is_error ()) { @@ -288,27 +290,6 @@ MethodResolver::select () TyTy::FnType *fntype; }; - std::vector predicate_items; - for (auto &bound : specified_bounds) - { - TyTy::TypeBoundPredicateItem lookup - = bound.lookup_associated_item (segment_name.as_string ()); - if (lookup.is_error ()) - continue; - - bool is_fn = lookup.get_raw_item ()->get_trait_item_type () - == TraitItemReference::TraitItemType::FN; - if (!is_fn) - continue; - - TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty (); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast (ty); - - precdicate_candidate candidate{lookup, fnty}; - predicate_items.push_back (candidate); - } - for (auto impl_item : inherent_impl_fns) { TyTy::FnType *fn = impl_item.ty; @@ -342,9 +323,9 @@ MethodResolver::select () } } - for (auto predicate : predicate_items) + for (const auto &predicate : predicate_items) { - TyTy::FnType *fn = predicate.fntype; + const TyTy::FnType *fn = predicate.fntype; rust_assert (fn->is_method ()); TyTy::BaseType *fn_self = fn->get_self_type (); @@ -355,14 +336,10 @@ MethodResolver::select () const TraitItemReference *trait_item = predicate.lookup.get_raw_item (); - TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver ( - receiver.get_root (), - predicate.lookup.get_parent ()->get_generic_args ()); - PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item, nullptr}; return PathProbeCandidate ( - PathProbeCandidate::CandidateType::TRAIT_FUNC, subst, + PathProbeCandidate::CandidateType::TRAIT_FUNC, fn->clone (), trait_item->get_locus (), c); } } @@ -370,5 +347,30 @@ MethodResolver::select () return PathProbeCandidate::get_error (); } +std::vector +MethodResolver::get_predicate_items ( + const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, + const std::vector &specified_bounds) +{ + std::vector predicate_items; + for (auto &bound : specified_bounds) + { + TyTy::TypeBoundPredicateItem lookup + = bound.lookup_associated_item (segment_name.as_string ()); + if (lookup.is_error ()) + continue; + + TyTy::BaseType *ty = lookup.get_tyty_for_receiver (&receiver); + if (ty->get_kind () == TyTy::TypeKind::FNDEF) + { + TyTy::FnType *fnty = static_cast (ty); + predicate_candidate candidate{lookup, fnty}; + predicate_items.push_back (candidate); + } + } + + return predicate_items; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h index f14300a4bfe..ef1038bd78c 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.h +++ b/gcc/rust/typecheck/rust-hir-dot-operator.h @@ -48,22 +48,32 @@ public: bool autoderef_flag = false); protected: + struct predicate_candidate + { + TyTy::TypeBoundPredicateItem lookup; + TyTy::FnType *fntype; + }; + static MethodCandidate Try (const TyTy::BaseType *r, const HIR::PathIdentSegment &segment_name, std::vector &adjustments); + static std::vector get_predicate_items ( + const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, + const std::vector &specified_bounds); + PathProbeCandidate select (); - MethodResolver (const TyTy::BaseType &receiver, - const HIR::PathIdentSegment &segment_name, - const std::vector &specified_bounds) + MethodResolver ( + const TyTy::BaseType &receiver, const HIR::PathIdentSegment &segment_name, + const std::vector &predicate_items) : receiver (receiver), segment_name (segment_name), - specified_bounds (specified_bounds) + predicate_items (predicate_items) {} const TyTy::BaseType &receiver; const HIR::PathIdentSegment &segment_name; - const std::vector &specified_bounds; + const std::vector &predicate_items; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 585fb6c8dbf..d8c8a1906cd 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -262,6 +262,8 @@ public: return hir_trait_ref->get_mappings (); } + DefId get_defid () const { return get_mappings ().get_defid (); } + bool lookup_hir_trait_item (const HIR::TraitItem &item, TraitItemReference **ref) { @@ -436,6 +438,9 @@ public: void setup_associated_types (); + void setup_associated_types2 (const TyTy::BaseType *self, + const TyTy::TypeBoundPredicate &bound); + void reset_associated_types (); TyTy::BaseType *get_projected_type (const TraitItemReference *trait_item_ref, diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 54fdc0253b6..b4e0efea0fa 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -137,7 +137,7 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) TyTy::PlaceholderType *placeholder = static_cast (item_ty); - placeholder->set_associated_type (ty->get_ref ()); + placeholder->set_associated_type (ty->get_ty_ref ()); } void @@ -175,6 +175,173 @@ AssociatedImplTrait::setup_associated_types () iter.go (); } +void +AssociatedImplTrait::setup_associated_types2 ( + const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound) +{ + // compute the constrained impl block generic arguments based on self and the + // higher ranked trait bound + TyTy::BaseType *receiver = self->clone (); + + // impl SliceIndex<[Y]> for Range + // vs + // I: SliceIndex<[]> and Range<> + // + // we need to figure out what Y is + + TyTy::BaseType *associated_self = get_self (); + rust_assert (associated_self->can_eq (self, false)); + + // grab the parameters + HIR::ImplBlock &impl_block = *get_impl_block (); + std::vector substitutions; + for (auto &generic_param : impl_block.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + // Skipping Lifetime completely until better handling. + break; + + case HIR::GenericParam::GenericKind::TYPE: { + TyTy::BaseType *l = nullptr; + bool ok = context->lookup_type ( + generic_param->get_mappings ().get_hirid (), &l); + if (ok && l->get_kind () == TyTy::TypeKind::PARAM) + { + substitutions.push_back (TyTy::SubstitutionParamMapping ( + static_cast (*generic_param), + static_cast (l))); + } + } + break; + } + } + + // generate inference variables for these bound arguments so we can compute + // their values + Location locus; + std::vector args; + for (auto &p : substitutions) + { + if (p.needs_substitution ()) + { + TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus); + args.push_back (TyTy::SubstitutionArg (&p, infer_var.get_tyty ())); + } + else + { + args.push_back ( + TyTy::SubstitutionArg (&p, p.get_param_ty ()->resolve ())); + } + } + + // this callback gives us the parameters that get substituted so we can + // compute the constrained type parameters for this impl block + std::map param_mappings; + TyTy::ParamSubstCb param_subst_cb + = [&] (const TyTy::ParamType &p, const TyTy::SubstitutionArg &a) { + param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref (); + }; + + TyTy::SubstitutionArgumentMappings infer_arguments (std::move (args), locus, + param_subst_cb); + TyTy::BaseType *impl_self_infer + = (associated_self->needs_generic_substitutions ()) + ? SubstMapperInternal::Resolve (associated_self, infer_arguments) + : associated_self; + + // FIXME this needs to do a lookup for the trait-reference DefId instead of + // assuming its the first one in the list + rust_assert (associated_self->num_specified_bounds () > 0); + TyTy::TypeBoundPredicate &impl_predicate + = associated_self->get_specified_bounds ().at (0); + + // infer the arguments on the predicate + std::vector impl_trait_predicate_args; + for (const auto &arg : impl_predicate.get_substs ()) + { + const TyTy::ParamType *p = arg.get_param_ty (); + if (p->get_symbol ().compare ("Self") == 0) + continue; + + TyTy::BaseType *r = p->resolve (); + r = SubstMapperInternal::Resolve (r, infer_arguments); + impl_trait_predicate_args.push_back (r); + } + + // we need to unify the receiver with the impl-block Self so that we compute + // the type correctly as our receiver may be generic and we are inferring its + // generic arguments and this Self might be the concrete version or vice + // versa. + auto result = receiver->unify (impl_self_infer); + rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); + + // unify the bounds arguments + std::vector hrtb_bound_arguments; + for (const auto &arg : bound.get_substs ()) + { + const TyTy::ParamType *p = arg.get_param_ty (); + if (p->get_symbol ().compare ("Self") == 0) + continue; + + TyTy::BaseType *r = p->resolve (); + hrtb_bound_arguments.push_back (r); + } + + rust_assert (impl_trait_predicate_args.size () + == hrtb_bound_arguments.size ()); + for (size_t i = 0; i < impl_trait_predicate_args.size (); i++) + { + TyTy::BaseType *a = impl_trait_predicate_args.at (i); + TyTy::BaseType *b = hrtb_bound_arguments.at (i); + + result = a->unify (b); + rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); + } + + // create the argument list + std::vector associated_arguments; + for (auto &p : substitutions) + { + std::string symbol = p.get_param_ty ()->get_symbol (); + auto it = param_mappings.find (symbol); + rust_assert (it != param_mappings.end ()); + + HirId id = it->second; + TyTy::BaseType *argument = nullptr; + bool ok = context->lookup_type (id, &argument); + rust_assert (ok); + + TyTy::SubstitutionArg arg (&p, argument); + associated_arguments.push_back (arg); + } + + TyTy::SubstitutionArgumentMappings associated_type_args ( + std::move (associated_arguments), locus); + + 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; + + // this might be generic + TyTy::BaseType *substituted + = SubstMapperInternal::Resolve (lookup, associated_type_args); + resolved_trait_item->associated_type_set (substituted); + }); + iter.go (); +} + void AssociatedImplTrait::reset_associated_types () { diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 806a46f13ce..651af9db81a 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -141,24 +141,26 @@ private: break; } } - rust_assert (self != nullptr); // Check if there is a super-trait, and apply this bound to the Self // TypeParam std::vector specified_bounds; - // They also inherit themselves as a bound this enables a trait item to - // reference other Self::trait_items + // copy the substitition mappings std::vector self_subst_copy; for (auto &sub : substitutions) self_subst_copy.push_back (sub.clone ()); - specified_bounds.push_back ( - TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (), - std::move (self_subst_copy), - trait_reference->get_locus ())); + // They also inherit themselves as a bound this enables a trait item to + // reference other Self::trait_items + auto self_hrtb + = TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (), + std::move (self_subst_copy), + trait_reference->get_locus ()); + specified_bounds.push_back (self_hrtb); + // look for any std::vector super_traits; if (trait_reference->has_type_param_bounds ()) { @@ -171,12 +173,8 @@ private: = static_cast (bound.get ()); // FIXME this might be recursive we need a check for that - - TraitReference *trait = resolve_trait_path (b->get_path ()); - TyTy::TypeBoundPredicate predicate (*trait, - bound->get_locus ()); - - specified_bounds.push_back (std::move (predicate)); + auto predicate = get_predicate_from_bound (b->get_path ()); + specified_bounds.push_back (predicate); super_traits.push_back (predicate.get ()); } } diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 539a3fee6f5..a3d911efd79 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -390,7 +390,6 @@ TypeCheckExpr::resolve_operator_overload ( rust_assert (fn->is_method ()); auto root = lhs->get_root (); - bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; if (root->get_kind () == TyTy::TypeKind::ADT) { const TyTy::ADTType *adt = static_cast (root); @@ -446,13 +445,8 @@ TypeCheckExpr::resolve_operator_overload ( } // handle generics - if (!receiver_is_type_param) - { - if (lookup->needs_generic_substitutions ()) - { - lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); - } - } + if (lookup->needs_generic_substitutions ()) + lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); // type check the arguments if required TyTy::FnType *type = static_cast (lookup); @@ -470,6 +464,10 @@ TypeCheckExpr::resolve_operator_overload ( fnparam.second->unify (rhs); // typecheck the rhs } + rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); + fn = static_cast (lookup); + fn->monomorphize (); + // get the return type TyTy::BaseType *function_ret_tyty = type->get_return_type ()->clone (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 1b14693aa8d..560581d588b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -291,7 +291,6 @@ public: } auto root = receiver_tyty->get_root (); - bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; if (root->get_kind () == TyTy::TypeKind::ADT) { const TyTy::ADTType *adt = static_cast (root); @@ -346,28 +345,21 @@ public: } } - if (!receiver_is_type_param) + // apply any remaining generic arguments + if (expr.get_method_name ().has_generic_args ()) { - // apply any remaining generic arguments - if (expr.get_method_name ().has_generic_args ()) - { - HIR::GenericArgs &args - = expr.get_method_name ().get_generic_args (); - lookup = SubstMapper::Resolve (lookup, - expr.get_method_name ().get_locus (), - &args); - if (lookup->get_kind () == TyTy::TypeKind::ERROR) - return; - } - else if (lookup->needs_generic_substitutions ()) - { - lookup - = SubstMapper::InferSubst (lookup, - expr.get_method_name ().get_locus ()); - } + HIR::GenericArgs &args = expr.get_method_name ().get_generic_args (); + lookup + = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (), + &args); + if (lookup->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, + expr.get_method_name ().get_locus ()); } - - // ADT expected but got PARAM TyTy::BaseType *function_ret_tyty = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self, diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 4c6c4a633d2..9846ed602f7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -79,6 +79,8 @@ public: rust_assert (!trait_reference->is_error ()); specified_bound = get_predicate_from_bound (*ref.get ()); + // FIXME error out maybe? + // if specified_Bound == TyTy::TypeBoundPredicate::error() ? } TyTy::BaseType *self = nullptr; diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index cd6d67a56ff..e2fa7f5e9ac 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -45,8 +45,8 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) } // Resolve the trait now - TraitReference *trait_ref - = TraitResolver::Resolve (*qual_path_type.get_trait ().get ()); + std::unique_ptr &trait_path_ref = qual_path_type.get_trait (); + TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ()); if (trait_ref->is_error ()) return; @@ -59,6 +59,14 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) if (expr.get_segments ().empty ()) return; + // get the predicate for the bound + auto specified_bound = get_predicate_from_bound (*trait_path_ref.get ()); + if (specified_bound.is_error ()) + return; + + // inherit the bound + root->inherit_bounds ({specified_bound}); + // we need resolve to the impl block NodeId impl_resolved_id = UNKNOWN_NODEID; bool ok = resolver->lookup_resolved_name ( diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index f96b9b3ee7a..f80368a0339 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.cc +++ b/gcc/rust/typecheck/rust-substitution-mapper.cc @@ -26,19 +26,31 @@ TyTy::BaseType * SubstMapperInternal::Resolve (TyTy::BaseType *base, TyTy::SubstitutionArgumentMappings &mappings) { + auto context = TypeCheckContext::get (); + SubstMapperInternal mapper (base->get_ref (), mappings); base->accept_vis (mapper); rust_assert (mapper.resolved != nullptr); // insert these new implict types into the context - bool is_param = mapper.resolved->get_kind () == TyTy::TypeKind::PARAM; - if (!is_param) + TyTy::BaseType *unused = nullptr; + bool is_ty_available + = context->lookup_type (mapper.resolved->get_ty_ref (), &unused); + if (!is_ty_available) { - auto context = TypeCheckContext::get (); context->insert_type ( Analysis::NodeMapping (0, 0, mapper.resolved->get_ty_ref (), 0), mapper.resolved); } + bool is_ref_available + = context->lookup_type (mapper.resolved->get_ref (), &unused); + if (!is_ref_available) + { + context->insert_type (Analysis::NodeMapping (0, 0, + mapper.resolved->get_ref (), + 0), + mapper.resolved); + } return mapper.resolved; } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index b34db3bd44e..e226400f5d9 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -106,28 +106,46 @@ TypeBoundPredicate::TypeBoundPredicate ( : SubstitutionRef (trait_reference.get_trait_substs (), SubstitutionArgumentMappings::error ()), reference (trait_reference.get_mappings ().get_defid ()), locus (locus), - args (HIR::GenericArgs::create_empty ()), error_flag (false) -{} + error_flag (false) +{ + // we setup a dummy implict self argument + SubstitutionArg placeholder_self (&get_substs ().front (), nullptr); + used_arguments.get_mappings ().push_back (placeholder_self); +} TypeBoundPredicate::TypeBoundPredicate ( DefId reference, std::vector substitutions, Location locus) : SubstitutionRef (std::move (substitutions), SubstitutionArgumentMappings::error ()), - reference (reference), locus (locus), - args (HIR::GenericArgs::create_empty ()), error_flag (false) -{} + reference (reference), locus (locus), error_flag (false) +{ + // we setup a dummy implict self argument + SubstitutionArg placeholder_self (&get_substs ().front (), nullptr); + used_arguments.get_mappings ().push_back (placeholder_self); +} TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other) - : SubstitutionRef ({}, other.used_arguments), reference (other.reference), - locus (other.locus), args (other.args), error_flag (other.error_flag) + : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()), + reference (other.reference), locus (other.locus), + error_flag (other.error_flag) { substitutions.clear (); - if (!other.is_error ()) + + for (const auto &p : other.get_substs ()) + substitutions.push_back (p.clone ()); + + std::vector mappings; + for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++) { - for (const auto &p : other.get_substs ()) - substitutions.push_back (p.clone ()); + const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i); + SubstitutionArg arg (oa); + mappings.push_back (std::move (arg)); } + + used_arguments + = SubstitutionArgumentMappings (mappings, + other.used_arguments.get_locus ()); } TypeBoundPredicate & @@ -135,17 +153,25 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate &other) { reference = other.reference; locus = other.locus; - args = other.args; error_flag = other.error_flag; - used_arguments = other.used_arguments; + used_arguments = SubstitutionArgumentMappings::error (); substitutions.clear (); - if (!other.is_error ()) + for (const auto &p : other.get_substs ()) + substitutions.push_back (p.clone ()); + + std::vector mappings; + for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++) { - for (const auto &p : other.get_substs ()) - substitutions.push_back (p.clone ()); + const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i); + SubstitutionArg arg (oa); + mappings.push_back (std::move (arg)); } + used_arguments + = SubstitutionArgumentMappings (mappings, + other.used_arguments.get_locus ()); + return *this; } @@ -203,17 +229,22 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args) { // we need to get the substitutions argument mappings but also remember that // we have an implicit Self argument which we must be careful to respect - rust_assert (used_arguments.is_empty ()); + rust_assert (!used_arguments.is_empty ()); rust_assert (!substitutions.empty ()); - // we setup a dummy implict self argument - SubstitutionArg placeholder_self (&substitutions.front (), nullptr); - used_arguments.get_mappings ().push_back (std::move (placeholder_self)); - // now actually perform a substitution used_arguments = get_mappings_from_generic_args (*generic_args); + error_flag |= used_arguments.is_error (); - args = *generic_args; + auto &subst_mappings = used_arguments; + for (auto &sub : get_substs ()) + { + SubstitutionArg arg = SubstitutionArg::error (); + bool ok + = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); + if (ok && arg.get_tyty () != nullptr) + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); + } } bool @@ -235,47 +266,34 @@ TypeBoundPredicate::lookup_associated_item (const std::string &search) const return TypeBoundPredicateItem (this, trait_item_ref); } +TypeBoundPredicateItem +TypeBoundPredicate::lookup_associated_item ( + const Resolver::TraitItemReference *ref) const +{ + return lookup_associated_item (ref->get_identifier ()); +} + BaseType * -TypeBoundPredicateItem::get_tyty_for_receiver ( - const TyTy::BaseType *receiver, const HIR::GenericArgs *bound_args) +TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) { TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty (); - if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) - { - TyTy::FnType *fn = static_cast (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 mappings; - mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ())); - - Location locus; // FIXME - TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus); - trait_item_tyty - = Resolver::SubstMapperInternal::Resolve (trait_item_tyty, args); - } + if (parent->get_substitution_arguments ().is_empty ()) + return trait_item_tyty; - if (!parent->has_generic_args ()) + const Resolver::TraitItemReference *tref = get_raw_item (); + bool is_associated_type = tref->get_trait_item_type (); + if (is_associated_type) return trait_item_tyty; - // FIXME LEAK this should really be const - const HIR::GenericArgs *args - = (bound_args != nullptr) ? bound_args : parent->get_generic_args (); - HIR::GenericArgs *generic_args = new HIR::GenericArgs (*args); - TyTy::BaseType *resolved - = Resolver::SubstMapper::Resolve (trait_item_tyty, parent->get_locus (), - generic_args); + SubstitutionArgumentMappings gargs = parent->get_substitution_arguments (); + + // set up the self mapping + rust_assert (!gargs.is_empty ()); + auto &sarg = gargs.get_mappings ().at (0); + SubstitutionArg self (sarg.get_param_mapping (), receiver->clone ()); + gargs.get_mappings ()[0] = self; - return resolved; + return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, gargs); } bool TypeBoundPredicate::is_error () const @@ -289,9 +307,25 @@ TypeBoundPredicate::is_error () const } BaseType * -TypeBoundPredicate::handle_substitions (SubstitutionArgumentMappings mappings) +TypeBoundPredicate::handle_substitions ( + SubstitutionArgumentMappings subst_mappings) { - gcc_unreachable (); + for (auto &sub : get_substs ()) + { + if (sub.get_param_ty () == nullptr) + continue; + + ParamType *p = sub.get_param_ty (); + BaseType *r = p->resolve (); + BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings); + + p->set_ty_ref (s->get_ty_ref ()); + } + + // FIXME more error handling at some point + // used_arguments = subst_mappings; + // error_flag |= used_arguments.is_error (); + return nullptr; } @@ -301,7 +335,7 @@ TypeBoundPredicate::requires_generic_args () const if (is_error ()) return false; - return substitutions.size () > 1 && args.is_empty (); + return substitutions.size () > 1; } // trait item reference @@ -351,7 +385,7 @@ TypeBoundsMappings::raw_bounds_as_string () const { const TypeBoundPredicate &b = specified_bounds.at (i); bool has_next = (i + 1) < specified_bounds.size (); - buf += b.get_name () + (has_next ? " + " : ""); + buf += b.as_string () + (has_next ? " + " : ""); } return buf; } diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index 9ea49cae820..f3118ba7dbb 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -1271,14 +1271,10 @@ public: // to handle the typing of the struct bool can_eq (const BaseType *other) override { - if (base->get_ref () == base->get_ty_ref ()) + if (!base->can_resolve ()) return BaseCmp::can_eq (other); - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (base->get_ty_ref (), &lookup); - rust_assert (ok); - + auto lookup = base->resolve (); return lookup->can_eq (other, emit_error_flag); } @@ -1425,11 +1421,6 @@ public: void visit (const SliceType &) 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 4deed5521a9..c24f17e6c94 100644 --- a/gcc/rust/typecheck/rust-tyty-coercion.h +++ b/gcc/rust/typecheck/rust-tyty-coercion.h @@ -53,12 +53,14 @@ public: if (p->can_resolve ()) { other = p->resolve (); + return get_base ()->coerce (other); } } else if (other->get_kind () == TypeKind::PROJECTION) { ProjectionType *p = static_cast (other); other = p->get (); + return get_base ()->coerce (other); } other->accept_vis (*this); @@ -1351,14 +1353,10 @@ public: // to handle the typing of the struct BaseType *coerce (BaseType *other) override final { - if (base->get_ref () == base->get_ty_ref ()) + if (!base->can_resolve ()) return BaseCoercionRules::coerce (other); - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (base->get_ty_ref (), &lookup); - rust_assert (ok); - + auto lookup = base->resolve (); return lookup->unify (other); } diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index c1fc2cd96c1..7c50112db60 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -60,10 +60,7 @@ public: if (other->get_kind () == TypeKind::PARAM) { ParamType *p = static_cast (other); - if (p->can_resolve ()) - { - other = p->resolve (); - } + other = p->resolve (); } else if (other->get_kind () == TypeKind::PLACEHOLDER) { @@ -71,12 +68,14 @@ public: if (p->can_resolve ()) { other = p->resolve (); + return get_base ()->unify (other); } } else if (other->get_kind () == TypeKind::PROJECTION) { ProjectionType *p = static_cast (other); other = p->get (); + return get_base ()->unify (other); } other->accept_vis (*this); @@ -1328,14 +1327,10 @@ public: // to handle the typing of the struct BaseType *unify (BaseType *other) override final { - if (base->get_ref () == base->get_ty_ref ()) + if (!base->can_resolve ()) return BaseRules::unify (other); - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (base->get_ty_ref (), &lookup); - rust_assert (ok); - + auto lookup = base->resolve (); return lookup->unify (other); } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 1d197f5a845..156cc101c79 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -266,6 +266,23 @@ TyVar::get_implicit_infer_var (Location locus) return TyVar (infer->get_ref ()); } +TyVar +TyVar::subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst) +{ + if (orig->get_kind () != TyTy::TypeKind::PARAM) + return TyVar (subst->get_ty_ref ()); + else if (subst->get_kind () == TyTy::TypeKind::PARAM) + { + TyTy::ParamType *p = static_cast (subst); + if (p->resolve ()->get_kind () == TyTy::TypeKind::PARAM) + { + return TyVar (subst->get_ty_ref ()); + } + } + + return TyVar (subst->get_ref ()); +} + void InferType::accept_vis (TyVisitor &vis) { @@ -442,10 +459,15 @@ SubstitutionParamMapping::need_substitution () const } bool -SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus) +SubstitutionParamMapping::fill_param_ty ( + SubstitutionArgumentMappings &subst_mappings, Location locus) { - auto context = Resolver::TypeCheckContext::get (); + SubstitutionArg arg = SubstitutionArg::error (); + bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg); + if (!ok) + return true; + TyTy::BaseType &type = *arg.get_tyty (); if (type.get_kind () == TyTy::TypeKind::INFER) { type.inherit_bounds (*param); @@ -467,43 +489,9 @@ SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus) if (!param->bounds_compatible (type, locus, true)) return false; - // setup any associated type mappings for the specified bonds and this - // type - auto candidates = Resolver::TypeBoundsProbe::Probe (&type); - for (auto &specified_bound : param->get_specified_bounds ()) - { - const Resolver::TraitReference *specified_bound_ref - = specified_bound.get (); - - // since the bounds_compatible check has occurred we should be able to - // assert on finding the trait references - HirId associated_impl_block_id = UNKNOWN_HIRID; - bool found = false; - for (auto &bound : candidates) - { - const Resolver::TraitReference *bound_trait_ref = bound.first; - const HIR::ImplBlock *associated_impl = bound.second; - - found = specified_bound_ref->is_equal (*bound_trait_ref); - if (found) - { - rust_assert (associated_impl != nullptr); - associated_impl_block_id - = associated_impl->get_mappings ().get_hirid (); - break; - } - } - - if (found && associated_impl_block_id != UNKNOWN_HIRID) - { - Resolver::AssociatedImplTrait *lookup_associated = nullptr; - bool found_impl_trait = context->lookup_associated_trait_impl ( - associated_impl_block_id, &lookup_associated); - - if (found_impl_trait) - lookup_associated->setup_associated_types (); - } - } + // recursively pass this down to all HRTB's + for (auto &bound : param->get_specified_bounds ()) + bound.handle_substitions (subst_mappings); param->set_ty_ref (type.get_ref ()); } @@ -602,6 +590,7 @@ SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args) args.get_locus ()); resolved = Resolver::SubstMapperInternal::Resolve (resolved, intermediate); + if (resolved->get_kind () == TypeKind::ERROR) return SubstitutionArgumentMappings::error (); } @@ -773,6 +762,65 @@ SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref, return SubstitutionArgumentMappings (resolved_mappings, locus); } +bool +SubstitutionRef::monomorphize () +{ + auto context = Resolver::TypeCheckContext::get (); + for (const auto &subst : get_substs ()) + { + const TyTy::ParamType *pty = subst.get_param_ty (); + + if (!pty->can_resolve ()) + continue; + + const TyTy::BaseType *binding = pty->resolve (); + if (binding->get_kind () == TyTy::TypeKind::PARAM) + continue; + + for (const auto &bound : pty->get_specified_bounds ()) + { + const Resolver::TraitReference *specified_bound_ref = bound.get (); + + // setup any associated type mappings for the specified bonds and this + // type + auto candidates = Resolver::TypeBoundsProbe::Probe (binding); + + Resolver::AssociatedImplTrait *associated_impl_trait = nullptr; + for (auto &probed_bound : candidates) + { + const Resolver::TraitReference *bound_trait_ref + = probed_bound.first; + const HIR::ImplBlock *associated_impl = probed_bound.second; + + HirId impl_block_id + = associated_impl->get_mappings ().get_hirid (); + Resolver::AssociatedImplTrait *associated = nullptr; + bool found_impl_trait + = context->lookup_associated_trait_impl (impl_block_id, + &associated); + rust_assert (found_impl_trait); + + bool found_trait + = specified_bound_ref->is_equal (*bound_trait_ref); + bool found_self + = associated->get_self ()->can_eq (binding, false); + if (found_trait && found_self) + { + associated_impl_trait = associated; + break; + } + } + + if (associated_impl_trait != nullptr) + { + associated_impl_trait->setup_associated_types2 (binding, bound); + } + } + } + + return true; +} + void ADTType::accept_vis (TyVisitor &vis) { @@ -951,7 +999,7 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok) - sub.fill_param_ty (*arg.get_tyty (), subst_mappings.get_locus ()); + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); } for (auto &variant : adt->get_variants ()) @@ -1059,6 +1107,7 @@ TupleType::handle_substitions (SubstitutionArgumentMappings mappings) auto mappings_table = Analysis::Mappings::get (); TupleType *tuple = static_cast (clone ()); + tuple->set_ref (mappings_table->get_next_hir_id ()); tuple->set_ty_ref (mappings_table->get_next_hir_id ()); for (size_t i = 0; i < tuple->fields.size (); i++) @@ -1069,7 +1118,8 @@ TupleType::handle_substitions (SubstitutionArgumentMappings mappings) BaseType *concrete = Resolver::SubstMapperInternal::Resolve (field.get_tyty (), mappings); - tuple->fields[i] = TyVar (concrete->get_ty_ref ()); + tuple->fields[i] + = TyVar::subst_covariant_var (field.get_tyty (), concrete); } } @@ -1196,7 +1246,7 @@ FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok) { - sub.fill_param_ty (*arg.get_tyty (), subst_mappings.get_locus ()); + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); } } @@ -1538,7 +1588,7 @@ ArrayType::handle_substitions (SubstitutionArgumentMappings mappings) // might be &T or &ADT so this needs to be recursive auto base = ref->get_element_type (); BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); - ref->element_type = TyVar (concrete->get_ty_ref ()); + ref->element_type = TyVar::subst_covariant_var (base, concrete); return ref; } @@ -1627,7 +1677,7 @@ SliceType::handle_substitions (SubstitutionArgumentMappings mappings) // might be &T or &ADT so this needs to be recursive auto base = ref->get_element_type (); BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); - ref->element_type = TyVar (concrete->get_ty_ref ()); + ref->element_type = TyVar::subst_covariant_var (base, concrete); return ref; } @@ -2146,7 +2196,7 @@ ReferenceType::handle_substitions (SubstitutionArgumentMappings mappings) // might be &T or &ADT so this needs to be recursive auto base = ref->get_base (); BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); - ref->base = TyVar (concrete->get_ty_ref ()); + ref->base = TyVar::subst_covariant_var (base, concrete); return ref; } @@ -2232,7 +2282,7 @@ PointerType::handle_substitions (SubstitutionArgumentMappings mappings) // might be &T or &ADT so this needs to be recursive auto base = ref->get_base (); BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); - ref->base = TyVar (concrete->get_ty_ref ()); + ref->base = TyVar::subst_covariant_var (base, concrete); return ref; } @@ -2252,31 +2302,22 @@ ParamType::accept_vis (TyConstVisitor &vis) const std::string ParamType::as_string () const { - if (get_ref () == get_ty_ref ()) + if (!can_resolve ()) { return get_symbol () + " REF: " + std::to_string (get_ref ()); } - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (get_ty_ref (), &lookup); - rust_assert (ok); - + BaseType *lookup = resolve (); return get_symbol () + "=" + lookup->as_string (); } std::string ParamType::get_name () const { - if (get_ref () == get_ty_ref ()) + if (!can_resolve ()) return get_symbol (); - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (get_ty_ref (), &lookup); - rust_assert (ok); - - return lookup->get_name (); + return resolve ()->get_name (); } BaseType * @@ -2364,14 +2405,27 @@ ParamType::is_equal (const BaseType &other) const } ParamType * -ParamType::handle_substitions (SubstitutionArgumentMappings mappings) +ParamType::handle_substitions (SubstitutionArgumentMappings subst_mappings) { + SubstitutionArg arg = SubstitutionArg::error (); + bool ok = subst_mappings.get_argument_for_symbol (this, &arg); + if (!ok || arg.is_error ()) + return this; + ParamType *p = static_cast (clone ()); + subst_mappings.on_param_subst (*p, arg); - SubstitutionArg arg = SubstitutionArg::error (); - bool ok = mappings.get_argument_for_symbol (this, &arg); - if (ok && !arg.is_error ()) - p->set_ty_ref (arg.get_tyty ()->get_ref ()); + // there are two cases one where we substitute directly to a new PARAM and + // otherwise + if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) + { + p->set_ty_ref (arg.get_tyty ()->get_ref ()); + return p; + } + + // this is the new subst that this needs to pass + p->set_ref (mappings->get_next_hir_id ()); + p->set_ty_ref (arg.get_tyty ()->get_ref ()); return p; } @@ -2658,7 +2712,7 @@ ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings) bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok) - sub.fill_param_ty (*arg.get_tyty (), subst_mappings.get_locus ()); + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); } auto fty = projection->base; @@ -2935,17 +2989,7 @@ TypeCheckCallExpr::visit (FnType &type) return; } - if (type.get_return_type ()->get_kind () == TyTy::TypeKind::PLACEHOLDER) - { - const TyTy::PlaceholderType *p - = static_cast (type.get_return_type ()); - if (p->can_resolve ()) - { - resolved = p->resolve ()->clone (); - return; - } - } - + type.monomorphize (); resolved = type.get_return_type ()->clone (); } @@ -3050,6 +3094,7 @@ TypeCheckMethodCallExpr::visit (FnType &type) return; } + type.monomorphize (); resolved = type.get_return_type ()->clone (); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 6ddc05dba50..17ba6554c4a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -93,9 +93,7 @@ public: return parent == nullptr || trait_item_ref == nullptr; } - BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver, - const HIR::GenericArgs *bound_args - = nullptr); + BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); const Resolver::TraitItemReference *get_raw_item () const; @@ -293,6 +291,9 @@ public: static TyVar get_implicit_infer_var (Location locus); + static TyVar subst_covariant_var (TyTy::BaseType *orig, + TyTy::BaseType *subst); + private: HirId ref; }; @@ -431,10 +432,10 @@ public: bool is_concrete () const override final { - if (!can_resolve ()) + auto r = resolve (); + if (r == this) return false; - auto r = resolve (); return r->is_concrete (); } @@ -559,7 +560,8 @@ public: return param->get_name (); } - bool fill_param_ty (BaseType &type, Location locus); + bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings, + Location locus); SubstitutionParamMapping clone () const { @@ -567,6 +569,8 @@ public: param->clone ())); } + ParamType *get_param_ty () { return param; } + const ParamType *get_param_ty () const { return param; } const HIR::TypeParam &get_generic_param () { return generic; }; @@ -577,11 +581,7 @@ public: bool needs_substitution () const { - auto p = get_param_ty (); - if (!p->can_resolve ()) - return true; - - return p->resolve ()->get_kind () == TypeKind::PARAM; + return !(get_param_ty ()->is_concrete ()); } Location get_param_locus () const { return generic.get_locus (); } @@ -605,9 +605,12 @@ class SubstitutionArg { public: SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument) - : param (std::move (param)), argument (argument) + : param (param), argument (argument) {} + // FIXME + // the copy constructors need removed - they are unsafe see + // TypeBoundPredicate SubstitutionArg (const SubstitutionArg &other) : param (other.param), argument (other.argument) {} @@ -651,16 +654,20 @@ private: BaseType *argument; }; +typedef std::function + ParamSubstCb; class SubstitutionArgumentMappings { public: SubstitutionArgumentMappings (std::vector mappings, - Location locus) - : mappings (mappings), locus (locus) + Location locus, + ParamSubstCb param_subst_cb = nullptr) + : mappings (mappings), locus (locus), param_subst_cb (param_subst_cb) {} SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other) - : mappings (other.mappings), locus (other.locus) + : mappings (other.mappings), locus (other.locus), + param_subst_cb (other.param_subst_cb) {} SubstitutionArgumentMappings & @@ -668,12 +675,14 @@ public: { mappings = other.mappings; locus = other.locus; + param_subst_cb = other.param_subst_cb; + return *this; } static SubstitutionArgumentMappings error () { - return SubstitutionArgumentMappings ({}, Location ()); + return SubstitutionArgumentMappings ({}, Location (), nullptr); } bool is_error () const { return mappings.size () == 0; } @@ -737,9 +746,18 @@ public: return "<" + buffer + ">"; } + void on_param_subst (const ParamType &p, const SubstitutionArg &a) const + { + if (param_subst_cb == nullptr) + return; + + param_subst_cb (p, a); + } + private: std::vector mappings; Location locus; + ParamSubstCb param_subst_cb; }; class SubstitutionRef @@ -944,6 +962,10 @@ public: return handle_substitions (std::move (infer_arguments)); } + // TODO comment + bool monomorphize (); + + // TODO comment virtual BaseType *handle_substitions (SubstitutionArgumentMappings mappings) = 0; @@ -992,11 +1014,8 @@ public: TypeBoundPredicateItem lookup_associated_item (const std::string &search) const; - HIR::GenericArgs *get_generic_args () { return &args; } - - const HIR::GenericArgs *get_generic_args () const { return &args; } - - bool has_generic_args () const { return args.has_generic_args (); } + TypeBoundPredicateItem + lookup_associated_item (const Resolver::TraitItemReference *ref) const; // WARNING THIS WILL ALWAYS RETURN NULLPTR BaseType * @@ -1009,7 +1028,6 @@ public: private: DefId reference; Location locus; - HIR::GenericArgs args; bool error_flag; }; diff --git a/gcc/testsuite/rust/compile/torture/traits19.rs b/gcc/testsuite/rust/compile/torture/traits19.rs new file mode 100644 index 00000000000..4412656f535 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits19.rs @@ -0,0 +1,33 @@ +// { dg-additional-options "-w" } +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: isize, +} + +impl Get for Struct { + type Value = isize; + fn get(&self) -> &isize { + &self.x + } +} + +trait Grab { + type U; + fn grab(&self) -> &::U; +} + +impl Grab for T { + type U = ::Value; + fn grab(&self) -> &::Value { + self.get() + } +} + +fn main() { + let s = Struct { x: 100 }; + let a = s.grab(); +} diff --git a/gcc/testsuite/rust/execute/torture/slice-magic.rs b/gcc/testsuite/rust/execute/torture/slice-magic.rs new file mode 100644 index 00000000000..bac8a7803e6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/slice-magic.rs @@ -0,0 +1,106 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [A] { + pub const fn len(self) -> usize { + let a = unsafe { Repr { rust: self }.raw }; + a.len + } + + pub const fn as_ptr(self) -> *const A { + self as *const A + } +} + +#[lang = "const_ptr"] +impl *const B { + pub const unsafe fn offset(self, count: isize) -> *const B { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const B { + self as *const B + } +} + +const fn slice_from_raw_parts(data: *const C, len: usize) -> *const [C] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + unsafe fn get_unchecked(self, slice: *const X) -> *const Self::Output; + + fn index(self, slice: &X) -> &Self::Output; +} + +unsafe impl SliceIndex<[Y]> for Range { + type Output = [Y]; + + unsafe fn get_unchecked(self, slice: *const [Y]) -> *const [Y] { + unsafe { + let a: *const Y = slice.as_ptr(); + let b: *const Y = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[Y]) -> &[Y] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/slice-magic2.rs b/gcc/testsuite/rust/execute/torture/slice-magic2.rs new file mode 100644 index 00000000000..5a89f2ef3dd --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/slice-magic2.rs @@ -0,0 +1,106 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + let a = unsafe { Repr { rust: self }.raw }; + a.len + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + + 0 +}