From 34e5a4992c920ce9e68c333621f3d4c967c012c4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Jul 2020 19:10:22 +0100 Subject: [PATCH] Normalize projection bounds when considering candidates This unfortunately requires some winnowing hacks to avoid now ambiguous candidates. --- .../src/traits/project.rs | 58 ++- .../src/traits/select/confirmation.rs | 33 +- .../src/traits/select/mod.rs | 336 +++++++++++------- .../bad-bounds-on-assoc-in-trait.rs | 40 ++- .../bad-bounds-on-assoc-in-trait.stderr | 8 +- .../associate-type-bound-normalization.rs | 25 ++ src/test/ui/closures/issue-41366.rs | 1 + src/test/ui/closures/issue-41366.stderr | 22 +- src/test/ui/issues/issue-24204.rs | 14 +- src/test/ui/issues/issue-24204.stderr | 15 - src/test/ui/issues/issue-58344.rs | 24 +- src/test/ui/issues/issue-58344.stderr | 25 -- src/test/ui/issues/issue-60283.rs | 1 + src/test/ui/issues/issue-60283.stderr | 22 +- .../missing-assoc-type-bound-restriction.rs | 4 +- ...issing-assoc-type-bound-restriction.stderr | 18 - 16 files changed, 390 insertions(+), 256 deletions(-) create mode 100644 src/test/ui/associated-types/associate-type-bound-normalization.rs delete mode 100644 src/test/ui/issues/issue-24204.stderr delete mode 100644 src/test/ui/issues/issue-58344.stderr delete mode 100644 src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index f23d3bb7611..d52e5419100 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -884,6 +884,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( candidate_set, ProjectionTyCandidate::ParamEnv, obligation.param_env.caller_bounds().iter(), + false, ); } @@ -927,6 +928,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( candidate_set, ProjectionTyCandidate::TraitDef, bounds.iter(), + true, ) } @@ -937,6 +939,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, env_predicates: impl Iterator>, + potentially_unnormalized_candidates: bool, ) { debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); let infcx = selcx.infcx(); @@ -948,16 +951,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let is_match = same_def_id && infcx.probe(|_| { - let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() + selcx.match_projection_projections( + obligation, + obligation_trait_ref, + &data, + potentially_unnormalized_candidates, + ) }); debug!( @@ -1157,9 +1156,12 @@ fn confirm_candidate<'cx, 'tcx>( debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); let mut progress = match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) - | ProjectionTyCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection) + ProjectionTyCandidate::ParamEnv(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection, false) + } + + ProjectionTyCandidate::TraitDef(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection, true) } ProjectionTyCandidate::Select(impl_source) => { @@ -1272,7 +1274,7 @@ fn confirm_object_candidate<'cx, 'tcx>( } }; - confirm_param_env_candidate(selcx, obligation, env_predicate) + confirm_param_env_candidate(selcx, obligation, env_predicate, false) } fn confirm_generator_candidate<'cx, 'tcx>( @@ -1323,7 +1325,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( } }); - confirm_param_env_candidate(selcx, obligation, predicate) + confirm_param_env_candidate(selcx, obligation, predicate, false) .with_addl_obligations(impl_source.nested) .with_addl_obligations(obligations) } @@ -1345,7 +1347,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( ty: self_ty.discriminant_ty(tcx), }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate)) + confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( @@ -1420,13 +1422,14 @@ fn confirm_callable_candidate<'cx, 'tcx>( ty: ret_type, }); - confirm_param_env_candidate(selcx, obligation, predicate) + confirm_param_env_candidate(selcx, obligation, predicate, false) } fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, + potentially_unnormalized_candidate: bool, ) -> Progress<'tcx> { let infcx = selcx.infcx(); let cause = &obligation.cause; @@ -1440,8 +1443,27 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); + let mut nested_obligations = Vec::new(); + let cache_trait_ref = if potentially_unnormalized_candidate { + ensure_sufficient_stack(|| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &cache_trait_ref, + &mut nested_obligations, + ) + }) + } else { + cache_trait_ref + }; + match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { - Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations }, + Ok(InferOk { value: _, obligations }) => { + nested_obligations.extend(obligations); + Progress { ty: cache_entry.ty, obligations: nested_obligations } + } Err(e) => { let msg = format!( "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d0b4bec1b1a..e6fce78f269 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -137,18 +137,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate = candidate_predicate .to_opt_poly_trait_ref() .expect("projection candidate is not a trait predicate"); - let mut obligations = self - .infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), candidate) - .map(|InferOk { obligations, .. }| obligations) - .unwrap_or_else(|_| { - bug!( - "Projection bound `{:?}` was applicable to `{:?}` but now is not", - candidate, - obligation - ); - }); + let Normalized { value: candidate, mut obligations } = normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &candidate, + ); + + obligations.extend( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation.predicate.to_poly_trait_ref(), candidate) + .map(|InferOk { obligations, .. }| obligations) + .unwrap_or_else(|_| { + bug!( + "Projection bound `{:?}` was applicable to `{:?}` but now is not", + candidate, + obligation + ); + }), + ); // Require that the projection is well-formed. let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty); let self_ty = normalize_with_depth_to( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e1dd3f215ca..147b0c74d16 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,6 +9,7 @@ use super::coherence::{self, Conflict}; use super::const_evaluatable; use super::project; use super::project::normalize_with_depth_to; +use super::project::ProjectionTyObligation; use super::util; use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::wf; @@ -36,9 +37,8 @@ use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::{ - self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; @@ -946,10 +946,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// to have a *lower* recursion_depth than the obligation used to create it. /// Projection sub-obligations may be returned from the projection cache, /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `wf::obligations` and - /// `InferCtxt.subtype_predicate` produce subobligations without - /// taking in a 'parent' depth, causing the generated subobligations - /// to have a `recursion_depth` of `0`. + /// Additionally, methods like `InferCtxt.subtype_predicate` produce + /// subobligations without taking in a 'parent' depth, causing the + /// generated subobligations to have a `recursion_depth` of `0`. /// /// To ensure that obligation_depth never decreasees, we force all subobligations /// to have at least the depth of the original obligation. @@ -1229,10 +1228,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_trait_ref: ty::TraitRef<'tcx>, ) -> Result>, ()> { debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); + if placeholder_trait_ref.def_id != trait_bound.def_id() { + // Avoid unnecessary normalization + return Err(()); + } + + let Normalized { value: trait_bound, obligations: mut nested_obligations } = + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_bound, + ) + }); self.infcx .at(&obligation.cause, obligation.param_env) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) - .map(|InferOk { obligations, .. }| obligations) + .map(|InferOk { obligations, .. }| { + nested_obligations.extend(obligations); + nested_obligations + }) .map_err(|_| ()) } @@ -1249,6 +1266,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + pub(super) fn match_projection_projections( + &mut self, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + data: &PolyProjectionPredicate<'tcx>, + potentially_unnormalized_candidates: bool, + ) -> bool { + let mut nested_obligations = Vec::new(); + let projection_ty = if potentially_unnormalized_candidates { + ensure_sufficient_stack(|| { + project::normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &data.map_bound_ref(|data| data.projection_ty), + &mut nested_obligations, + ) + }) + } else { + data.map_bound_ref(|data| data.projection_ty) + }; + + // FIXME(generic_associated_types): Compare the whole projections + let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx())); + let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .map_or(false, |InferOk { obligations, value: () }| { + self.evaluate_predicates_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + nested_obligations.into_iter().chain(obligations), + ) + .map_or(false, |res| res.may_apply()) + }) + } + /////////////////////////////////////////////////////////////////////////// // WINNOW // @@ -1283,18 +1338,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. - match other.candidate { + match (&other.candidate, &victim.candidate) { + (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + // (*) - BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true, - ParamCandidate(ref cand) => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // (*) - BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false, + (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true, + (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false, + + (ParamCandidate(..), ParamCandidate(..)) => false, + + // 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. + // Arbitrarily give param candidates priority + // over projection and object candidates. + ( + ParamCandidate(ref cand), ImplCandidate(..) | ClosureCandidate | GeneratorCandidate @@ -1302,28 +1366,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinObjectCandidate | BuiltinUnsizeCandidate | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => { - // 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. - !is_global(cand) - } - ObjectCandidate | ProjectionCandidate(_) => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - !is_global(cand) - } - ParamCandidate(..) => false, - }, - ObjectCandidate | ProjectionCandidate(_) => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // (*) - BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false, + | TraitAliasCandidate(..) + | ObjectCandidate + | ProjectionCandidate(_), + ) => !is_global(cand), + (ObjectCandidate | ProjectionCandidate(_), ParamCandidate(ref cand)) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) + } + ( + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ParamCandidate(ref cand), + ) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) && other.evaluation.must_apply_modulo_regions() + } + + (ProjectionCandidate(i), ProjectionCandidate(j)) => { + // Arbitrarily pick the first candidate for backwards + // compatibility reasons. Don't let this affect inference. + i > j && !needs_infer + } + (ObjectCandidate, ObjectCandidate) => bug!("Duplicate object candidate"), + (ObjectCandidate, ProjectionCandidate(_)) + | (ProjectionCandidate(_), ObjectCandidate) => { + bug!("Have both object and projection candidate") + } + + // Arbitrarily give projection and object candidates priority. + ( + ObjectCandidate | ProjectionCandidate(_), ImplCandidate(..) | ClosureCandidate | GeneratorCandidate @@ -1331,99 +1412,100 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinObjectCandidate | BuiltinUnsizeCandidate | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => true, - ObjectCandidate | ProjectionCandidate(_) => { - // Shouldn't have both an object and projection candidate, - // nor multiple object candidates. Multiple projection - // candidates are ambiguous. - false - } - ParamCandidate(ref cand) => is_global(cand), - }, - ImplCandidate(other_def) => { + | TraitAliasCandidate(..), + ) => true, + + ( + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { .. } + | TraitAliasCandidate(..), + ObjectCandidate | ProjectionCandidate(_), + ) => false, + + (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { // See if we can toss out `victim` based on specialization. // This requires us to know *for sure* that the `other` impl applies // i.e., `EvaluatedToOk`. if other.evaluation.must_apply_modulo_regions() { - match victim.candidate { - ImplCandidate(victim_def) => { - let tcx = self.tcx(); - if tcx.specializes((other_def, victim_def)) { - return true; - } - return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { - Some(ty::ImplOverlapKind::Permitted { marker: true }) => { - // Subtle: If the predicate we are evaluating has inference - // variables, do *not* allow discarding candidates due to - // marker trait impls. - // - // Without this restriction, we could end up accidentally - // constrainting inference variables based on an arbitrarily - // chosen trait impl. - // - // Imagine we have the following code: - // - // ```rust - // #[marker] trait MyTrait {} - // impl MyTrait for u8 {} - // impl MyTrait for bool {} - // ``` - // - // And we are evaluating the predicate `<_#0t as MyTrait>`. - // - // During selection, we will end up with one candidate for each - // impl of `MyTrait`. If we were to discard one impl in favor - // of the other, we would be left with one candidate, causing - // us to "successfully" select the predicate, unifying - // _#0t with (for example) `u8`. - // - // However, we have no reason to believe that this unification - // is correct - we've essentially just picked an arbitrary - // *possibility* for _#0t, and required that this be the *only* - // possibility. - // - // Eventually, we will either: - // 1) Unify all inference variables in the predicate through - // some other means (e.g. type-checking of a function). We will - // then be in a position to drop marker trait candidates - // without constraining inference variables (since there are - // none left to constrin) - // 2) Be left with some unconstrained inference variables. We - // will then correctly report an inference error, since the - // existence of multiple marker trait impls tells us nothing - // about which one should actually apply. - !needs_infer - } - Some(_) => true, - None => false, - }; - } - ParamCandidate(ref cand) => { - // Prefer the impl to a global where clause candidate. - return is_global(cand); - } - _ => (), + let tcx = self.tcx(); + if tcx.specializes((other_def, victim_def)) { + return true; } + return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { + Some(ty::ImplOverlapKind::Permitted { marker: true }) => { + // Subtle: If the predicate we are evaluating has inference + // variables, do *not* allow discarding candidates due to + // marker trait impls. + // + // Without this restriction, we could end up accidentally + // constrainting inference variables based on an arbitrarily + // chosen trait impl. + // + // Imagine we have the following code: + // + // ```rust + // #[marker] trait MyTrait {} + // impl MyTrait for u8 {} + // impl MyTrait for bool {} + // ``` + // + // And we are evaluating the predicate `<_#0t as MyTrait>`. + // + // During selection, we will end up with one candidate for each + // impl of `MyTrait`. If we were to discard one impl in favor + // of the other, we would be left with one candidate, causing + // us to "successfully" select the predicate, unifying + // _#0t with (for example) `u8`. + // + // However, we have no reason to believe that this unification + // is correct - we've essentially just picked an arbitrary + // *possibility* for _#0t, and required that this be the *only* + // possibility. + // + // Eventually, we will either: + // 1) Unify all inference variables in the predicate through + // some other means (e.g. type-checking of a function). We will + // then be in a position to drop marker trait candidates + // without constraining inference variables (since there are + // none left to constrin) + // 2) Be left with some unconstrained inference variables. We + // will then correctly report an inference error, since the + // existence of multiple marker trait impls tells us nothing + // about which one should actually apply. + !needs_infer + } + Some(_) => true, + None => false, + }; + } else { + false } + } - false - } - ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { has_nested: true } => { - match victim.candidate { - ParamCandidate(ref cand) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() - } - _ => false, - } - } - _ => false, + // Everything else is ambiguous + ( + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ) => false, } } diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index 4c78f17a6a3..8093c4b9d9e 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -6,26 +6,25 @@ use std::fmt::Debug; use std::iter::Once; -trait Lam { type App; } +trait Lam { + type App; +} #[derive(Clone)] struct L1; -impl<'a> Lam<&'a u8> for L1 { type App = u8; } +impl<'a> Lam<&'a u8> for L1 { + type App = u8; +} #[derive(Clone)] struct L2; -impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; } +impl<'a, 'b> Lam<&'a &'b u8> for L2 { + type App = u8; +} trait Case1 { - type C: Clone + Iterator Lam<&'a u8, App: - Debug - > - > + Sync>; - //~^^^^^^ ERROR `<::C as std::iter::Iterator>::Item` is not an iterator - //~^^^^^^ ERROR `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely - //~^^^ ERROR `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely + type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; + //~^ ERROR overflow evaluating the requirement `<::C as std::iter::Iterator>::Item` } pub struct S1; @@ -34,10 +33,20 @@ impl Case1 for S1 { } fn assume_case1() { - fn assert_a<_0, A>() where A: Iterator, _0: Debug {} + fn assert_a<_0, A>() + where + A: Iterator, + _0: Debug, + { + } assert_a::<_, T::A>(); - fn assert_b<_0, B>() where B: Iterator, _0: 'static {} + fn assert_b<_0, B>() + where + B: Iterator, + _0: 'static, + { + } assert_b::<_, T::B>(); fn assert_c<_0, _1, _2, C>() @@ -46,7 +55,8 @@ fn assume_case1() { _2: Send + Iterator, _1: for<'a> Lam<&'a u8, App = _0>, _0: Debug, - {} + { + } assert_c::<_, _, _, T::C>(); } diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index 20a087a85a6..abaae7e5343 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -1,5 +1,5 @@ -error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:5 +error[E0275]: overflow evaluating the requirement `<::C as std::iter::Iterator>::Item` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:28:5 | LL | / type C: Clone + Iterator::C as std::iter::Iterator>::Item: std::marker::Sync { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/associate-type-bound-normalization.rs b/src/test/ui/associated-types/associate-type-bound-normalization.rs new file mode 100644 index 00000000000..db092970f79 --- /dev/null +++ b/src/test/ui/associated-types/associate-type-bound-normalization.rs @@ -0,0 +1,25 @@ +// Make sure that we normalize bounds on associated types before checking them +// as candidates. + +// check-pass + +trait Mul { + type Output; +} + +trait Matrix: Mul<::Row, Output = ()> { + type Row; + + type Transpose: Matrix; +} + +fn is_mul>() {} + +fn f() { + // The unnormalized bound on `T::Transpose` is + // `Mul<::Row` which has to be normalized to be + // equal to `T::Row`. + is_mul::(); +} + +fn main() {} diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs index af1e37ba867..909c33f642d 100644 --- a/src/test/ui/closures/issue-41366.rs +++ b/src/test/ui/closures/issue-41366.rs @@ -9,4 +9,5 @@ impl<'g> T<'g> for u32 { fn main() { (&|_| ()) as &dyn for<'x> Fn(>::V); //~^ ERROR: type mismatch in closure arguments + //~| ERROR: size for values of type `>::V` cannot be known at compilation time } diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr index df0495cdc46..97c33c0708e 100644 --- a/src/test/ui/closures/issue-41366.stderr +++ b/src/test/ui/closures/issue-41366.stderr @@ -9,6 +9,24 @@ LL | (&|_| ()) as &dyn for<'x> Fn(>::V); | = note: required for the cast to the object type `dyn for<'x> Fn(>::V)` -error: aborting due to previous error +error[E0277]: the size for values of type `>::V` cannot be known at compilation time + --> $DIR/issue-41366.rs:10:8 + | +LL | (&|_| ()) as &dyn for<'x> Fn(>::V); + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `>::V` + = help: unsized locals are gated as an unstable feature +help: consider further restricting the associated type + | +LL | fn main() where >::V: std::marker::Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | (&|&_| ()) as &dyn for<'x> Fn(>::V); + | ^ -For more information about this error, try `rustc --explain E0631`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0631. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-24204.rs b/src/test/ui/issues/issue-24204.rs index df72283de23..5a7b3459589 100644 --- a/src/test/ui/issues/issue-24204.rs +++ b/src/test/ui/issues/issue-24204.rs @@ -1,3 +1,5 @@ +// check-pass + #![allow(dead_code)] trait MultiDispatch { @@ -8,10 +10,16 @@ trait Trait: Sized { type A: MultiDispatch; type B; - fn new(u: U) -> >::O where Self::A : MultiDispatch; + fn new(u: U) -> >::O + where + Self::A: MultiDispatch; } -fn test>(b: i32) -> T where T::A: MultiDispatch { T::new(b) } -//~^ ERROR mismatched types +fn test>(b: i32) -> T +where + T::A: MultiDispatch, +{ + T::new(b) +} fn main() {} diff --git a/src/test/ui/issues/issue-24204.stderr b/src/test/ui/issues/issue-24204.stderr deleted file mode 100644 index 9d66c9ff0a8..00000000000 --- a/src/test/ui/issues/issue-24204.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-24204.rs:14:72 - | -LL | fn test>(b: i32) -> T where T::A: MultiDispatch { T::new(b) } - | - - ^^^^^^^^^ expected type parameter `T`, found associated type - | | | - | this type parameter expected `T` because of return type - | - = note: expected type parameter `T` - found associated type `<::A as MultiDispatch>::O` - = note: you might be missing a type parameter or trait bound - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs index 9b184e296aa..0cb04dcb22a 100644 --- a/src/test/ui/issues/issue-58344.rs +++ b/src/test/ui/issues/issue-58344.rs @@ -1,3 +1,5 @@ +// check-pass + use std::ops::Add; trait Trait { @@ -18,7 +20,11 @@ enum Either { } impl Either { - fn converge(self) -> T where L: Trait, R: Trait { + fn converge(self) -> T + where + L: Trait, + R: Trait, + { match self { Either::Left(val) => val.get(), Either::Right(val) => val.get(), @@ -26,22 +32,16 @@ impl Either { } } -fn add_generic, B>(lhs: A, rhs: B) -> Either< - impl Trait<>::Output>, - impl Trait<>::Output> -> { - if true { - Either::Left(Holder(lhs + rhs)) - } else { - Either::Right(Holder(lhs + rhs)) - } +fn add_generic, B>( + lhs: A, + rhs: B, +) -> Either>::Output>, impl Trait<>::Output>> { + if true { Either::Left(Holder(lhs + rhs)) } else { Either::Right(Holder(lhs + rhs)) } } fn add_one( value: u32, ) -> Either>::Output>, impl Trait<>::Output>> { - //~^ ERROR: the trait bound `impl Trait<::Output>: Trait` - //~| ERROR: the trait bound `impl Trait<::Output>: Trait` add_generic(value, 1u32) } diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr deleted file mode 100644 index ade85d8b016..00000000000 --- a/src/test/ui/issues/issue-58344.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied - --> $DIR/issue-58344.rs:42:13 - | -LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` -... -LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` - | - = note: the return type of a function must have a statically known size - -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied - --> $DIR/issue-58344.rs:42:52 - | -LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` -... -LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` - | - = note: the return type of a function must have a statically known size - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs index 9c2b2dc9f4d..9f4813071a1 100644 --- a/src/test/ui/issues/issue-60283.rs +++ b/src/test/ui/issues/issue-60283.rs @@ -16,4 +16,5 @@ where fn main() { foo((), drop) //~^ ERROR type mismatch in function arguments + //~| ERROR the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time } diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr index ad679bfa220..2922eb87e82 100644 --- a/src/test/ui/issues/issue-60283.stderr +++ b/src/test/ui/issues/issue-60283.stderr @@ -13,6 +13,24 @@ LL | foo((), drop) | expected signature of `fn(<() as Trait<'a>>::Item) -> _` | found signature of `fn(()) -> _` -error: aborting due to previous error +error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time + --> $DIR/issue-60283.rs:17:13 + | +LL | foo((), drop) + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/libcore/mem/mod.rs:LL:COL + | +LL | pub fn drop(_x: T) {} + | - required by this bound in `std::mem::drop` + | + = help: the trait `std::marker::Sized` is not implemented for `<() as Trait<'_>>::Item` +help: consider further restricting the associated type + | +LL | fn main() where <() as Trait<'_>>::Item: std::marker::Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For more information about this error, try `rustc --explain E0631`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0631. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs index 8218fecc3f1..4954a8a6965 100644 --- a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs +++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs @@ -1,5 +1,4 @@ -// Running rustfix would cause the same suggestion to be applied multiple times, which results in -// invalid code. +// check-pass trait Parent { type Ty; @@ -17,7 +16,6 @@ struct ParentWrapper(T); impl> Parent for ParentWrapper { type Ty = A; type Assoc = ChildWrapper; - //~^ ERROR the trait bound `::Assoc: Child` is not satisfied } fn main() {} diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr deleted file mode 100644 index 676e2fb1a51..00000000000 --- a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `::Assoc: Child` is not satisfied - --> $DIR/missing-assoc-type-bound-restriction.rs:19:5 - | -LL | type Assoc: Child; - | --------------- required by this bound in `Parent::Assoc` -... -LL | type Assoc = ChildWrapper; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child` is not implemented for `::Assoc` - | - = note: required because of the requirements on the impl of `Child` for `ChildWrapper<::Assoc>` -help: consider further restricting the associated type - | -LL | impl> Parent for ParentWrapper where ::Assoc: Child { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`.