From d3aecc1001e3a4cf1117de3456d2a30662493c78 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 19 Dec 2021 22:01:48 -0500 Subject: [PATCH] When obligation is a sized predicate, prefer projection or object candidates instead of param_env candidates --- compiler/rustc_infer/src/traits/util.rs | 2 +- compiler/rustc_middle/src/ty/print/mod.rs | 5 +++ compiler/rustc_middle/src/ty/print/pretty.rs | 9 +++--- .../src/traits/project.rs | 9 +++--- .../src/traits/select/candidate_assembly.rs | 16 ++++++---- .../src/traits/select/mod.rs | 23 +++++++------ compiler/rustc_typeck/src/astconv/mod.rs | 4 +-- compiler/rustc_typeck/src/check/method/mod.rs | 2 ++ src/test/ui/associated-types/substs-ppaux.rs | 2 +- .../substs-ppaux.verbose.stderr | 4 +-- .../generic-associated-types/issue-89352.rs | 32 +++++++++++++++++++ .../projection-no-regions-closure.stderr | 8 ++--- ...m-closure-outlives-from-return-type.stderr | 2 +- 13 files changed, 84 insertions(+), 34 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-89352.rs diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 61588147364..6bca27d7b0d 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -152,7 +152,7 @@ impl Elaborator<'tcx> { obligation.cause.clone(), ) }); - debug!("super_predicates: data={:?}", data); + debug!(?data, ?obligations, "super_predicates"); // Only keep those bounds that we haven't already seen. // This is necessary to prevent infinite recursion in some diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 308b4d2fefc..0366f6200ff 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -188,6 +188,11 @@ pub trait Printer<'tcx>: Sized { own_params.start = 1; } + // If we're in verbose mode, then print default-equal args too + if self.tcx().sess.verbose() { + return &substs[own_params]; + } + // Don't print args that are the defaults of their respective parameters. own_params.end -= generics .params diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 175295b3199..5ce2d977a35 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1776,10 +1776,11 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { self = print_prefix(self)?; // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); + let print_regions = self.tcx.sess.verbose() + || args.iter().any(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => *r != ty::ReErased, + _ => false, + }); let args = args.iter().cloned().filter(|arg| match arg.unpack() { GenericArgKind::Lifetime(_) => print_regions, _ => true, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b32fb616e12..d244ddc1c63 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1242,6 +1242,10 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( ); } +#[tracing::instrument( + level = "debug", + skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates) +)] fn assemble_candidates_from_predicates<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, @@ -1250,8 +1254,6 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( env_predicates: impl Iterator>, potentially_unnormalized_candidates: bool, ) { - debug!(?obligation, "assemble_candidates_from_predicates"); - let infcx = selcx.infcx(); for predicate in env_predicates { debug!(?predicate); @@ -1287,13 +1289,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( } } +#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))] fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { - debug!("assemble_candidates_from_impls"); - // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 017f47d4357..b573c4b4390 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -173,6 +173,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let needs_infer = stack.obligation.predicate.has_infer_types_or_consts(); + let sized_predicate = self.tcx().lang_items().sized_trait() + == Some(stack.obligation.predicate.skip_binder().def_id()); + // If there are STILL multiple candidates, we can further // reduce the list by dropping duplicates -- including // resolving specializations. @@ -181,6 +184,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { while i < candidates.len() { let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { self.candidate_should_be_dropped_in_favor_of( + sized_predicate, &candidates[i], &candidates[j], needs_infer, @@ -338,13 +342,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(candidates) } + #[tracing::instrument(level = "debug", skip(self, candidates))] fn assemble_candidates_from_projected_tys( &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - debug!(?obligation, "assemble_candidates_from_projected_tys"); - // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { @@ -369,12 +372,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// supplied to find out whether it is listed among them. /// /// Never affects the inference environment. + #[tracing::instrument(level = "debug", skip(self, stack, candidates))] fn assemble_candidates_from_caller_bounds<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - debug!(?stack.obligation, "assemble_candidates_from_caller_bounds"); + debug!(?stack.obligation); let all_bounds = stack .obligation @@ -876,6 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, @@ -883,7 +888,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // Okay to skip binder here because the tests we do below do not involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - debug!(?self_ty, "assemble_candidates_for_trait_alias"); + debug!(?self_ty); let def_id = obligation.predicate.def_id(); @@ -894,6 +899,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Assembles the trait which are built-in to the language itself: /// `Copy`, `Clone` and `Sized`. + #[tracing::instrument(level = "debug", skip(self, candidates))] fn assemble_builtin_bound_candidates( &mut self, conditions: BuiltinImplConditions<'tcx>, @@ -901,14 +907,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { match conditions { BuiltinImplConditions::Where(nested) => { - debug!(?nested, "builtin_bound"); candidates .vec .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); } BuiltinImplConditions::None => {} BuiltinImplConditions::Ambiguous => { - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); candidates.ambiguous = true; } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 607deb8f908..492a8f8bffd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -200,6 +200,7 @@ struct EvaluatedCandidate<'tcx> { } /// When does the builtin impl for `T: Trait` apply? +#[derive(Debug)] enum BuiltinImplConditions<'tcx> { /// The impl is conditional on `T1, T2, ...: Trait`. Where(ty::Binder<'tcx, Vec>>), @@ -343,7 +344,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } Err(e) => Err(e), Ok(candidate) => { - debug!(?candidate); + debug!(?candidate, "confirmed"); Ok(Some(candidate)) } } @@ -1476,6 +1477,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// See the comment for "SelectionCandidate" for more details. fn candidate_should_be_dropped_in_favor_of( &mut self, + sized_predicate: bool, victim: &EvaluatedCandidate<'tcx>, other: &EvaluatedCandidate<'tcx>, needs_infer: bool, @@ -1547,6 +1549,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Drop otherwise equivalent non-const fn pointer candidates (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + // If obligation is a sized predicate or the where-clause bound is + // global, prefer the projection or object candidate. See issue + // #50825 and #89352. + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { + sized_predicate || is_global(cand) + } + (ParamCandidate(ref cand), ObjectCandidate(_) | ProjectionCandidate(_)) => { + !(sized_predicate || is_global(cand)) + } + // Global bounds from the where clause should be ignored // here (see issue #50825). Otherwise, we have a where // clause so don't go around looking for impls. @@ -1562,15 +1574,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { .. } - | TraitAliasCandidate(..) - | ObjectCandidate(_) - | ProjectionCandidate(_), + | TraitAliasCandidate(..), ) => !is_global(cand), - (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - is_global(cand) - } ( ImplCandidate(_) | ClosureCandidate diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 23c3b5af262..abcd79526eb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -286,7 +286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Given the type/lifetime/const arguments provided to some path (along with /// an implicit `Self`, if this is a trait reference), returns the complete /// set of substitutions. This may involve applying defaulted type parameters. - /// Also returns back constraints on associated types. + /// Constraints on associated typess are created from `create_assoc_bindings_for_generic_args`. /// /// Example: /// @@ -300,7 +300,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// which will have been resolved to a `def_id` /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type /// parameters are returned in the `SubstsRef`, the associated type bindings like - /// `Output = u32` are returned in the `Vec` result. + /// `Output = u32` are returned from `create_assoc_bindings_for_generic_args`. /// /// Note that the type listing given here is *exactly* what the user provided. /// diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 03518dc8d12..ea75a1ed80d 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -360,6 +360,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (obligation, substs) = self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); + debug!(?obligation); + // Now we want to know if this can be matched if !self.predicate_may_hold(&obligation) { debug!("--> Cannot match obligation"); diff --git a/src/test/ui/associated-types/substs-ppaux.rs b/src/test/ui/associated-types/substs-ppaux.rs index 66cd94d7a1b..974a1d961a0 100644 --- a/src/test/ui/associated-types/substs-ppaux.rs +++ b/src/test/ui/associated-types/substs-ppaux.rs @@ -25,7 +25,7 @@ fn foo<'z>() where &'z (): Sized { let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types //[verbose]~| expected unit type `()` - //[verbose]~| found fn item `fn() {>::bar::}` + //[verbose]~| found fn item `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types //[normal]~| expected unit type `()` //[normal]~| found fn item `fn() {>::bar::<'static, char>}` diff --git a/src/test/ui/associated-types/substs-ppaux.verbose.stderr b/src/test/ui/associated-types/substs-ppaux.verbose.stderr index b831f3b7a76..cf480223da2 100644 --- a/src/test/ui/associated-types/substs-ppaux.verbose.stderr +++ b/src/test/ui/associated-types/substs-ppaux.verbose.stderr @@ -20,7 +20,7 @@ error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:25:17 | LL | fn bar<'a, T>() where T: 'a {} - | --------------------------- fn() {>::bar::} defined here + | --------------------------- fn() {>::bar::} defined here ... LL | let x: () = >::bar::<'static, char>; | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item @@ -28,7 +28,7 @@ LL | let x: () = >::bar::<'static, char>; | expected due to this | = note: expected unit type `()` - found fn item `fn() {>::bar::}` + found fn item `fn() {>::bar::}` help: use parentheses to call this function | LL | let x: () = >::bar::<'static, char>(); diff --git a/src/test/ui/generic-associated-types/issue-89352.rs b/src/test/ui/generic-associated-types/issue-89352.rs new file mode 100644 index 00000000000..d9c656d5f58 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-89352.rs @@ -0,0 +1,32 @@ +// check-pass + +#![feature(generic_associated_types)] + +use std::marker::PhantomData; + +pub trait GenAssoc { + type Iter<'at>; + fn iter(&self) -> Self::Iter<'_>; + fn reborrow<'longt: 'shortt, 'shortt>(iter: Self::Iter<'longt>) -> Self::Iter<'shortt>; +} + +pub struct Wrapper<'a, T: 'a, A: GenAssoc> { + a: A::Iter<'a>, + _p: PhantomData, +} + +impl<'ai, T: 'ai, A: GenAssoc> GenAssoc for Wrapper<'ai, T, A> +where + A::Iter<'ai>: Clone, +{ + type Iter<'b> = (); + fn iter<'s>(&'s self) -> Self::Iter<'s> { + let a = A::reborrow::<'ai, 's>(self.a.clone()); + } + + fn reborrow<'long: 'short, 'short>(iter: Self::Iter<'long>) -> Self::Iter<'short> { + () + } +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 983d6a06afa..459198eec5a 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -6,7 +6,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>, (), ] = note: number of external vids: 3 @@ -42,7 +42,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>, (), ] = note: number of external vids: 3 @@ -69,7 +69,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>, (), ] = note: number of external vids: 4 @@ -105,7 +105,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>, (), ] = note: number of external vids: 4 diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 88d73e7a729..6e8b3021d33 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -6,7 +6,7 @@ LL | with_signature(x, |y| y) | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r), std::alloc::Global>, (), ] = note: number of external vids: 3