From 5f0fe8f093555c9f435dcb8ec0dfa6552ef0e492 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 17:20:10 -0400 Subject: [PATCH 01/30] remove `commit_if_ok` wrapper --- src/librustc/traits/select.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index bd347764cc681..1832d35e3ae45 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -549,15 +549,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.probe(|snapshot| f(self, snapshot)) } - /// Wraps a commit_if_ok s.t. obligations collected during it are not returned in selection if - /// the transaction fails and s.t. old obligations are retained. - fn commit_if_ok(&mut self, f: F) -> Result - where - F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> Result, - { - self.infcx.commit_if_ok(|snapshot| f(self, snapshot)) - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -3041,7 +3032,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // reported an ambiguity. (When we do find a match, also // record it for later.) let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while( - |&t| match self.commit_if_ok(|this, _| this.match_poly_trait_ref(obligation, t)) { + |&t| match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { Ok(obligations) => { upcast_trait_ref = Some(t); nested.extend(obligations); From 79efed84a006620c6e4596088074f7ff195580fe Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 17:28:37 -0400 Subject: [PATCH 02/30] remove wrapper functions that had no purpose --- src/librustc/traits/select.rs | 93 ++++++++++++++--------------------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 1832d35e3ae45..e7c01df3dca0a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -29,8 +29,7 @@ use super::{ use dep_graph::{DepKind, DepNodeIndex}; use hir::def_id::DefId; -use infer; -use infer::{InferCtxt, InferOk, TypeFreshener}; +use infer::{self, InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; use mir::interpret::GlobalId; use ty::fast_reject; @@ -531,24 +530,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx } - /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection - /// context's self. - fn in_snapshot(&mut self, f: F) -> R - where - F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R, - { - self.infcx.in_snapshot(|snapshot| f(self, snapshot)) - } - - /// Wraps a probe s.t. obligations collected during it are ignored and old obligations are - /// retained. - fn probe(&mut self, f: F) -> R - where - F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R, - { - self.infcx.probe(|snapshot| f(self, snapshot)) - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -630,8 +611,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, obligation: &PredicateObligation<'tcx>, ) -> Result { - self.probe(|this, _| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + self.infcx.probe(|_| { + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) }) } @@ -1066,10 +1047,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { "evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate ); - let result = self.probe(|this, _| { + let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => this.evaluate_predicates_recursively( + match self.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => self.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().iter(), ), @@ -1697,8 +1678,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ => return, } - let result = self.probe(|this, snapshot| { - this.match_projection_obligation_against_definition_bounds(obligation, snapshot) + let result = self.infcx.probe(|snapshot| { + self.match_projection_obligation_against_definition_bounds(obligation, snapshot) }); if result { @@ -1750,8 +1731,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates) .filter_to_traits() .find(|bound| { - self.probe(|this, _| { - this.match_projection( + self.infcx.probe(|_| { + self.match_projection( obligation, bound.clone(), skol_trait_predicate.trait_ref.clone(), @@ -1853,10 +1834,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.probe(move |this, _| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.infcx.probe(|_| { + match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.iter()) + self.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => Ok(EvaluatedToErr), } @@ -2006,8 +1987,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { - if let Ok(placeholder_map) = this.match_impl(impl_def_id, obligation, snapshot) + self.infcx.probe(|snapshot| { + if let Ok(placeholder_map) = self.match_impl(impl_def_id, obligation, snapshot) { candidates.vec.push(ImplCandidate(impl_def_id)); @@ -2084,11 +2065,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.self_ty().skip_binder() ); - self.probe(|this, _snapshot| { + self.infcx.probe(|_snapshot| { // The code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase // any LBR. - let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty()); + let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); let poly_trait_ref = match self_ty.sty { ty::Dynamic(ref data, ..) => { if data.auto_traits() @@ -2102,7 +2083,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return; } - data.principal().with_self_ty(this.tcx(), self_ty) + data.principal().with_self_ty(self.tcx(), self_ty) } ty::Infer(ty::TyVar(_)) => { debug!("assemble_candidates_from_object_ty: ambiguous"); @@ -2122,11 +2103,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // correct trait, but also the correct type parameters. // For example, we may be trying to upcast `Foo` to `Bar`, // but `Foo` is declared as `trait Foo : Bar`. - let upcast_trait_refs = util::supertraits(this.tcx(), poly_trait_ref) + let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) .filter(|upcast_trait_ref| { - this.probe(|this, _| { + self.infcx.probe(|_| { let upcast_trait_ref = upcast_trait_ref.clone(); - this.match_poly_trait_ref(obligation, upcast_trait_ref) + self.match_poly_trait_ref(obligation, upcast_trait_ref) .is_ok() }) }) @@ -2671,20 +2652,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // binder moved -\ let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ - self.in_snapshot(|this, snapshot| { - let (skol_ty, placeholder_map) = this.infcx() + self.infcx.in_snapshot(|snapshot| { + let (skol_ty, placeholder_map) = self.infcx .replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, mut obligations, } = project::normalize_with_depth( - this, + self, param_env, cause.clone(), recursion_depth, &skol_ty, ); - let skol_obligation = this.tcx().predicate_for_trait_def( + let skol_obligation = self.tcx().predicate_for_trait_def( param_env, cause.clone(), trait_def_id, @@ -2693,7 +2674,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &[], ); obligations.push(skol_obligation); - this.infcx() + self.infcx .plug_leaks(placeholder_map, snapshot, obligations) }) }) @@ -2785,9 +2766,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.in_snapshot(|this, snapshot| { + self.infcx.in_snapshot(|snapshot| { let result = - this.match_projection_obligation_against_definition_bounds(obligation, snapshot); + self.match_projection_obligation_against_definition_bounds(obligation, snapshot); assert!(result); }) } @@ -2904,12 +2885,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested, ); - let trait_obligations: Vec> = self.in_snapshot(|this, snapshot| { + let trait_obligations: Vec> = self.infcx.in_snapshot(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, placeholder_map) = this.infcx() + let (trait_ref, placeholder_map) = self.infcx .replace_bound_vars_with_placeholders(&poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); - this.impl_or_trait_obligations( + self.impl_or_trait_obligations( cause, obligation.recursion_depth + 1, obligation.param_env, @@ -2941,11 +2922,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.in_snapshot(|this, snapshot| { - let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot); + self.infcx.in_snapshot(|snapshot| { + let (substs, placeholder_map) = self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - this.vtable_impl( + self.vtable_impl( impl_def_id, substs, cause, @@ -3108,14 +3089,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, alias_def_id ); - self.in_snapshot(|this, snapshot| { - let (predicate, placeholder_map) = this.infcx() + self.infcx.in_snapshot(|snapshot| { + let (predicate, placeholder_map) = self.infcx .replace_bound_vars_with_placeholders(&obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; - let trait_obligations = this.impl_or_trait_obligations( + let trait_obligations = self.impl_or_trait_obligations( obligation.cause.clone(), obligation.recursion_depth, obligation.param_env, From 4b5f274f90d3eb925bad9a1bfa6fe58209f6a6c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Sep 2018 13:56:11 -0400 Subject: [PATCH 03/30] make evaluation track whether outlives relationships mattered Previously, evaluation ignored outlives relationships. Since we using evaluation to skip the "normal" trait selection (which enforces outlives relationships) this led to incorrect results in some cases. --- src/librustc/infer/mod.rs | 2 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/mod.rs | 22 ++-- src/librustc/traits/object_safety.rs | 2 +- .../traits/query/evaluate_obligation.rs | 19 ++- src/librustc/traits/select.rs | 123 +++++------------- src/librustc/ty/util.rs | 36 ++--- src/librustc_typeck/check/cast.rs | 8 +- src/test/ui/hrtb/hrtb-cache-issue-54302.rs | 24 ++++ .../ui/hrtb/hrtb-cache-issue-54302.stderr | 17 +++ 10 files changed, 129 insertions(+), 126 deletions(-) create mode 100644 src/test/ui/hrtb/hrtb-cache-issue-54302.rs create mode 100644 src/test/ui/hrtb/hrtb-cache-issue-54302.stderr diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index c000e3aa013f8..2eb9f1d678433 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1455,7 +1455,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span) + !traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) } /// Obtains the latest type of the given closure; this may be a diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 556b97dc9bcf1..219e971b3c927 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -282,7 +282,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx().predicate_must_hold(&obligation) { + if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) { debug!("selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth); return ProcessResult::Changed(vec![]) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 49bd04782b28e..0377b98d3f863 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -628,14 +628,14 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, /// `bound` or is not known to meet bound (note that this is /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). -pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - span: Span) --> bool -{ - debug!("type_known_to_meet_bound(ty={:?}, bound={:?})", +pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + span: Span, +) -> bool { + debug!("type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", ty, infcx.tcx.item_path_str(def_id)); @@ -650,7 +650,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx predicate: trait_ref.to_predicate(), }; - let result = infcx.predicate_must_hold(&obligation); + let result = infcx.predicate_must_hold_modulo_regions(&obligation); debug!("type_known_to_meet_ty={:?} bound={} => {:?}", ty, infcx.tcx.item_path_str(def_id), result); @@ -677,13 +677,13 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx // assume it is move; linear is always ok. match fulfill_cx.select_all_or_error(infcx) { Ok(()) => { - debug!("type_known_to_meet_bound: ty={:?} bound={} success", + debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", ty, infcx.tcx.item_path_str(def_id)); true } Err(e) => { - debug!("type_known_to_meet_bound: ty={:?} bound={} errors={:?}", + debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", ty, infcx.tcx.item_path_str(def_id), e); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1554afdeefdaf..31342c250e2bd 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -568,7 +568,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self.infer_ctxt().enter(|ref infcx| { // the receiver is dispatchable iff the obligation holds - infcx.predicate_must_hold(&obligation) + infcx.predicate_must_hold_modulo_regions(&obligation) }) } diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index 4c1d65c46c56f..fdae7d833734e 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -16,11 +16,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// Evaluates whether the predicate can be satisfied in the given /// `ParamEnv`, and returns `false` if not certain. However, this is /// not entirely accurate if inference variables are involved. - pub fn predicate_must_hold( + /// + /// This version may conservatively fail when outlives obligations + /// are required. + pub fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'tcx>, ) -> bool { - self.evaluate_obligation_no_overflow(obligation) == EvaluationResult::EvaluatedToOk + self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + /// + /// This version ignores all outlives constraints. + pub fn predicate_must_hold_modulo_regions( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() } /// Evaluate a given predicate, capturing overflow and propagating it back. diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e7c01df3dca0a..6b4c3469acd5b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -327,7 +327,8 @@ enum BuiltinImplConditions<'tcx> { /// evaluations. /// /// The evaluation results are ordered: -/// - `EvaluatedToOk` implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` +/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` +/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` /// - `EvaluatedToErr` implies `EvaluatedToRecur` /// - the "union" of evaluation results is equal to their maximum - /// all the "potential success" candidates can potentially succeed, @@ -336,6 +337,8 @@ enum BuiltinImplConditions<'tcx> { pub enum EvaluationResult { /// Evaluation successful EvaluatedToOk, + /// Evaluation successful, but there were unevaluated region obligations + EvaluatedToOkModuloRegions, /// Evaluation is known to be ambiguous - it *might* hold for some /// assignment of inference variables, but it might not. /// @@ -399,9 +402,23 @@ pub enum EvaluationResult { } impl EvaluationResult { + /// True if this evaluation result is known to apply, even + /// considering outlives constraints. + pub fn must_apply_considering_regions(self) -> bool { + self == EvaluatedToOk + } + + /// True if this evaluation result is known to apply, ignoring + /// outlives constraints. + pub fn must_apply_modulo_regions(self) -> bool { + self <= EvaluatedToOkModuloRegions + } + pub fn may_apply(self) -> bool { match self { - EvaluatedToOk | EvaluatedToAmbig | EvaluatedToUnknown => true, + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { + true + } EvaluatedToErr | EvaluatedToRecur => false, } @@ -411,13 +428,14 @@ impl EvaluationResult { match self { EvaluatedToUnknown | EvaluatedToRecur => true, - EvaluatedToOk | EvaluatedToAmbig | EvaluatedToErr => false, + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, } } } impl_stable_hash_for!(enum self::EvaluationResult { EvaluatedToOk, + EvaluatedToOkModuloRegions, EvaluatedToAmbig, EvaluatedToUnknown, EvaluatedToRecur, @@ -686,92 +704,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { None => Ok(EvaluatedToAmbig), }, - ty::Predicate::TypeOutlives(ref binder) => { - assert!(!binder.has_escaping_bound_vars()); - // Check if the type has higher-ranked vars. - if binder.skip_binder().0.has_escaping_bound_vars() { - // If so, this obligation is an error (for now). Eventually we should be - // able to support additional cases here, like `for<'a> &'a str: 'a`. - - // NOTE: this hack is implemented in both trait fulfillment and - // evaluation. If you fix it in one place, make sure you fix it - // in the other. - - // We don't want to allow this sort of reasoning in intercrate - // mode, for backwards-compatibility reasons. - if self.intercrate.is_some() { - Ok(EvaluatedToAmbig) - } else { - Ok(EvaluatedToErr) - } - } else { - // If the type has no late bound vars, then if we assign all - // the inference variables in it to be 'static, then the type - // will be 'static itself. - // - // Therefore, `staticize(T): 'a` holds for any `'a`, so this - // obligation is fulfilled. Because evaluation works with - // staticized types (yes I know this is involved with #21974), - // we are 100% OK here. - Ok(EvaluatedToOk) - } - } - - ty::Predicate::RegionOutlives(ref binder) => { - let ty::OutlivesPredicate(r_a, r_b) = binder.skip_binder(); - - if r_a == r_b { - // for<'a> 'a: 'a. OK - Ok(EvaluatedToOk) - } else if **r_a == ty::ReStatic { - // 'static: 'x always holds. - // - // This special case is handled somewhat inconsistently - if we - // have an inference variable that is supposed to be equal to - // `'static`, then we don't allow it to be equated to an LBR, - // but if we have a literal `'static`, then we *do*. - // - // This is actually consistent with how our region inference works. - // - // It would appear that this sort of inconsistency would - // cause "instability" problems with evaluation caching. However, - // evaluation caching is only for trait predicates, and when - // trait predicates create nested obligations, they contain - // inference variables for all the regions in the trait - the - // only way this codepath can be reached from trait predicate - // evaluation is when the user typed an explicit `where 'static: 'a` - // lifetime bound (in which case we want to return EvaluatedToOk). - // - // If we ever want to handle inference variables that might be - // equatable with ReStatic, we need to make sure we are not confused by - // technically-allowed-by-RFC-447-but-probably-should-not-be - // impls such as - // ```Rust - // impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's - // ``` - Ok(EvaluatedToOk) - } else if r_a.is_late_bound() || r_b.is_late_bound() { - // There is no current way to prove `for<'a> 'a: 'x` - // unless `'a = 'x`, because there are no bounds involving - // lifetimes. - - // It might be possible to prove `for<'a> 'x: 'a` by forcing `'x` - // to be `'static`. However, this is not currently done by type - // inference unless `'x` is literally ReStatic. See the comment - // above. - - // We don't want to allow this sort of reasoning in intercrate - // mode, for backwards-compatibility reasons. - if self.intercrate.is_some() { - Ok(EvaluatedToAmbig) - } else { - Ok(EvaluatedToErr) - } - } else { - // Relating 2 inference variable regions. These will - // always hold if our query is "staticized". - Ok(EvaluatedToOk) - } + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + // we do not consider region relationships when + // evaluating trait matches + Ok(EvaluatedToOkModuloRegions) } ty::Predicate::ObjectSafe(trait_def_id) => { @@ -985,6 +921,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); + // Subtle: when checking for a coinductive cycle, we do + // not compare using the "freshened trait refs" (which + // have erased regions) but rather the fully explicit + // trait refs. This is important because it's only a cycle + // if the regions match exactly. let cycle = stack.iter().skip(1).take(rec_index + 1); let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); if self.coinductive_match(cycle) { @@ -2324,7 +2265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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 == EvaluatedToOk { + if other.evaluation.must_apply_modulo_regions() { match victim.candidate { ImplCandidate(victim_def) => { let tcx = self.tcx().global_tcx(); @@ -2351,7 +2292,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ParamCandidate(ref cand) => { // Prefer these to a global where-clause bound // (see issue #50825) - is_global(cand) && other.evaluation == EvaluatedToOk + is_global(cand) && other.evaluation.must_apply_modulo_regions() } _ => false, } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1d30ccb87b5d8..0fa4c98be6370 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -851,11 +851,13 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP)) + .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( + &infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP, + )) } fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -865,11 +867,13 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP)) + .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( + &infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP, + )) } fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -879,11 +883,13 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP)) + .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( + &infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP, + )) } fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 6ad707e3d2c78..9d418704f487d 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return Err(ErrorReported); } - if self.type_is_known_to_be_sized(t, span) { + if self.type_is_known_to_be_sized_modulo_regions(t, span) { return Ok(Some(PointerKind::Thin)); } @@ -397,7 +397,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { self.expr_ty, self.cast_ty); - if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) { + if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) { self.report_cast_to_unsized_type(fcx); } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages @@ -618,8 +618,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool { + fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem); - traits::type_known_to_meet_bound(self, self.param_env, ty, lang_item, span) + traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) } } diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.rs b/src/test/ui/hrtb/hrtb-cache-issue-54302.rs new file mode 100644 index 0000000000000..a20d03c7747cd --- /dev/null +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.rs @@ -0,0 +1,24 @@ +// Regression test for #54302. +// +// We were incorrectly using the "evaluation cache" (which ignored +// region results) to conclude that `&'static str: Deserialize`, even +// though it would require that `for<'de> 'de: 'static`, which is +// clearly false. + +trait Deserialize<'de> {} + +trait DeserializeOwned: for<'de> Deserialize<'de> {} +impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} + +// Based on this impl, `&'static str` only implements Deserialize<'static>. +// It does not implement for<'de> Deserialize<'de>. +impl<'de: 'a, 'a> Deserialize<'de> for &'a str {} + +fn main() { + fn assert_deserialize_owned() {} + assert_deserialize_owned::<&'static str>(); //~ ERROR + + // It correctly does not implement for<'de> Deserialize<'de>. + // fn assert_hrtb Deserialize<'de>>() {} + // assert_hrtb::<&'static str>(); +} diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr new file mode 100644 index 0000000000000..061d0e309c500 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -0,0 +1,17 @@ +error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) + --> $DIR/hrtb-cache-issue-54302.rs:19:5 + | +LL | assert_deserialize_owned::<&'static str>(); //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str` + = note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str` +note: required by `main::assert_deserialize_owned` + --> $DIR/hrtb-cache-issue-54302.rs:18:5 + | +LL | fn assert_deserialize_owned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0279`. From 4170829e536f5b284c4c66f291acfb0da23bb526 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Oct 2018 05:42:18 -0400 Subject: [PATCH 04/30] introduce ability to detect region constraints from snapshot --- src/librustc/infer/mod.rs | 9 ++++++ src/librustc/infer/region_constraints/mod.rs | 9 ++++++ src/librustc/traits/select.rs | 30 ++++++++++++++------ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2eb9f1d678433..9a5e707b57d89 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -868,6 +868,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r } + pub fn region_constraints_added_in_snapshot( + &self, + snapshot: &CombinedSnapshot<'a, 'tcx>, + ) -> bool { + self.borrow_region_constraints().region_constraints_added_in_snapshot( + &snapshot.region_constraints_snapshot, + ) + } + pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { self.borrow_region_constraints().add_given(sub, sup); } diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 66ebbe111dbce..89086e66dffbf 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -854,6 +854,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> { debug!("tainted: result={:?}", taint_set); return taint_set.into_set(); } + + pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> bool { + self.undo_log[mark.length..] + .iter() + .any(|&elt| match elt { + AddConstraint(_) => true, + _ => false, + }) + } } impl fmt::Debug for RegionSnapshot { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6b4c3469acd5b..6ba3e54eaca51 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -629,8 +629,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, obligation: &PredicateObligation<'tcx>, ) -> Result { - self.infcx.probe(|_| { - self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + self.evaluation_probe(|this| { + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + }) + } + + fn evaluation_probe( + &mut self, + op: impl FnOnce(&mut Self) -> Result, + ) -> Result { + self.infcx.probe(|snapshot| -> Result { + let result = op(self)?; + if !self.infcx.region_constraints_added_in_snapshot(snapshot) { + Ok(result) + } else { + Ok(result.max(EvaluatedToOkModuloRegions)) + } }) } @@ -988,10 +1002,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { "evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate ); - let result = self.infcx.probe(|_| { + let result = self.evaluation_probe(|this| { let candidate = (*candidate).clone(); - match self.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => self.evaluate_predicates_recursively( + match this.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().iter(), ), @@ -1775,10 +1789,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.infcx.probe(|_| { - match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.evaluation_probe(|this| { + match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - self.evaluate_predicates_recursively(stack.list(), obligations.iter()) + this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => Ok(EvaluatedToErr), } From 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Dec 2018 10:22:55 -0500 Subject: [PATCH 05/30] select.rs: unsizing coercion should use a subtype When we coerce `dyn Foo` to `dyn Bar`, that is OK as long as `Foo` is usable in all contexts where `Bar` is usable (hence using the source must be a subtype of the target). This is needed for the universe-based code to handle `old-lub-glb-object`; that test used to work sort of by accident before with the old code. --- src/librustc/traits/select.rs | 4 ++-- src/test/ui/lub-glb/old-lub-glb-object.rs | 2 +- src/test/ui/lub-glb/old-lub-glb-object.stderr | 14 ++++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6ba3e54eaca51..2576578f4c294 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -3268,10 +3268,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ); tcx.mk_existential_predicates(iter) }); - let new_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b); let InferOk { obligations, .. } = self.infcx .at(&obligation.cause, obligation.param_env) - .eq(target, new_trait) + .sup(target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs index 309f2d0ea7663..132df608af71a 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.rs +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -7,7 +7,7 @@ fn foo( x: &for<'a, 'b> Foo<&'a u8, &'b u8>, y: &for<'a> Foo<&'a u8, &'a u8>, ) { - let z = match 22 { //~ ERROR incompatible types + let z = match 22 { //~ ERROR cannot infer 0 => x, _ => y, }; diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 243414c19c01e..3a7478b73b85a 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,17 +1,19 @@ error[E0308]: match arms have incompatible types --> $DIR/old-lub-glb-object.rs:10:13 | -LL | let z = match 22 { //~ ERROR incompatible types +LL | let z = match 22 { //~ ERROR cannot infer | _____________^ LL | | 0 => x, LL | | _ => y, - | | - match arm with an incompatible type LL | | }; - | |_____^ expected bound lifetime parameter 'a, found concrete lifetime + | |_____^ | - = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>` - found type `&dyn for<'a> Foo<&'a u8, &'a u8>` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U5, name: BrNamed(crate0:DefIndex(1:11), 'a) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U5, name: BrNamed(crate0:DefIndex(1:12), 'b) })... + = note: ...so that the types are compatible: + expected dyn for<'a, 'b> Foo<&'a u8, &'b u8> + found dyn for<'a> Foo<&'a u8, &'a u8> error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0495`. From eba2ae526b2624c76bdb9fea41f88d2c1740c722 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Dec 2018 10:23:02 -0500 Subject: [PATCH 06/30] WIP: wfcheck ability to detect --- src/librustc_typeck/check/wfcheck.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 65539d3b10709..53e44d53e6a9b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -873,7 +873,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( trait_ref.to_predicate() ); - if !fcx.predicate_must_hold(&obligation) { + if !fcx.predicate_must_hold_modulo_regions(&obligation) { debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait", receiver_ty); return false From b68fad670bb3612cac26e50751e4fd9150e59977 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Sep 2018 20:11:23 -0400 Subject: [PATCH 07/30] universe transition Remove the leak-check and its associated machinery. Replace with making the solver aware of universes. --- src/librustc/infer/higher_ranked/mod.rs | 507 ++---------------- .../infer/lexical_region_resolve/mod.rs | 41 +- src/librustc/infer/mod.rs | 86 +-- src/librustc/infer/region_constraints/mod.rs | 31 -- .../infer/region_constraints/taint.rs | 85 --- src/librustc/traits/auto_trait.rs | 8 +- src/librustc/traits/error_reporting.rs | 9 +- src/librustc/traits/fulfill.rs | 6 +- src/librustc/traits/project.rs | 48 +- src/librustc/traits/select.rs | 122 ++--- 10 files changed, 144 insertions(+), 799 deletions(-) delete mode 100644 src/librustc/infer/region_constraints/taint.rs diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 3a3a21d0f1d4a..709e8c0ba9b24 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -1,31 +1,23 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{CombinedSnapshot, - InferCtxt, - HigherRankedType, - SubregionOrigin, - PlaceholderMap}; use super::combine::CombineFields; -use super::region_constraints::{TaintDirections}; +use super::{HigherRankedType, InferCtxt, PlaceholderMap}; -use ty::{self, TyCtxt, Binder, TypeFoldable}; -use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; -use syntax_pos::Span; -use util::nodemap::{FxHashMap, FxHashSet}; - -pub struct HrMatchResult { - pub value: U, -} +use ty::{self, Binder, TypeFoldable}; impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) - -> RelateResult<'tcx, Binder> - where T: Relate<'tcx> + pub fn higher_ranked_sub( + &mut self, + a: &Binder, + b: &Binder, + a_is_expected: bool, + ) -> RelateResult<'tcx, Binder> + where + T: Relate<'tcx>, { - debug!("higher_ranked_sub(a={:?}, b={:?})", - a, b); + debug!("higher_ranked_sub(a={:?}, b={:?})", a, b); // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure @@ -35,279 +27,37 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // please see the large comment at the end of the file in the (inlined) module // `doc`. - // Start a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - let span = self.trace.cause.span; - - // First, we instantiate each bound region in the supertype with a - // fresh placeholder region. - let (b_prime, placeholder_map) = - self.infcx.replace_bound_vars_with_placeholders(b); - - // Next, we instantiate each bound region in the subtype - // with a fresh region variable. These region variables -- - // but no other pre-existing region variables -- can name - // the placeholders. - let (a_prime, _) = self.infcx.replace_bound_vars_with_fresh_vars( - span, - HigherRankedType, - a - ); - - debug!("a_prime={:?}", a_prime); - debug!("b_prime={:?}", b_prime); - - // Compare types now that bound regions have been replaced. - let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - - // Presuming type comparison succeeds, we need to check - // that the placeholder regions do not "leak". - self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?; - - // We are finished with the placeholder regions now so pop - // them off. - self.infcx.pop_placeholders(placeholder_map, snapshot); - - debug!("higher_ranked_sub: OK result={:?}", result); - - Ok(ty::Binder::bind(result)) - }); - } - - /// The value consists of a pair `(t, u)` where `t` is the - /// *matcher* and `u` is a *value*. The idea is to find a - /// substitution `S` such that `S(t) == b`, and then return - /// `S(u)`. In other words, find values for the late-bound regions - /// in `a` that can make `t == b` and then replace the LBR in `u` - /// with those values. - /// - /// This routine is (as of this writing) used in trait matching, - /// particularly projection. - /// - /// NB. It should not happen that there are LBR appearing in `U` - /// that do not appear in `T`. If that happens, those regions are - /// unconstrained, and this routine replaces them with `'static`. - pub fn higher_ranked_match(&mut self, - a_pair: &Binder<(T, U)>, - b_match: &T, - a_is_expected: bool) - -> RelateResult<'tcx, HrMatchResult> - where T: Relate<'tcx>, - U: TypeFoldable<'tcx> - { - debug!("higher_ranked_match(a={:?}, b={:?})", - a_pair, b_match); - - // Start a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - // First, we instantiate each bound region in the matcher - // with a placeholder region. - let ((a_match, a_value), placeholder_map) = - self.infcx.replace_bound_vars_with_placeholders(a_pair); + let span = self.trace.cause.span; - debug!("higher_ranked_match: a_match={:?}", a_match); - debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map); + // First, we instantiate each bound region in the supertype with a + // fresh placeholder region. + let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b); - // Equate types now that bound regions have been replaced. - self.equate(a_is_expected).relate(&a_match, &b_match)?; + // Next, we instantiate each bound region in the subtype + // with a fresh region variable. These region variables -- + // but no other pre-existing region variables -- can name + // the placeholders. + let (a_prime, _) = + self.infcx + .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a); - // Map each placeholder region to a vector of other regions that it - // must be equated with. (Note that this vector may include other - // placeholder regions from `placeholder_map`.) - let placeholder_resolution_map: FxHashMap<_, _> = - placeholder_map - .iter() - .map(|(&br, &placeholder)| { - let tainted_regions = - self.infcx.tainted_regions(snapshot, - placeholder, - TaintDirections::incoming()); // [1] + debug!("a_prime={:?}", a_prime); + debug!("b_prime={:?}", b_prime); - // [1] this routine executes after the placeholder - // regions have been *equated* with something - // else, so examining the incoming edges ought to - // be enough to collect all constraints + // Compare types now that bound regions have been replaced. + let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - (placeholder, (br, tainted_regions)) - }) - .collect(); + debug!("higher_ranked_sub: OK result={:?}", result); - // For each placeholder region, pick a representative -- which can - // be any region from the sets above, except for other members of - // `placeholder_map`. There should always be a representative if things - // are properly well-formed. - let placeholder_representatives: FxHashMap<_, _> = - placeholder_resolution_map - .iter() - .map(|(&placeholder, &(_, ref regions))| { - let representative = - regions.iter() - .filter(|&&r| !placeholder_resolution_map.contains_key(r)) - .cloned() - .next() - .unwrap_or_else(|| { - bug!("no representative region for `{:?}` in `{:?}`", - placeholder, regions) - }); - - (placeholder, representative) - }) - .collect(); - - // Equate all the members of each placeholder set with the - // representative. - for (placeholder, &(_br, ref regions)) in &placeholder_resolution_map { - let representative = &placeholder_representatives[placeholder]; - debug!("higher_ranked_match: \ - placeholder={:?} representative={:?} regions={:?}", - placeholder, representative, regions); - for region in regions.iter() - .filter(|&r| !placeholder_resolution_map.contains_key(r)) - .filter(|&r| r != representative) - { - let origin = SubregionOrigin::Subtype(self.trace.clone()); - self.infcx.borrow_region_constraints() - .make_eqregion(origin, - *representative, - *region); - } - } - - // Replace the placeholder regions appearing in value with - // their representatives - let a_value = - fold_regions_in( - self.tcx(), - &a_value, - |r, _| placeholder_representatives.get(&r).cloned().unwrap_or(r)); - - debug!("higher_ranked_match: value={:?}", a_value); - - // We are now done with these placeholder variables. - self.infcx.pop_placeholders(placeholder_map, snapshot); - - Ok(HrMatchResult { value: a_value }) - }); + Ok(ty::Binder::bind(result)) } } -fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - unbound_value: &T, - mut fldr: F) - -> T - where T: TypeFoldable<'tcx>, - F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, -{ - tcx.fold_regions(unbound_value, &mut false, |region, current_depth| { - // we should only be encountering "escaping" late-bound regions here, - // because the ones at the current level should have been replaced - // with fresh variables - assert!(match *region { - ty::ReLateBound(..) => false, - _ => true - }); - - fldr(region, current_depth) - }) -} - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn tainted_regions(&self, - snapshot: &CombinedSnapshot<'a, 'tcx>, - r: ty::Region<'tcx>, - directions: TaintDirections) - -> FxHashSet> { - self.borrow_region_constraints().tainted( - self.tcx, - &snapshot.region_constraints_snapshot, - r, - directions) - } - - fn region_vars_confined_to_snapshot(&self, - snapshot: &CombinedSnapshot<'a, 'tcx>) - -> Vec - { - /*! - * Returns the set of region variables that do not affect any - * types/regions which existed before `snapshot` was - * started. This is used in the sub/lub/glb computations. The - * idea here is that when we are computing lub/glb of two - * regions, we sometimes create intermediate region variables. - * Those region variables may touch some of the placeholder or - * other "forbidden" regions we created to replace bound - * regions, but they don't really represent an "external" - * constraint. - * - * However, sometimes fresh variables are created for other - * purposes too, and those *may* represent an external - * constraint. In particular, when a type variable is - * instantiated, we create region variables for all the - * regions that appear within, and if that type variable - * pre-existed the snapshot, then those region variables - * represent external constraints. - * - * An example appears in the unit test - * `sub_free_bound_false_infer`. In this test, we want to - * know whether - * - * ```rust - * fn(_#0t) <: for<'a> fn(&'a int) - * ``` - * - * Note that the subtype has a type variable. Because the type - * variable can't be instantiated with a region that is bound - * in the fn signature, this comparison ought to fail. But if - * we're not careful, it will succeed. - * - * The reason is that when we walk through the subtyping - * algorithm, we begin by replacing `'a` with a placeholder - * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This - * can be made true by unifying `_#0t` with `&'1 int`. In the - * process, we create a fresh variable for the placeholder - * region, `'$2`, and hence we have that `_#0t == &'$2 - * int`. However, because `'$2` was created during the sub - * computation, if we're not careful we will erroneously - * assume it is one of the transient region variables - * representing a lub/glb internally. Not good. - * - * To prevent this, we check for type variables which were - * unified during the snapshot, and say that any region - * variable created during the snapshot but which finds its - * way into a type variable is considered to "escape" the - * snapshot. - */ - - let mut region_vars = - self.borrow_region_constraints().vars_created_since_snapshot( - &snapshot.region_constraints_snapshot); - - let escaping_types = - self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot); - - let mut escaping_region_vars = FxHashSet::default(); - for ty in &escaping_types { - self.tcx.collect_regions(ty, &mut escaping_region_vars); - } - - region_vars.retain(|®ion_vid| { - let r = ty::ReVar(region_vid); - !escaping_region_vars.contains(&r) - }); - - debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}", - region_vars, - escaping_types); - - region_vars - } - /// Replace all regions (resp. types) bound by `binder` with placeholder /// regions (resp. types) and return a map indicating which bound-region - /// was replaced with what placeholder region. This is the first step of - /// checking subtyping when higher-ranked things are involved. + /// placeholder region. This is the first step of checking subtyping + /// when higher-ranked things are involved. /// /// **Important:** you must call this function from within a snapshot. /// Moreover, before committing the snapshot, you must eventually call @@ -354,201 +104,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { (result, map) } - - /// Searches the region constraints created since `snapshot` was started - /// and checks to determine whether any of the placeholder regions created - /// in `placeholder_map` would "escape" -- meaning that they are related to - /// other regions in some way. If so, the higher-ranked subtyping doesn't - /// hold. See `README.md` for more details. - pub fn leak_check(&self, - overly_polymorphic: bool, - _span: Span, - placeholder_map: &PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'a, 'tcx>) - -> RelateResult<'tcx, ()> - { - debug!("leak_check: placeholder_map={:?}", - placeholder_map); - - // If the user gave `-Zno-leak-check`, then skip the leak - // check completely. This is wildly unsound and also not - // unlikely to cause an ICE or two. It is intended for use - // only during a transition period, in which the MIR typeck - // uses the "universe-style" check, and the rest of typeck - // uses the more conservative leak check. Since the leak - // check is more conservative, we can't test the - // universe-style check without disabling it. - if self.tcx.sess.opts.debugging_opts.no_leak_check { - return Ok(()); - } - - let new_vars = self.region_vars_confined_to_snapshot(snapshot); - for (&placeholder_br, &placeholder) in placeholder_map { - // The inputs to a placeholder variable can only - // be itself or other new variables. - let incoming_taints = self.tainted_regions(snapshot, - placeholder, - TaintDirections::both()); - for &tainted_region in &incoming_taints { - // Each placeholder should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReVar(vid) => { - if new_vars.contains(&vid) { - continue; - } - } - _ => { - if tainted_region == placeholder { continue; } - } - }; - - debug!("{:?} (which replaced {:?}) is tainted by {:?}", - placeholder, - placeholder_br, - tainted_region); - - return Err(if overly_polymorphic { - debug!("Overly polymorphic!"); - TypeError::RegionsOverlyPolymorphic(placeholder_br, tainted_region) - } else { - debug!("Not as polymorphic!"); - TypeError::RegionsInsufficientlyPolymorphic(placeholder_br, tainted_region) - }) - } - } - - Ok(()) - } - - /// This code converts from placeholder regions back to late-bound - /// regions. It works by replacing each region in the taint set of a - /// placeholder region with a bound-region. The bound region will be bound - /// by the outer-most binder in `value`; the caller must ensure that there is - /// such a binder and it is the right place. - /// - /// This routine is only intended to be used when the leak-check has - /// passed; currently, it's used in the trait matching code to create - /// a set of nested obligations from an impl that matches against - /// something higher-ranked. More details can be found in - /// `librustc/middle/traits/README.md`. - /// - /// As a brief example, consider the obligation `for<'a> Fn(&'a int) - /// -> &'a int`, and the impl: - /// - /// impl Fn for SomethingOrOther - /// where A : Clone - /// { ... } - /// - /// Here we will have replaced `'a` with a placeholder region - /// `'0`. This means that our substitution will be `{A=>&'0 - /// int, R=>&'0 int}`. - /// - /// When we apply the substitution to the bounds, we will wind up with - /// `&'0 int : Clone` as a predicate. As a last step, we then go and - /// replace `'0` with a late-bound region `'a`. The depth is matched - /// to the depth of the predicate, in this case 1, so that the final - /// predicate is `for<'a> &'a int : Clone`. - pub fn plug_leaks(&self, - placeholder_map: PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'a, 'tcx>, - value: T) -> T - where T : TypeFoldable<'tcx> - { - debug!("plug_leaks(placeholder_map={:?}, value={:?})", - placeholder_map, - value); - - if placeholder_map.is_empty() { - return value; - } - - // Compute a mapping from the "taint set" of each placeholder - // region back to the `ty::BoundRegion` that it originally - // represented. Because `leak_check` passed, we know that - // these taint sets are mutually disjoint. - let inv_placeholder_map: FxHashMap, ty::BoundRegion> = - placeholder_map - .iter() - .flat_map(|(&placeholder_br, &placeholder)| { - self.tainted_regions(snapshot, placeholder, TaintDirections::both()) - .into_iter() - .map(move |tainted_region| (tainted_region, placeholder_br)) - }) - .collect(); - - debug!("plug_leaks: inv_placeholder_map={:?}", - inv_placeholder_map); - - // Remove any instantiated type variables from `value`; those can hide - // references to regions from the `fold_regions` code below. - let value = self.resolve_type_vars_if_possible(&value); - - // Map any placeholder byproducts back to a late-bound - // region. Put that late-bound region at whatever the outermost - // binder is that we encountered in `value`. The caller is - // responsible for ensuring that (a) `value` contains at least one - // binder and (b) that binder is the one we want to use. - let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| { - match inv_placeholder_map.get(&r) { - None => r, - Some(br) => { - // It is the responsibility of the caller to ensure - // that each placeholder region appears within a - // binder. In practice, this routine is only used by - // trait checking, and all of the placeholder regions - // appear inside predicates, which always have - // binders, so this assert is satisfied. - assert!(current_depth > ty::INNERMOST); - - // since leak-check passed, this placeholder region - // should only have incoming edges from variables - // (which ought not to escape the snapshot, but we - // don't check that) or itself - assert!( - match *r { - ty::ReVar(_) => true, - ty::RePlaceholder(index) => index.name == *br, - _ => false, - }, - "leak-check would have us replace {:?} with {:?}", - r, br); - - self.tcx.mk_region(ty::ReLateBound( - current_depth.shifted_out(1), - br.clone(), - )) - } - } - }); - - self.pop_placeholders(placeholder_map, snapshot); - - debug!("plug_leaks: result={:?}", result); - - result - } - - /// Pops the placeholder regions found in `placeholder_map` from the region - /// inference context. Whenever you create placeholder regions via - /// `replace_bound_vars_with_placeholders`, they must be popped before you - /// commit the enclosing snapshot (if you do not commit, e.g., within a - /// probe or as a result of an error, then this is not necessary, as - /// popping happens as part of the rollback). - /// - /// Note: popping also occurs implicitly as part of `leak_check`. - pub fn pop_placeholders( - &self, - placeholder_map: PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'a, 'tcx>, - ) { - debug!("pop_placeholders({:?})", placeholder_map); - let placeholder_regions: FxHashSet<_> = placeholder_map.values().cloned().collect(); - self.borrow_region_constraints().pop_placeholders(&placeholder_regions); - self.universe.set(snapshot.universe); - if !placeholder_map.is_empty() { - self.projection_cache.borrow_mut().rollback_placeholder( - &snapshot.projection_cache_snapshot); - } - } } diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index de64800ee8d35..bbab17f951659 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -215,23 +215,41 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { ) -> bool { debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data); - // Check if this relationship is implied by a given. match *a_region { + // Check if this relationship is implied by a given. ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid)) { debug!("given"); return false; }, + _ => {} } + match *b_data { VarValue::Value(cur_region) => { - let lub = self.lub_concrete_regions(a_region, cur_region); + let mut lub = self.lub_concrete_regions(a_region, cur_region); if lub == cur_region { return false; } + // Watch out for `'b: !1` relationships, where the + // universe of `'b` can't name the placeholder `!1`. In + // that case, we have to grow `'b` to be `'static` for the + // relationship to hold. This is obviously a kind of sub-optimal + // choice -- in the future, when we incorporate a knowledge + // of the parameter environment, we might be able to find a + // tighter bound than `'static`. + // + // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) + let b_universe = self.var_infos[b_vid].universe; + if let ty::RePlaceholder(p) = lub { + if b_universe.cannot_name(p.universe) { + lub = self.tcx().types.re_static; + } + } + debug!( "Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub @@ -554,10 +572,22 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { lower_bounds.sort_by_key(region_order_key); upper_bounds.sort_by_key(region_order_key); + let node_universe = self.var_infos[node_idx].universe; + for lower_bound in &lower_bounds { + let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region { + if node_universe.cannot_name(p.universe) { + self.tcx().types.re_static + } else { + lower_bound.region + } + } else { + lower_bound.region + }; + for upper_bound in &upper_bounds { if !self.region_rels - .is_subregion_of(lower_bound.region, upper_bound.region) + .is_subregion_of(effective_lower_bound, upper_bound.region) { let origin = self.var_infos[node_idx].origin.clone(); debug!( @@ -580,9 +610,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { span_bug!( self.var_infos[node_idx].origin.span(), "collect_error_for_expanding_node() could not find \ - error for var {:?}, lower_bounds={:?}, \ - upper_bounds={:?}", + error for var {:?} in universe {:?}, lower_bounds={:#?}, \ + upper_bounds={:#?}", node_idx, + node_universe, lower_bounds, upper_bounds ); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9a5e707b57d89..3b9affa6ffb50 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,6 @@ use ty::{FloatVid, IntVid, TyVid}; use util::nodemap::FxHashMap; use self::combine::CombineFields; -use self::higher_ranked::HrMatchResult; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; @@ -948,39 +947,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return None; } - Some(self.commit_if_ok(|snapshot| { - let ( - ty::SubtypePredicate { - a_is_expected, - a, - b, - }, - placeholder_map, - ) = self.replace_bound_vars_with_placeholders(predicate); + let ( + ty::SubtypePredicate { + a_is_expected, + a, + b, + }, + _, + ) = self.replace_bound_vars_with_placeholders(predicate); - let cause_span = cause.span; - let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; - self.leak_check(false, cause_span, &placeholder_map, snapshot)?; - self.pop_placeholders(placeholder_map, snapshot); - Ok(ok.unit()) - })) + Some( + self.at(cause, param_env) + .sub_exp(a_is_expected, a, b) + .map(|ok| ok.unit()), + ) } pub fn region_outlives_predicate( &self, cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>, - ) -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { - let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = - self.replace_bound_vars_with_placeholders(predicate); - let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span) - }); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, cause.span, &placeholder_map, snapshot)?; - Ok(self.pop_placeholders(placeholder_map, snapshot)) - }) + ) { + let (ty::OutlivesPredicate(r_a, r_b), _) = + self.replace_bound_vars_with_placeholders(predicate); + let origin = + SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` } pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { @@ -1389,46 +1381,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.replace_bound_vars(value, fld_r, fld_t) } - /// Given a higher-ranked projection predicate like: - /// - /// for<'a> >::Output = &'a u32 - /// - /// and a target trait-ref like: - /// - /// > - /// - /// find a substitution `S` for the higher-ranked regions (here, - /// `['a => 'x]`) such that the predicate matches the trait-ref, - /// and then return the value (here, `&'a u32`) but with the - /// substitution applied (hence, `&'x u32`). - /// - /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more - /// details. - pub fn match_poly_projection_predicate( - &self, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - match_a: ty::PolyProjectionPredicate<'tcx>, - match_b: ty::TraitRef<'tcx>, - ) -> InferResult<'tcx, HrMatchResult>> { - let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty)); - let trace = TypeTrace { - cause, - values: TraitRefs(ExpectedFound::new( - true, - match_pair.skip_binder().0, - match_b, - )), - }; - - let mut combine = self.combine_fields(trace, param_env); - let result = combine.higher_ranked_match(&match_pair, &match_b, true)?; - Ok(InferOk { - value: result, - obligations: combine.obligations, - }) - } - /// See `verify_generic_bound` method in `region_constraints` pub fn verify_generic_bound( &self, diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 89086e66dffbf..b29eb67dfa225 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -17,8 +17,6 @@ use ty::{Region, RegionVid}; use std::collections::BTreeMap; use std::{cmp, fmt, mem, u32}; -mod taint; - #[derive(Default)] pub struct RegionConstraintCollector<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. @@ -826,35 +824,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { .collect() } - /// Computes all regions that have been related to `r0` since the - /// mark `mark` was made---`r0` itself will be the first - /// entry. The `directions` parameter controls what kind of - /// relations are considered. For example, one can say that only - /// "incoming" edges to `r0` are desired, in which case one will - /// get the set of regions `{r|r <= r0}`. This is used when - /// checking whether placeholder regions are being improperly - /// related to other regions. - pub fn tainted( - &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mark: &RegionSnapshot, - r0: Region<'tcx>, - directions: TaintDirections, - ) -> FxHashSet> { - debug!( - "tainted(mark={:?}, r0={:?}, directions={:?})", - mark, r0, directions - ); - - // `result_set` acts as a worklist: we explore all outgoing - // edges and add any new regions we find to result_set. This - // is not a terribly efficient implementation. - let mut taint_set = taint::TaintSet::new(directions, r0); - taint_set.fixed_point(tcx, &self.undo_log[mark.length..], &self.data.verifys); - debug!("tainted: result={:?}", taint_set); - return taint_set.into_set(); - } - pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> bool { self.undo_log[mark.length..] .iter() diff --git a/src/librustc/infer/region_constraints/taint.rs b/src/librustc/infer/region_constraints/taint.rs deleted file mode 100644 index 6743f37972ae5..0000000000000 --- a/src/librustc/infer/region_constraints/taint.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::*; - -#[derive(Debug)] -pub(super) struct TaintSet<'tcx> { - directions: TaintDirections, - regions: FxHashSet>, -} - -impl<'tcx> TaintSet<'tcx> { - pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self { - let mut regions = FxHashSet::default(); - regions.insert(initial_region); - TaintSet { - directions: directions, - regions: regions, - } - } - - pub(super) fn fixed_point( - &mut self, - tcx: TyCtxt<'_, '_, 'tcx>, - undo_log: &[UndoLog<'tcx>], - verifys: &[Verify<'tcx>], - ) { - let mut prev_len = 0; - while prev_len < self.len() { - debug!( - "tainted: prev_len = {:?} new_len = {:?}", - prev_len, - self.len() - ); - - prev_len = self.len(); - - for undo_entry in undo_log { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::RegSubVar(a, b)) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::VarSubReg(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), b); - } - &AddConstraint(Constraint::RegSubReg(a, b)) => { - self.add_edge(a, b); - } - &AddGiven(a, b) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddVerify(i) => { - span_bug!( - verifys[i].origin.span(), - "we never add verifications while doing higher-ranked things", - ) - } - &Purged | &AddCombination(..) | &AddVar(..) => {} - } - } - } - } - - pub(super) fn into_set(self) -> FxHashSet> { - self.regions - } - - fn len(&self) -> usize { - self.regions.len() - } - - fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) { - if self.directions.incoming { - if self.regions.contains(&target) { - self.regions.insert(source); - } - } - - if self.directions.outgoing { - if self.regions.contains(&source) { - self.regions.insert(target); - } - } - } -} diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index f96c4e9014b36..92004ece26d00 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -771,13 +771,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } } &ty::Predicate::RegionOutlives(ref binder) => { - if select - .infcx() - .region_outlives_predicate(&dummy_cause, binder) - .is_err() - { - return false; - } + let () = select.infcx().region_outlives_predicate(&dummy_cause, binder); } &ty::Predicate::TypeOutlives(ref binder) => { match ( diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0e63ef666c75a..21352ac1053a8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -728,12 +728,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.region_outlives_predicate(&obligation.cause, - &predicate).err().unwrap(); - struct_span_err!(self.tcx.sess, span, E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, err) + // These errors should show up as region + // inference failures. + panic!("region outlives {:?} failed", predicate); } ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 219e971b3c927..2e00d4d4b7c3b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -331,10 +331,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, } ty::Predicate::RegionOutlives(ref binder) => { - match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { - Ok(()) => ProcessResult::Changed(vec![]), - Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), - } + let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder); + ProcessResult::Changed(vec![]) } ty::Predicate::TypeOutlives(ref binder) => { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 952b37b89f2d4..732ca70dc78c5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -13,7 +13,7 @@ use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPoin use super::util; use hir::def_id::DefId; -use infer::{InferCtxt, InferOk}; +use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use infer::type_variable::TypeVariableOrigin; use mir::interpret::ConstValue; use mir::interpret::{GlobalId}; @@ -192,28 +192,12 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( obligation); let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (placeholder_predicate, placeholder_map) = + infcx.commit_if_ok(|_| { + let (placeholder_predicate, _) = infcx.replace_bound_vars_with_placeholders(&obligation.predicate); - let skol_obligation = obligation.with(placeholder_predicate); - let r = match project_and_unify_type(selcx, &skol_obligation) { - Ok(result) => { - let span = obligation.cause.span; - match infcx.leak_check(false, span, &placeholder_map, snapshot) { - Ok(()) => Ok(infcx.plug_leaks(placeholder_map, snapshot, result)), - Err(e) => { - debug!("poly_project_and_unify_type: leak check encountered error {:?}", e); - Err(MismatchedProjectionTypes { err: e }) - } - } - } - Err(e) => { - Err(e) - } - }; - - r + let placeholder_obligation = obligation.with(placeholder_predicate); + project_and_unify_type(selcx, &placeholder_obligation) }) } @@ -1443,17 +1427,25 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - poly_projection: ty::PolyProjectionPredicate<'tcx>) + poly_cache_entry: ty::PolyProjectionPredicate<'tcx>) -> Progress<'tcx> { let infcx = selcx.infcx(); - let cause = obligation.cause.clone(); + let cause = &obligation.cause; let param_env = obligation.param_env; - let trait_ref = obligation.predicate.trait_ref(infcx.tcx); - match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) { - Ok(InferOk { value: ty_match, obligations }) => { + + let (cache_entry, _) = + infcx.replace_bound_vars_with_fresh_vars( + cause.span, + LateBoundRegionConversionTime::HigherRankedType, + &poly_cache_entry); + + let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); + let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); + match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { + Ok(InferOk { value: _, obligations }) => { Progress { - ty: ty_match.value, + ty: cache_entry.ty, obligations, } } @@ -1463,7 +1455,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( "Failed to unify obligation `{:?}` \ with poly_projection `{:?}`: {:?}", obligation, - poly_projection, + poly_cache_entry, e); } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2576578f4c294..f5e96286d184e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -29,7 +29,7 @@ use super::{ use dep_graph::{DepKind, DepNodeIndex}; use hir::def_id::DefId; -use infer::{self, InferCtxt, InferOk, TypeFreshener}; +use infer::{InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; use mir::interpret::GlobalId; use ty::fast_reject; @@ -44,7 +44,6 @@ use rustc_target::spec::abi::Abi; use std::cmp; use std::fmt; use std::iter; -use std::mem; use std::rc::Rc; use util::nodemap::{FxHashMap, FxHashSet}; @@ -1633,8 +1632,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ => return, } - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_definition_bounds(obligation, snapshot) + let result = self.infcx.probe(|_| { + self.match_projection_obligation_against_definition_bounds(obligation) }); if result { @@ -1645,16 +1644,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, ) -> bool { let poly_trait_predicate = self.infcx() .resolve_type_vars_if_possible(&obligation.predicate); - let (skol_trait_predicate, placeholder_map) = self.infcx() + let (skol_trait_predicate, _) = self.infcx() .replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( "match_projection_obligation_against_definition_bounds: \ - skol_trait_predicate={:?} placeholder_map={:?}", - skol_trait_predicate, placeholder_map + skol_trait_predicate={:?}", + skol_trait_predicate, ); let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty { @@ -1691,8 +1689,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, bound.clone(), skol_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, ) }) }); @@ -1710,12 +1706,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, bound, skol_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, ); - self.infcx.pop_placeholders(placeholder_map, snapshot); - assert!(result); true } @@ -1727,20 +1719,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_bound: ty::PolyTraitRef<'tcx>, skol_trait_ref: ty::TraitRef<'tcx>, - placeholder_map: &infer::PlaceholderMap<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, ) -> bool { debug_assert!(!skol_trait_ref.has_escaping_bound_vars()); - if self.infcx + self.infcx .at(&obligation.cause, obligation.param_env) .sup(ty::Binder::dummy(skol_trait_ref), trait_bound) - .is_err() - { - return false; - } - - self.infcx - .leak_check(false, obligation.cause.span, placeholder_map, snapshot) .is_ok() } @@ -1942,14 +1925,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(placeholder_map) = self.match_impl(impl_def_id, obligation, snapshot) + self.infcx.probe(|_| { + if let Ok(_substs) = self.match_impl(impl_def_id, obligation) { candidates.vec.push(ImplCandidate(impl_def_id)); - - // N.B., we can safely drop the placeholder map - // since we are in a probe. - mem::drop(placeholder_map); } }); }, @@ -2607,8 +2586,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // binder moved -\ let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ - self.infcx.in_snapshot(|snapshot| { - let (skol_ty, placeholder_map) = self.infcx + self.infcx.in_snapshot(|_| { + let (skol_ty, _) = self.infcx .replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, @@ -2629,8 +2608,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &[], ); obligations.push(skol_obligation); - self.infcx - .plug_leaks(placeholder_map, snapshot, obligations) + obligations }) }) .collect() @@ -2721,9 +2699,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.in_snapshot(|snapshot| { + self.infcx.in_snapshot(|_| { let result = - self.match_projection_obligation_against_definition_bounds(obligation, snapshot); + self.match_projection_obligation_against_definition_bounds(obligation); assert!(result); }) } @@ -2840,9 +2818,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested, ); - let trait_obligations: Vec> = self.infcx.in_snapshot(|snapshot| { + let trait_obligations: Vec> = self.infcx.in_snapshot(|_| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, placeholder_map) = self.infcx + let (trait_ref, _) = self.infcx .replace_bound_vars_with_placeholders(&poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); self.impl_or_trait_obligations( @@ -2851,8 +2829,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.param_env, trait_def_id, &trait_ref.substs, - placeholder_map, - snapshot, ) }); @@ -2877,8 +2853,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.in_snapshot(|snapshot| { - let (substs, placeholder_map) = self.rematch_impl(impl_def_id, obligation, snapshot); + self.infcx.in_snapshot(|_| { + let substs = self.rematch_impl(impl_def_id, obligation); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); self.vtable_impl( @@ -2887,8 +2863,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { cause, obligation.recursion_depth + 1, obligation.param_env, - placeholder_map, - snapshot, ) }) } @@ -2900,12 +2874,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, - placeholder_map: infer::PlaceholderMap<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, placeholder_map={:?})", - impl_def_id, substs, recursion_depth, placeholder_map + "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", + impl_def_id, substs, recursion_depth, ); let mut impl_obligations = self.impl_or_trait_obligations( @@ -2914,8 +2886,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { param_env, impl_def_id, &substs.value, - placeholder_map, - snapshot, ); debug!( @@ -3044,8 +3014,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, alias_def_id ); - self.infcx.in_snapshot(|snapshot| { - let (predicate, placeholder_map) = self.infcx + self.infcx.in_snapshot(|_| { + let (predicate, _) = self.infcx() .replace_bound_vars_with_placeholders(&obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; @@ -3057,8 +3027,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.param_env, trait_def_id, &substs, - placeholder_map, - snapshot, ); debug!( @@ -3473,13 +3441,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, - ) -> ( - Normalized<'tcx, &'tcx Substs<'tcx>>, - infer::PlaceholderMap<'tcx>, - ) { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok((substs, placeholder_map)) => (substs, placeholder_map), + ) -> Normalized<'tcx, &'tcx Substs<'tcx>> { + match self.match_impl(impl_def_id, obligation) { + Ok(substs) => substs, Err(()) => { bug!( "Impl {:?} was matchable against {:?} but now is not", @@ -3494,14 +3458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, - ) -> Result< - ( - Normalized<'tcx, &'tcx Substs<'tcx>>, - infer::PlaceholderMap<'tcx>, - ), - (), - > { + ) -> Result>, ()> { let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first @@ -3511,7 +3468,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Err(()); } - let (skol_obligation, placeholder_map) = self.infcx() + let (skol_obligation, _) = self.infcx() .replace_bound_vars_with_placeholders(&obligation.predicate); let skol_obligation_trait_ref = skol_obligation.trait_ref; @@ -3543,22 +3500,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; nested_obligations.extend(obligations); - if let Err(e) = - self.infcx - .leak_check(false, obligation.cause.span, &placeholder_map, snapshot) - { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok(( - Normalized { - value: impl_substs, - obligations: nested_obligations, - }, - placeholder_map, - )) + Ok(Normalized { + value: impl_substs, + obligations: nested_obligations, + }) } fn fast_reject_trait_refs( @@ -3714,8 +3660,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, // of impl or trait substs: &Substs<'tcx>, // for impl or trait - placeholder_map: infer::PlaceholderMap<'tcx>, - snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, ) -> Vec> { debug!("impl_or_trait_obligations(def_id={:?})", def_id); let tcx = self.tcx(); @@ -3777,8 +3721,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut seen = FxHashSet::default(); predicates.retain(|i| seen.insert(i.clone())); } - self.infcx() - .plug_leaks(placeholder_map, snapshot, predicates) + + predicates } } From 652fd2efdfea46f9b31859ff3c8a92e40581f224 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Oct 2018 16:38:50 -0400 Subject: [PATCH 08/30] add tests exercising `exists<'a> { forall<'b> { .. } }` pattern Amazingly, this scenario was not tested for trait matching. --- src/test/ui/hrtb/hrtb-exists-forall-fn.rs | 23 ++++++++++++ src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 24 ++++++++++++ .../hrtb-exists-forall-trait-contravariant.rs | 35 ++++++++++++++++++ .../hrtb-exists-forall-trait-covariant.rs | 37 +++++++++++++++++++ .../hrtb-exists-forall-trait-invariant.rs | 29 +++++++++++++++ .../hrtb-exists-forall-trait-invariant.stderr | 15 ++++++++ 6 files changed, 163 insertions(+) create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-fn.rs create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-fn.stderr create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.rs b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs new file mode 100644 index 0000000000000..bba1f4dfb86c2 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs @@ -0,0 +1,23 @@ +// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile! +// +// In particular, we test this pattern in trait solving, where it is not connected +// to any part of the source code. + +trait Trait {} + +fn foo<'a>() -> fn(&'a u32) { + panic!() +} + +fn main() { + // Here, proving that `(): Trait fn(&'b u32)>` uses the impl: + // + // - The impl provides the clause `forall<'a> { (): Trait }` + // - We instantiate `'a` existentially to get `(): Trait` + // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` + // - This requires (among other things) instantiating `'b` universally, + // yielding `fn(&!b u32)`, in a fresh universe U1 + // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. + + let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer +} diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr new file mode 100644 index 0000000000000..75ba89f58da1b --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -0,0 +1,24 @@ +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/hrtb-exists-forall-fn.rs:22:34 + | +LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer + | ^^^ + | + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'b) })... + = note: ...so that the expression is assignable: + expected for<'b> fn(&'b u32) + found fn(&u32) +note: but, the lifetime must be valid for the call at 22:34... + --> $DIR/hrtb-exists-forall-fn.rs:22:34 + | +LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer + | ^^^^^ +note: ...so type `fn(&u32)` of expression is valid during the expression + --> $DIR/hrtb-exists-forall-fn.rs:22:34 + | +LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs new file mode 100644 index 0000000000000..8801760056ecb --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs @@ -0,0 +1,35 @@ +// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile! +// +// In particular, we test this pattern in trait solving, where it is not connected +// to any part of the source code. +// +// compile-pass + +trait Trait {} + +fn foo() +where + T: Trait fn(&'b u32)>, +{ +} + +impl<'a> Trait for () {} + +fn main() { + // Here, proving that `(): Trait fn(&'b u32)>` uses the impl: + // + // - The impl provides the clause `forall<'a> { (): Trait }` + // - We instantiate `'a` existentially to get `(): Trait` + // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` -- this does a + // "bidirectional" subtyping check, so we wind up with: + // - `fn(&?a u32) <: for<'b> fn(&'b u32)` :- + // - `&'!b u32 <: &?a u32` + // - `!'b: ?a` -- solveable if `?a` is inferred to `'empty` + // - `for<'b> fn(&'b u32) <: fn(&?a u32)` :- + // - `&?a u32 u32 <: &?b u32` + // - `?a: ?b` -- solveable if `?b` is also inferred to `'empty` + // - So the subtyping check succeeds, somewhat surprisingly. + // This is because we can use `'empty`. + + foo::<()>(); +} diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs new file mode 100644 index 0000000000000..da1bb7cd5fd0b --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs @@ -0,0 +1,37 @@ +// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile! +// +// In particular, we test this pattern in trait solving, where it is not connected +// to any part of the source code. +// +// compile-pass + +trait Trait {} + +fn foo() +where + T: Trait fn(fn(&'b u32))>, +{ +} + +impl<'a> Trait for () {} + +fn main() { + // Here, proving that `(): Trait fn(&'b u32)>` uses the impl: + // + // - The impl provides the clause `forall<'a> { (): Trait }` + // - We instantiate `'a` existentially to get `(): Trait` + // - We unify `fn(fn(&?a u32))` with `for<'b> fn(fn(&'b u32))` -- this does a + // "bidirectional" subtyping check, so we wind up with: + // - `fn(fn(&?a u32)) <: for<'b> fn(fn(&'b u32))` :- + // - `fn(&!b u32) <: fn(&?a u32)` + // - `&?a u32 <: &!b u32` + // - `?a: !'b` -- solveable if `?a` is inferred to `'static` + // - `for<'b> fn(fn(&'b u32)) <: fn(fn(&?a u32))` :- + // - `fn(&?a u32) <: fn(&?b u32)` + // - `&?b u32 <: &?a u32` + // - `?b: ?a` -- solveable if `?b` is inferred to `'static` + // - So the subtyping check succeeds, somewhat surprisingly. + // This is because we can use `'static`. + + foo::<()>(); +} diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs new file mode 100644 index 0000000000000..db589548d0e8e --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs @@ -0,0 +1,29 @@ +// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile! +// +// In particular, we test this pattern in trait solving, where it is not connected +// to any part of the source code. + +use std::cell::Cell; + +trait Trait {} + +fn foo() +where + T: Trait fn(Cell<&'b u32>)>, +{ +} + +impl<'a> Trait)> for () {} + +fn main() { + // Here, proving that `(): Trait fn(&'b u32)>` uses the impl: + // + // - The impl provides the clause `forall<'a> { (): Trait }` + // - We instantiate `'a` existentially to get `(): Trait` + // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` + // - This requires (among other things) instantiating `'b` universally, + // yielding `fn(&!b u32)`, in a fresh universe U1 + // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. + + foo::<()>(); //~ ERROR cannot infer +} diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr new file mode 100644 index 0000000000000..7a0986ccdd939 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -0,0 +1,15 @@ +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 + | +LL | foo::<()>(); //~ ERROR cannot infer + | ^^^^^^^^^ + | + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })... + = note: ...so that the types are compatible: + expected Trait fn(std::cell::Cell<&'b u32>)> + found Trait)> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0495`. From 78705b5ec75b96d03b88b46f81466dd53f1c1c9b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Oct 2018 16:39:29 -0400 Subject: [PATCH 09/30] tests: move coherence-subtyping from run-pass to compile-fail This is the pattern we no longer accept. --- .../coherence/coherence-subtyping.rs | 4 ++- .../ui/coherence/coherence-subtyping.stderr | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) rename src/test/{run-pass => ui}/coherence/coherence-subtyping.rs (94%) create mode 100644 src/test/ui/coherence/coherence-subtyping.stderr diff --git a/src/test/run-pass/coherence/coherence-subtyping.rs b/src/test/ui/coherence/coherence-subtyping.rs similarity index 94% rename from src/test/run-pass/coherence/coherence-subtyping.rs rename to src/test/ui/coherence/coherence-subtyping.rs index b7aa57b5c31f7..2ac9156017829 100644 --- a/src/test/run-pass/coherence/coherence-subtyping.rs +++ b/src/test/ui/coherence/coherence-subtyping.rs @@ -1,4 +1,3 @@ -// run-pass // Test that two distinct impls which match subtypes of one another // yield coherence errors (or not) depending on the variance. @@ -10,6 +9,7 @@ impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + //~^ ERROR } /////////////////////////////////////////////////////////////////////////// @@ -22,6 +22,7 @@ impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + //~^ ERROR } /////////////////////////////////////////////////////////////////////////// @@ -34,6 +35,7 @@ impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + //~^ ERROR } fn main() { } diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr new file mode 100644 index 0000000000000..92ac829f8000b --- /dev/null +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -0,0 +1,30 @@ +error[E0119]: conflicting implementations of trait `Contravariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: + --> $DIR/coherence-subtyping.rs:21:1 + | +LL | impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { + | -------------------------------------------------------------- first implementation here +... +LL | impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + +error[E0119]: conflicting implementations of trait `Covariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: + --> $DIR/coherence-subtyping.rs:34:1 + | +LL | impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { + | ---------------------------------------------------------- first implementation here +... +LL | impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + +error[E0119]: conflicting implementations of trait `Invariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: + --> $DIR/coherence-subtyping.rs:47:1 + | +LL | impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { + | ---------------------------------------------------------- first implementation here +... +LL | impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. From d3c96ff15249a73736222d41d87ade7013440945 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Oct 2018 16:57:52 -0400 Subject: [PATCH 10/30] tests: worse diagnostics, but basically same errors --- .../associated-types-eq-hr.rs | 24 +++- .../associated-types-eq-hr.stderr | 110 +++++++----------- .../higher-ranked-projection.bad.stderr | 25 ++-- .../higher-ranked-projection.good.stderr | 3 +- .../higher-ranked-projection.rs | 3 +- .../expect-fn-supply-fn.rs | 9 +- .../expect-fn-supply-fn.stderr | 93 ++++++++------- src/test/ui/generator/auto-trait-regions.rs | 8 +- .../ui/generator/auto-trait-regions.stderr | 65 ++++++----- .../ui/hrtb/hrtb-cache-issue-54302.stderr | 16 ++- src/test/ui/hrtb/hrtb-conflate-regions.rs | 2 +- src/test/ui/hrtb/hrtb-conflate-regions.stderr | 23 ++-- ...tb-higher-ranker-supertraits-transitive.rs | 2 +- ...igher-ranker-supertraits-transitive.stderr | 21 ++-- .../ui/hrtb/hrtb-higher-ranker-supertraits.rs | 6 +- .../hrtb-higher-ranker-supertraits.stderr | 89 ++++++++------ src/test/ui/hrtb/hrtb-just-for-static.rs | 2 +- src/test/ui/hrtb/hrtb-just-for-static.stderr | 22 ++-- src/test/ui/hrtb/hrtb-perfect-forwarding.rs | 2 +- .../ui/hrtb/hrtb-perfect-forwarding.stderr | 31 +++-- src/test/ui/issues/issue-22872.stderr | 19 +-- src/test/ui/issues/issue-40000.rs | 3 +- src/test/ui/issues/issue-40000.stderr | 26 ++++- src/test/ui/issues/issue-54302-cases.rs | 8 +- src/test/ui/issues/issue-54302-cases.stderr | 70 +++++------ src/test/ui/issues/issue-54302.rs | 2 +- src/test/ui/issues/issue-54302.stderr | 16 ++- .../closure-arg-type-mismatch.rs | 6 +- .../closure-arg-type-mismatch.stderr | 73 ++++++++---- .../ui/mismatched_types/closure-mismatch.rs | 3 +- .../mismatched_types/closure-mismatch.stderr | 37 ++---- ...ion-lifetime-bounds-on-fns-where-clause.rs | 2 +- ...lifetime-bounds-on-fns-where-clause.stderr | 17 +-- ...ple-lifetime-bounds-on-fns-where-clause.rs | 2 +- ...lifetime-bounds-on-fns-where-clause.stderr | 17 +-- .../regions/regions-lifetime-bounds-on-fns.rs | 2 +- .../regions-lifetime-bounds-on-fns.stderr | 17 +-- src/test/ui/where-clauses/where-for-self-2.rs | 3 +- .../ui/where-clauses/where-for-self-2.stderr | 21 ++-- 39 files changed, 463 insertions(+), 437 deletions(-) diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs index d0245a07e40bd..bc7888f74af22 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.rs +++ b/src/test/ui/associated-types/associated-types-eq-hr.rs @@ -77,23 +77,35 @@ fn tuple_four() // not ok for tuple, two lifetimes, and lifetime matching is invariant } -pub fn main() { +pub fn call_foo() { foo::(); foo::(); //~ ERROR type mismatch +} +pub fn call_bar() { bar::(); //~ ERROR type mismatch bar::(); +} +pub fn call_tuple_one() { tuple_one::(); - //~^ ERROR E0277 - //~| ERROR type mismatch + //~^ ERROR E0495 + //~| ERROR E0495 +} +pub fn call_tuple_two() { tuple_two::(); - //~^ ERROR E0277 - //~| ERROR type mismatch + //~^ ERROR E0495 + //~| ERROR E0495 +} +pub fn call_tuple_three() { tuple_three::(); +} +pub fn call_tuple_four() { tuple_four::(); - //~^ ERROR E0277 + //~^ ERROR E0495 } + +fn main() { } diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 5e04dc5f8c5d9..226733da0f63f 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -17,7 +17,7 @@ LL | | } | |_^ error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` - --> $DIR/associated-types-eq-hr.rs:84:5 + --> $DIR/associated-types-eq-hr.rs:86:5 | LL | bar::(); //~ ERROR type mismatch | ^^^^^^^^^^^^^^^^ expected isize, found usize @@ -34,93 +34,67 @@ LL | | // ok for UintStruct, but not IntStruct LL | | } | |_^ -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:87:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/associated-types-eq-hr.rs:91:5 | LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 + | ^^^^^^^^^^^^^^^^^^ | -LL | / fn tuple_one() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick first -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:20), 'x) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:21), 'y) })... + = note: ...so that the types are compatible: + expected TheTrait<(&'x isize, &'y isize)> + found TheTrait<(&isize, &isize)> -error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` - --> $DIR/associated-types-eq-hr.rs:87:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/associated-types-eq-hr.rs:91:5 | LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 + | ^^^^^^^^^^^^^^^^^^ | -LL | / fn tuple_one() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick first -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:20), 'x) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:21), 'y) })... + = note: ...so that the types are compatible: + expected TheTrait<(&'x isize, &'y isize)> + found TheTrait<(&isize, &isize)> -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:91:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/associated-types-eq-hr.rs:97:5 | LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 + | ^^^^^^^^^^^^^^^^^^ | -LL | / fn tuple_two() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick second -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:23), 'x) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:24), 'y) })... + = note: ...so that the types are compatible: + expected TheTrait<(&'x isize, &'y isize)> + found TheTrait<(&isize, &isize)> -error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` - --> $DIR/associated-types-eq-hr.rs:91:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/associated-types-eq-hr.rs:97:5 | LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^ | -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 - | -LL | / fn tuple_two() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick second -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:23), 'x) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:24), 'y) })... + = note: ...so that the types are compatible: + expected TheTrait<(&'x isize, &'y isize)> + found TheTrait<(&isize, &isize)> -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:97:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/associated-types-eq-hr.rs:107:5 | LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_four` - --> $DIR/associated-types-eq-hr.rs:74:1 + | ^^^^^^^^^^^^^^^^^^^ | -LL | / fn tuple_four() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> -LL | | { -LL | | // not ok for tuple, two lifetimes, and lifetime matching is invariant -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:28), 'x) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:29), 'y) })... + = note: ...so that the types are compatible: + expected TheTrait<(&'x isize, &'y isize)> + found TheTrait<(&isize, &isize)> error: aborting due to 7 previous errors -Some errors occurred: E0271, E0277. +Some errors occurred: E0271, E0495. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index cc69e849fe144..b5355e6009975 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr @@ -1,17 +1,24 @@ -error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/higher-ranked-projection.rs:25:5 | LL | foo(()); - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | ^^^ | -note: required by `foo` - --> $DIR/higher-ranked-projection.rs:14:1 + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'a) })... + = note: ...so that the types are compatible: + expected Mirror + found Mirror +note: but, the lifetime must be valid for the expression at 25:5... + --> $DIR/higher-ranked-projection.rs:25:5 | -LL | / fn foo(_t: T) -LL | | where for<'a> &'a T: Mirror -LL | | {} - | |__^ +LL | foo(()); + | ^^^ +note: ...so type `fn(()) {foo::<&(), ()>}` of expression is valid during the expression + --> $DIR/higher-ranked-projection.rs:25:5 + | +LL | foo(()); + | ^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr index 632fe493e1f3f..a837df0cd2429 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr @@ -3,8 +3,7 @@ error: compilation successful | LL | / fn main() { //[good]~ ERROR compilation successful LL | | foo(()); -LL | | //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` -LL | | //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime +LL | | //[bad]~^ ERROR E0495 LL | | } | |_^ diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs index be6300c418293..2d2221c6c6392 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.rs +++ b/src/test/ui/associated-types/higher-ranked-projection.rs @@ -23,6 +23,5 @@ fn foo(_t: T) #[rustc_error] fn main() { //[good]~ ERROR compilation successful foo(()); - //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` - //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime + //[bad]~^ ERROR E0495 } diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs index 8c7d3cbad33c4..49f6565540b7e 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs @@ -28,14 +28,14 @@ fn expect_free_supply_bound() { // Here, we are given a function whose region is bound at closure level, // but we expect one bound in the argument. Error results. with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - //~^ ERROR type mismatch in closure arguments + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { // Here, we are given a `fn(&u32)` but we expect a `fn(&'x // u32)`. In principle, this could be ok, but we demand equality. with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - //~^ ERROR type mismatch in closure arguments + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_closure() { @@ -43,8 +43,9 @@ fn expect_bound_supply_free_from_closure() { // bound at the closure level, but we expect something bound at // the argument level. type Foo<'a> = fn(&'a u32); - with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {}); - //~^ ERROR type mismatch in closure arguments + with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + //~^ ERROR cannot infer + }); } fn expect_bound_supply_bound<'x>(x: &'x u32) { diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index 9c85743106776..d140e9989a3f6 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -36,58 +36,61 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:30:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:30:52 + | +LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + | ^^^^^^^^ lifetime mismatch + | + = note: expected type `fn(&u32)` + found type `for<'r> fn(&'r u32)` + = note: lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) })... +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 30:48 + --> $DIR/expect-fn-supply-fn.rs:30:48 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `for<'a, 'r> fn(fn(&'a u32), &'r i32) -> _` - | -note: required by `with_closure_expecting_fn_with_free_region` - --> $DIR/expect-fn-supply-fn.rs:1:1 - | -LL | / fn with_closure_expecting_fn_with_free_region(_: F) -LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) -LL | | { -LL | | } - | |_^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:37:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:37:53 | LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `for<'r> fn(for<'s> fn(&'s u32), &'r i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ + | ^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `for<'r> fn(&'r u32)` + found type `fn(&'x u32)` + = note: lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 34:37 + --> $DIR/expect-fn-supply-fn.rs:34:37 + | +LL | fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { + | ^^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:46:5 - | -LL | with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `for<'r> fn(for<'s> fn(&'s u32), &'r i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements + --> $DIR/expect-fn-supply-fn.rs:46:53 + | +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^ + | + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... + = note: ...so that the types are compatible: + expected for<'r> fn(&'r u32) + found fn(&u32) +note: but, the lifetime must be valid for the expression at 46:65... + --> $DIR/expect-fn-supply-fn.rs:46:65 + | +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | _________________________________________________________________^ +LL | | //~^ ERROR cannot infer +LL | | }); + | |_____^ +note: ...so that the type `fn(&u32)` will meet its required lifetime bounds + --> $DIR/expect-fn-supply-fn.rs:46:53 + | +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^ error: aborting due to 5 previous errors -Some errors occurred: E0308, E0631. +Some errors occurred: E0308, E0495. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 2110e8a5407ba..4523e05696a2b 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -27,7 +27,9 @@ fn main() { yield; assert_foo(x); }; - assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied + assert_foo(gen); + //~^ ERROR mismatched types + //~| ERROR mismatched types // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); @@ -44,5 +46,7 @@ fn main() { yield; assert_foo(a); }; - assert_foo(gen); //~ ERROR the requirement `for<'r, 's> 'r : 's` is not satisfied + assert_foo(gen); + //~^ ERROR E0495 + //~| ERROR E0495 } diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index a301dc2ff9a00..3998ffe2522b4 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,37 +1,50 @@ -error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` +error[E0308]: mismatched types --> $DIR/auto-trait-regions.rs:30:5 | -LL | assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied - | ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No` +LL | assert_foo(gen); + | ^^^^^^^^^^ lifetime mismatch | - = help: the following implementations were found: - - = note: required because it appears within the type `OnlyFooIfStaticRef` - = note: required because it appears within the type `&OnlyFooIfStaticRef` - = note: required because it appears within the type `for<'r> {&'r OnlyFooIfStaticRef, ()}` - = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` -note: required by `assert_foo` - --> $DIR/auto-trait-regions.rs:20:1 + = note: expected type `Foo` + found type `Foo` + = note: lifetime RePlaceholder(Placeholder { universe: U31, name: BrAnon(1) })... + = note: ...does not necessarily outlive the static lifetime + +error[E0308]: mismatched types + --> $DIR/auto-trait-regions.rs:30:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^ lifetime mismatch | -LL | fn assert_foo(f: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected type `Foo` + found type `Foo` + = note: lifetime RePlaceholder(Placeholder { universe: U35, name: BrAnon(1) })... + = note: ...does not necessarily outlive the static lifetime -error[E0279]: the requirement `for<'r, 's> 'r : 's` is not satisfied (`expected bound lifetime parameter, found concrete lifetime`) - --> $DIR/auto-trait-regions.rs:47:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements + --> $DIR/auto-trait-regions.rs:49:5 | -LL | assert_foo(gen); //~ ERROR the requirement `for<'r, 's> 'r : 's` is not satisfied +LL | assert_foo(gen); | ^^^^^^^^^^ | - = note: required because of the requirements on the impl of `for<'r, 's> Foo` for `A<'_, '_>` - = note: required because it appears within the type `for<'r, 's> {A<'r, 's>, ()}` - = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:42:15: 46:6 for<'r, 's> {A<'r, 's>, ()}]` -note: required by `assert_foo` - --> $DIR/auto-trait-regions.rs:20:1 + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U47, name: BrAnon(2) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U47, name: BrAnon(1) })... + = note: ...so that the types are compatible: + expected Foo + found Foo + +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements + --> $DIR/auto-trait-regions.rs:49:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^ | -LL | fn assert_foo(f: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U51, name: BrAnon(2) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U51, name: BrAnon(1) })... + = note: ...so that the types are compatible: + expected Foo + found Foo -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0277, E0279. -For more information about an error, try `rustc --explain E0277`. +Some errors occurred: E0308, E0495. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr index 061d0e309c500..940a6e3f06853 100644 --- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -1,17 +1,15 @@ -error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements --> $DIR/hrtb-cache-issue-54302.rs:19:5 | LL | assert_deserialize_owned::<&'static str>(); //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str` - = note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str` -note: required by `main::assert_deserialize_owned` - --> $DIR/hrtb-cache-issue-54302.rs:18:5 - | -LL | fn assert_deserialize_owned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'de) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Deserialize<'de> + found Deserialize<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0279`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.rs b/src/test/ui/hrtb/hrtb-conflate-regions.rs index 8953a847213d5..391303676d784 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.rs +++ b/src/test/ui/hrtb/hrtb-conflate-regions.rs @@ -25,6 +25,6 @@ impl<'a> Foo<(&'a isize, &'a isize)> for SomeStruct } fn a() { want_foo1::(); } // OK -- foo wants just one region -fn b() { want_foo2::(); } //~ ERROR E0277 +fn b() { want_foo2::(); } //~ ERROR fn main() { } diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index e2a99ea8472ba..24d374e470e32 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,20 +1,15 @@ -error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/hrtb-conflate-regions.rs:28:10 | -LL | fn b() { want_foo2::(); } //~ ERROR E0277 - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct` +LL | fn b() { want_foo2::(); } //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the following implementations were found: - > -note: required by `want_foo2` - --> $DIR/hrtb-conflate-regions.rs:8:1 - | -LL | / fn want_foo2() -LL | | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> -LL | | { -LL | | } - | |_^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'a) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:12), 'b) })... + = note: ...so that the types are compatible: + expected Foo<(&'a isize, &'b isize)> + found Foo<(&isize, &isize)> 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 E0495`. diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.rs b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.rs index 99001d7053c62..f9ae1429ee4a2 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.rs +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.rs @@ -44,7 +44,7 @@ fn want_qux(b: &B) where B : Qux { want_foo_for_any_tcx(b); - want_bar_for_any_ccx(b); //~ ERROR E0277 + want_bar_for_any_ccx(b); //~ ERROR } fn main() {} diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index d233ed475241a..b02764184fbe9 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,19 +1,14 @@ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied +error[E0308]: mismatched types --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | -LL | want_bar_for_any_ccx(b); //~ ERROR E0277 - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` +LL | want_bar_for_any_ccx(b); //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound -note: required by `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:31:1 - | -LL | / fn want_bar_for_any_ccx(b: &B) -LL | | where B : for<'ccx> Bar<'ccx> -LL | | { -LL | | } - | |_^ + = note: expected type `for<'ccx> Bar<'ccx>` + found type `Bar<'static>` + = note: lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:16), 'ccx) })... + = note: ...does not necessarily outlive the static lifetime 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 E0308`. diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs index f430a10d2a722..638587f428d78 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs @@ -15,7 +15,8 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F) where F : Foo<'x> { want_foo_for_some_tcx(f); - want_foo_for_any_tcx(f); //~ ERROR E0277 + want_foo_for_any_tcx(f); //~ ERROR E0308 + //~^ ERROR E0308 } fn want_foo_for_any_tcx(f: &F) @@ -32,7 +33,8 @@ fn want_bar_for_some_ccx<'x,B>(b: &B) want_foo_for_any_tcx(b); want_bar_for_some_ccx(b); - want_bar_for_any_ccx(b); //~ ERROR E0277 + want_bar_for_any_ccx(b); //~ ERROR E0308 + //~^ ERROR E0308 } fn want_bar_for_any_ccx(b: &B) diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr index fe485c5b259eb..71ed59ce2ff7e 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -1,40 +1,63 @@ -error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied +error[E0308]: mismatched types --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 | -LL | want_foo_for_any_tcx(f); //~ ERROR E0277 - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` +LL | want_foo_for_any_tcx(f); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound -note: required by `want_foo_for_any_tcx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1 + = note: expected type `for<'tcx> Foo<'tcx>` + found type `Foo<'x>` + = note: lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:15), 'tcx) })... +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 14:26 + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:26 | -LL | / fn want_foo_for_any_tcx(f: &F) -LL | | where F : for<'tcx> Foo<'tcx> -LL | | { -LL | | want_foo_for_some_tcx(f); -LL | | want_foo_for_any_tcx(f); -LL | | } - | |_^ +LL | fn want_foo_for_some_tcx<'x,F>(f: &'x F) + | ^^ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5 - | -LL | want_bar_for_any_ccx(b); //~ ERROR E0277 - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound -note: required by `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1 - | -LL | / fn want_bar_for_any_ccx(b: &B) -LL | | where B : for<'ccx> Bar<'ccx> -LL | | { -LL | | want_foo_for_some_tcx(b); -... | -LL | | want_bar_for_any_ccx(b); -LL | | } - | |_^ +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 + | +LL | want_foo_for_any_tcx(f); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `for<'tcx> Foo<'tcx>` + found type `Foo<'x>` +note: the lifetime 'x as defined on the function body at 14:26... + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:26 + | +LL | fn want_foo_for_some_tcx<'x,F>(f: &'x F) + | ^^ + = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:15), 'tcx) }) + +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits.rs:36:5 + | +LL | want_bar_for_any_ccx(b); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `for<'ccx> Bar<'ccx>` + found type `Bar<'x>` + = note: lifetime RePlaceholder(Placeholder { universe: U8, name: BrNamed(crate0:DefIndex(1:19), 'ccx) })... +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 29:26 + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:26 + | +LL | fn want_bar_for_some_ccx<'x,B>(b: &B) + | ^^ + +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits.rs:36:5 + | +LL | want_bar_for_any_ccx(b); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `for<'ccx> Bar<'ccx>` + found type `Bar<'x>` +note: the lifetime 'x as defined on the function body at 29:26... + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:26 + | +LL | fn want_bar_for_some_ccx<'x,B>(b: &B) + | ^^ + = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U8, name: BrNamed(crate0:DefIndex(1:19), 'ccx) }) -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.rs b/src/test/ui/hrtb/hrtb-just-for-static.rs index c162c777c0bad..3aee241ccd2d7 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.rs +++ b/src/test/ui/hrtb/hrtb-just-for-static.rs @@ -21,7 +21,7 @@ fn give_any() { struct StaticInt; impl Foo<&'static isize> for StaticInt { } fn give_static() { - want_hrtb::() //~ ERROR `for<'a> StaticInt: Foo<&'a isize>` is not satisfied + want_hrtb::() //~ ERROR } fn main() { } diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 38865fac86ded..d3c2f7d059a6f 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,20 +1,14 @@ -error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied +error[E0308]: mismatched types --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | want_hrtb::() //~ ERROR `for<'a> StaticInt: Foo<&'a isize>` is not satisfied - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` +LL | want_hrtb::() //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = help: the following implementations were found: - > -note: required by `want_hrtb` - --> $DIR/hrtb-just-for-static.rs:8:1 - | -LL | / fn want_hrtb() -LL | | where T : for<'a> Foo<&'a isize> -LL | | { -LL | | } - | |_^ + = note: expected type `Foo<&'a isize>` + found type `Foo<&'static isize>` + = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'a) })... + = note: ...does not necessarily outlive the static lifetime 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 E0308`. diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs index 90e1773a3f62d..31dad39efc3f5 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs @@ -43,7 +43,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T) // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. - foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied + foo_hrtb_bar_not(&mut t); //~ ERROR E0495 } fn foo_hrtb_bar_hrtb(mut t: T) diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr index 6cada7ac78f4b..2de60a79a85bd 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -1,23 +1,22 @@ -error[E0277]: the trait bound `for<'a> T: Bar<&'a isize>` is not satisfied +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/hrtb-perfect-forwarding.rs:46:5 | -LL | foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied - | ^^^^^^^^^^^^^^^^ the trait `for<'a> Bar<&'a isize>` is not implemented for `T` +LL | foo_hrtb_bar_not(&mut t); //~ ERROR E0495 + | ^^^^^^^^^^^^^^^^ | - = help: consider adding a `where for<'a> T: Bar<&'a isize>` bound - = note: required because of the requirements on the impl of `for<'a> Foo<&'a isize>` for `&mut T` -note: required by `foo_hrtb_bar_not` - --> $DIR/hrtb-perfect-forwarding.rs:39:1 + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:23), 'a) })... + = note: ...so that the types are compatible: + expected Foo<&'a isize> + found Foo<&isize> +note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 39:21... + --> $DIR/hrtb-perfect-forwarding.rs:39:21 | -LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T) -LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize> -LL | | { -LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also -... | -LL | | foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied -LL | | } - | |_^ +LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) + | ^^ + = note: ...so that the types are compatible: + expected Bar<&isize> + found Bar<&'b isize> 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 E0495`. diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index 231080add9bd0..ebd096f1dde5a 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -1,23 +1,14 @@ -error[E0277]: the trait bound `for<'b> P: Process<'b>` is not satisfied +error[E0277]: `

>::Item` is not an iterator --> $DIR/issue-22872.rs:20:36 | LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> Process<'b>` is not implemented for `P` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

>::Item` is not an iterator | - = help: consider adding a `where for<'b> P: Process<'b>` bound + = help: the trait `std::iter::Iterator` is not implemented for `

>::Item` + = help: consider adding a `where

>::Item: std::iter::Iterator` bound = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper

` = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` -error[E0277]: `

>::Item` is not an iterator - --> $DIR/issue-22872.rs:20:36 - | -LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

>::Item` is not an iterator - | - = help: the trait `for<'b> std::iter::Iterator` is not implemented for `

>::Item` - = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper

` - = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-40000.rs b/src/test/ui/issues/issue-40000.rs index 2d1e1d07a26ff..c7d1900ada958 100644 --- a/src/test/ui/issues/issue-40000.rs +++ b/src/test/ui/issues/issue-40000.rs @@ -3,6 +3,5 @@ fn main() { fn foo(x: Box) {} let bar = Box::new(|x: &i32| {}) as Box; - foo(bar); //~ ERROR mismatched types - //~| expected concrete lifetime, found bound lifetime parameter + foo(bar); //~ ERROR E0495 } diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 3ff5870348109..3aa1da8680c02 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -1,12 +1,26 @@ -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-40000.rs:6:9 | -LL | foo(bar); //~ ERROR mismatched types - | ^^^ expected concrete lifetime, found bound lifetime parameter +LL | foo(bar); //~ ERROR E0495 + | ^^^ | - = note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>` - found type `std::boxed::Box` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U8, name: BrAnon(0) })... + = note: ...so that the types are compatible: + expected dyn for<'r> std::ops::Fn(&'r i32) + found dyn std::ops::Fn(&i32) +note: but, the lifetime must be valid for the block suffix following statement 2 at 5:5... + --> $DIR/issue-40000.rs:5:5 + | +LL | / let bar = Box::new(|x: &i32| {}) as Box; +LL | | foo(bar); //~ ERROR E0495 +LL | | } + | |_^ +note: ...so that variable is valid at time of its declaration + --> $DIR/issue-40000.rs:5:9 + | +LL | let bar = Box::new(|x: &i32| {}) as Box; + | ^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-54302-cases.rs b/src/test/ui/issues/issue-54302-cases.rs index 0c852a2eb6321..286d37b182e31 100644 --- a/src/test/ui/issues/issue-54302-cases.rs +++ b/src/test/ui/issues/issue-54302-cases.rs @@ -61,25 +61,25 @@ impl RefFoo for T where for<'a> &'a T: Foo<'static, T> { fn coerce_lifetime1(a: &u32) -> &'static u32 { >::ref_foo(a) - //~^ ERROR the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied + //~^ ERROR cannot infer } fn coerce_lifetime2(a: &i32) -> &'static i32 { >::ref_foo(a) - //~^ ERROR the requirement `for<'a> 'a : ` is not satisfied + //~^ ERROR cannot infer } fn coerce_lifetime3(a: &u64) -> &'static u64 { >::ref_foo(a) - //~^ ERROR type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` + //~^ ERROR cannot infer } fn coerce_lifetime4(a: &i64) -> &'static i64 { >::ref_foo(a) - //~^ ERROR type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` + //~^ ERROR cannot infer } fn main() {} diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr index 0ed88463277d5..09a4e091d2bcf 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -1,65 +1,51 @@ -error[E0277]: the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements --> $DIR/issue-54302-cases.rs:63:5 | LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo2<'_, u32>` is not implemented for `&'a u32` - | - = help: the following implementations were found: - <&'x u32 as Foo2<'x, u32>> - = note: required because of the requirements on the impl of `for<'a> Foo<'static, u32>` for `&'a u32` - = note: required because of the requirements on the impl of `RefFoo` for `u32` -note: required by `RefFoo::ref_foo` - --> $DIR/issue-54302-cases.rs:51:5 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | fn ref_foo(&self) -> &'static T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Foo<'static, u32> + found Foo<'_, u32> -error[E0279]: the requirement `for<'a> 'a : ` is not satisfied (`expected bound lifetime parameter 'a, found concrete lifetime`) +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements --> $DIR/issue-54302-cases.rs:69:5 | LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i32>` for `&'a i32` - = note: required because of the requirements on the impl of `for<'a> Foo<'static, i32>` for `&'a i32` - = note: required because of the requirements on the impl of `RefFoo` for `i32` -note: required by `RefFoo::ref_foo` - --> $DIR/issue-54302-cases.rs:51:5 - | -LL | fn ref_foo(&self) -> &'static T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Foo<'static, i32> + found Foo<'_, i32> -error[E0271]: type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements --> $DIR/issue-54302-cases.rs:75:5 | LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime - | - = note: required because of the requirements on the impl of `for<'a> Foo2<'_, u64>` for `&'a u64` - = note: required because of the requirements on the impl of `for<'a> Foo<'static, u64>` for `&'a u64` - = note: required because of the requirements on the impl of `RefFoo` for `u64` -note: required by `RefFoo::ref_foo` - --> $DIR/issue-54302-cases.rs:51:5 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | fn ref_foo(&self) -> &'static T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Foo<'static, u64> + found Foo<'_, u64> -error[E0271]: type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements --> $DIR/issue-54302-cases.rs:81:5 | LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime - | - = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i64>` for `&'a i64` - = note: required because of the requirements on the impl of `for<'a> Foo<'static, i64>` for `&'a i64` - = note: required because of the requirements on the impl of `RefFoo` for `i64` -note: required by `RefFoo::ref_foo` - --> $DIR/issue-54302-cases.rs:51:5 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | fn ref_foo(&self) -> &'static T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Foo<'static, i64> + found Foo<'_, i64> error: aborting due to 4 previous errors -Some errors occurred: E0271, E0277, E0279. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-54302.rs b/src/test/ui/issues/issue-54302.rs index c681d37cdae00..35cdc73a78fd0 100644 --- a/src/test/ui/issues/issue-54302.rs +++ b/src/test/ui/issues/issue-54302.rs @@ -11,7 +11,7 @@ fn main() { // Then why does it implement DeserializeOwned? This compiles. fn assert_deserialize_owned() {} assert_deserialize_owned::<&'static str>(); - //~^ ERROR the requirement `for<'de> 'de : ` is not satisfied + //~^ ERROR E0495 // It correctly does not implement for<'de> Deserialize<'de>. //fn assert_hrtb Deserialize<'de>>() {} diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr index 2d95aa2b156f2..b456d2582ffd6 100644 --- a/src/test/ui/issues/issue-54302.stderr +++ b/src/test/ui/issues/issue-54302.stderr @@ -1,17 +1,15 @@ -error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements --> $DIR/issue-54302.rs:13:5 | LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str` - = note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str` -note: required by `main::assert_deserialize_owned` - --> $DIR/issue-54302.rs:12:5 - | -LL | fn assert_deserialize_owned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'de) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the types are compatible: + expected Deserialize<'de> + found Deserialize<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0279`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs index c5d9e4b9b766b..f71a1736d4d3f 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -7,6 +7,8 @@ fn main() { fn baz(_: F) {} fn _test<'a>(f: fn(*mut &'a u32)) { - baz(f); //~ ERROR type mismatch - //~^ ERROR type mismatch + baz(f); //~ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 5dd6887005e83..2cd63099bb756 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -22,34 +22,67 @@ LL | a.iter().map(|_: (u16, u16)| 45); //~ ERROR type mismatch | | | expected signature of `fn(&(u32, u32)) -> _` -error[E0631]: type mismatch in function arguments +error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 | -LL | baz(f); //~ ERROR type mismatch - | ^^^ - | | - | expected signature of `for<'r> fn(*mut &'r u32) -> _` - | found signature of `fn(*mut &'a u32) -> _` +LL | baz(f); //~ ERROR mismatched types + | ^^^ lifetime mismatch | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 + = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` + found type `std::ops::Fn<(*mut &'a u32,)>` + = note: lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) })... +note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 9:10 + --> $DIR/closure-arg-type-mismatch.rs:9:10 | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn _test<'a>(f: fn(*mut &'a u32)) { + | ^^ -error[E0271]: type mismatch resolving `for<'r> >::Output == ()` +error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 | -LL | baz(f); //~ ERROR type mismatch - | ^^^ expected bound lifetime parameter, found concrete lifetime +LL | baz(f); //~ ERROR mismatched types + | ^^^ lifetime mismatch | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 + = note: expected type `std::ops::FnOnce<(*mut &u32,)>` + found type `std::ops::FnOnce<(*mut &'a u32,)>` + = note: lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... +note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 9:10 + --> $DIR/closure-arg-type-mismatch.rs:9:10 | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn _test<'a>(f: fn(*mut &'a u32)) { + | ^^ -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/closure-arg-type-mismatch.rs:10:5 + | +LL | baz(f); //~ ERROR mismatched types + | ^^^ lifetime mismatch + | + = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` + found type `std::ops::Fn<(*mut &'a u32,)>` +note: the lifetime 'a as defined on the function body at 9:10... + --> $DIR/closure-arg-type-mismatch.rs:9:10 + | +LL | fn _test<'a>(f: fn(*mut &'a u32)) { + | ^^ + = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) }) + +error[E0308]: mismatched types + --> $DIR/closure-arg-type-mismatch.rs:10:5 + | +LL | baz(f); //~ ERROR mismatched types + | ^^^ lifetime mismatch + | + = note: expected type `std::ops::FnOnce<(*mut &u32,)>` + found type `std::ops::FnOnce<(*mut &'a u32,)>` +note: the lifetime 'a as defined on the function body at 9:10... + --> $DIR/closure-arg-type-mismatch.rs:9:10 + | +LL | fn _test<'a>(f: fn(*mut &'a u32)) { + | ^^ + = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) }) + +error: aborting due to 7 previous errors -Some errors occurred: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +Some errors occurred: E0308, E0631. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs index 40a4641fe7196..0f28e5dfd7ee0 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -5,6 +5,5 @@ impl Foo for T {} fn baz(_: T) {} fn main() { - baz(|_| ()); //~ ERROR type mismatch - //~^ ERROR type mismatch + baz(|_| ()); //~ ERROR E0495 } diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index e55047e96c297..f028817a935a7 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,32 +1,15 @@ -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/closure-mismatch.rs:8:5 | -LL | baz(|_| ()); //~ ERROR type mismatch - | ^^^ expected bound lifetime parameter, found concrete lifetime +LL | baz(|_| ()); //~ ERROR E0495 + | ^^^ | - = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:5:1 - | -LL | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/closure-mismatch.rs:8:5 - | -LL | baz(|_| ()); //~ ERROR type mismatch - | ^^^ ------ found signature of `fn(_) -> _` - | | - | expected signature of `for<'r> fn(&'r ()) -> _` - | - = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:5:1 - | -LL | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U6, name: BrAnon(0) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U6, name: BrAnon(0) })... + = note: ...so that the types are compatible: + expected for<'r> std::ops::Fn<(&'r (),)> + found std::ops::Fn<(&(),)> -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs index ab4c6d9cf9198..e5514d32c4e9f 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs @@ -17,7 +17,7 @@ fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types + let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 } fn e() { diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr index 5c8b3d3ba6922..3824755fa06f5 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -16,16 +16,19 @@ LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { LL | a(x, y); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types - | ^ expected concrete lifetime, found bound lifetime parameter +LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 + | ^ | - = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...so that the expression is assignable: + expected for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize) + found for<'r, 's> fn(&'r mut &isize, &'s mut &isize) error: aborting due to 3 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +Some errors occurred: E0495, E0623. +For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs index 8e7f4ccad9cb4..3e635300d7b68 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs @@ -19,7 +19,7 @@ fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR mismatched types + let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0495 } fn e() { diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr index 01899349bf701..f694d31264070 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -27,16 +27,19 @@ LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { LL | a(x, y, z); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 | -LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR mismatched types - | ^ expected concrete lifetime, found bound lifetime parameter +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0495 + | ^ | - = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` - found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...so that the expression is assignable: + expected for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize) + found for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) error: aborting due to 4 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +Some errors occurred: E0495, E0623. +For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs index 2f35883cc9916..6ebfc3f80d252 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs @@ -17,7 +17,7 @@ fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types + let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 } fn e() { diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr index c4d4a159a9c32..20e28e8877fca 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -16,16 +16,19 @@ LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { LL | a(x, y); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types - | ^ expected concrete lifetime, found bound lifetime parameter +LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 + | ^ | - = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... + = note: ...so that the expression is assignable: + expected for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize) + found for<'r, 's> fn(&'r mut &isize, &'s mut &isize) error: aborting due to 3 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +Some errors occurred: E0495, E0623. +For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs index 10b25c734037a..c69055fe0cc82 100644 --- a/src/test/ui/where-clauses/where-for-self-2.rs +++ b/src/test/ui/where-clauses/where-for-self-2.rs @@ -18,6 +18,5 @@ fn foo(x: &T) {} fn main() { - foo(&X); - //~^ error: `for<'a> &'a _: Bar` is not satisfied + foo(&X); //~ ERROR E0308 } diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index dbe68b82c24cb..04d7bbabb2a57 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,19 +1,14 @@ -error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied +error[E0308]: mismatched types --> $DIR/where-for-self-2.rs:21:5 | -LL | foo(&X); - | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` +LL | foo(&X); //~ ERROR E0308 + | ^^^ lifetime mismatch | - = help: the following implementations were found: - <&'static u32 as Bar> -note: required by `foo` - --> $DIR/where-for-self-2.rs:16:1 - | -LL | / fn foo(x: &T) -LL | | where for<'a> &'a T: Bar -LL | | {} - | |__^ + = note: expected type `Bar` + found type `Bar` + = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:10), 'a) })... + = note: ...does not necessarily outlive the static lifetime 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 E0308`. From c8e0a90dfcbee25827089bfa58b82154f2644d74 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 31 Dec 2018 13:45:40 -0500 Subject: [PATCH 11/30] tests: cases where we now do the right thing but did not before Fixes #33684 --- ...pe.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 13 ++++---- .../hr-subtype.bound_a_b_vs_bound_a.stderr | 22 +++++++------- .../hr-subtype.bound_a_vs_bound_a.stderr | 6 ++-- .../hr-subtype.bound_a_vs_bound_b.stderr | 6 ++-- .../hr-subtype.bound_a_vs_free_x.stderr | 12 +++++++- ...-subtype.bound_co_a_b_vs_bound_co_a.stderr | 22 +++++++------- ...ubtype.bound_co_a_co_b_ret_contra_a.stderr | 22 +++++++------- ...hr-subtype.bound_co_a_vs_bound_co_b.stderr | 6 ++-- ...pe.bound_contra_a_contra_b_ret_co_a.stderr | 22 +++++++------- ...ubtype.bound_inv_a_b_vs_bound_inv_a.stderr | 13 ++++---- ...-subtype.bound_inv_a_vs_bound_inv_b.stderr | 6 ++-- .../hr-subtype.free_x_vs_free_x.stderr | 6 ++-- src/test/ui/hr-subtype/hr-subtype.rs | 20 ++++++------- src/test/ui/lub-glb/old-lub-glb-hr.rs | 9 ++++-- src/test/ui/lub-glb/old-lub-glb-hr.stderr | 17 ----------- ...regions-fn-subtyping-return-static-fail.rs | 9 ++---- ...ons-fn-subtyping-return-static-fail.stderr | 28 +++++++---------- .../regions-fn-subtyping-return-static.rs | 5 ++-- .../regions-fn-subtyping-return-static.stderr | 30 ++++++++++++++----- 19 files changed, 137 insertions(+), 137 deletions(-) delete mode 100644 src/test/ui/lub-glb/old-lub-glb-hr.stderr diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index 8e2b0b8c60045..4069e3b25ade0 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -1,16 +1,19 @@ -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ ... LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_________________________________________________________________________________________- in this macro invocation | - = note: expected type `std::option::Option fn(&'a u32, &'b u32) -> &'a u32>` - found type `std::option::Option fn(&'a u32, &'a u32) -> &'a u32>` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:26), 'b) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:25), 'a) })... + = note: ...so that the expression is assignable: + expected std::option::Option fn(&'a u32, &'b u32) -> &'a u32> + found std::option::Option fn(&'a u32, &'a u32) -> &'a u32> error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index dbb5018139076..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,16 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: compilation successful + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), -LL | | for<'a> fn(&'a u32, &'a u32)) } - | |__________________________________________________________________- in this macro invocation - | - = note: expected type `std::option::Option fn(&'a u32, &'b u32)>` - found type `std::option::Option fn(&'a u32, &'a u32)>` +LL | / fn main() { +LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful +LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful +LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 5fcb63e17bf31..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,12 +1,12 @@ error: compilation successful - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 5fcb63e17bf31..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,12 +1,12 @@ error: compilation successful - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index db9892b48a6f7..1225842665d99 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ lifetime mismatch ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } @@ -10,6 +10,16 @@ LL | | fn(&'x u32)) } | = note: expected type `std::option::Option fn(&'a u32)>` found type `std::option::Option` + = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:23), 'a) })... +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 48:22 + --> $DIR/hr-subtype.rs:48:22 + | +LL | fn supertype<'x,'y:'x,'z:'y>() { + | ^^ +... +LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), +LL | | fn(&'x u32)) } + | |___________________________________________- in this macro invocation error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index e9fb73411bd39..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,16 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: compilation successful + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), -LL | | for<'a> fn(Co<'a>, Co<'a>)) } - | |______________________________________________________________________- in this macro invocation - | - = note: expected type `std::option::Option fn(Co<'a>, Co<'b>)>` - found type `std::option::Option fn(Co<'a>, Co<'a>)>` +LL | / fn main() { +LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful +LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful +LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index d0e80faa68e8b..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,16 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: compilation successful + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, -LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } - | |______________________________________________________________________________________- in this macro invocation - | - = note: expected type `std::option::Option fn(Co<'a>, Co<'b>) -> Contra<'a>>` - found type `std::option::Option fn(Co<'a>, Co<'a>) -> Contra<'a>>` +LL | / fn main() { +LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful +LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful +LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 5fcb63e17bf31..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,12 +1,12 @@ error: compilation successful - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index 3605ecf4f8667..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,16 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: compilation successful + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, -LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } - | |______________________________________________________________________________________________- in this macro invocation - | - = note: expected type `std::option::Option fn(Contra<'a>, Contra<'b>) -> Co<'a>>` - found type `std::option::Option fn(Contra<'a>, Contra<'a>) -> Co<'a>>` +LL | / fn main() { +LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful +LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful +LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index fae6e9b5c89ca..1a806bd2cb550 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -1,16 +1,19 @@ -error[E0308]: mismatched types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ ... LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________________________________________________- in this macro invocation | - = note: expected type `std::option::Option fn(Inv<'a>, Inv<'b>)>` - found type `std::option::Option fn(Inv<'a>, Inv<'a>)>` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:25), 'a) })... + = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:26), 'b) })... + = note: ...so that the expression is assignable: + expected std::option::Option fn(Inv<'a>, Inv<'b>)> + found std::option::Option fn(Inv<'a>, Inv<'a>)> error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 5fcb63e17bf31..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,12 +1,12 @@ error: compilation successful - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 5fcb63e17bf31..25b74d855bb48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,12 +1,12 @@ error: compilation successful - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +... | +LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs index 4157953fb9068..ad4f39f840528 100644 --- a/src/test/ui/hr-subtype/hr-subtype.rs +++ b/src/test/ui/hr-subtype/hr-subtype.rs @@ -31,21 +31,17 @@ macro_rules! check { #[cfg($rev)] fn subtype<'x,'y:'x,'z:'y>() { gimme::<$t2>(None::<$t1>); - //[free_inv_x_vs_free_inv_y]~^ ERROR mismatched types + //[free_inv_x_vs_free_inv_y]~^ ERROR } #[cfg($rev)] fn supertype<'x,'y:'x,'z:'y>() { gimme::<$t1>(None::<$t2>); - //[bound_a_vs_free_x]~^ ERROR mismatched types - //[free_x_vs_free_y]~^^ ERROR mismatched types - //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR mismatched types - //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR mismatched types - //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR mismatched types - //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types - //[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR mismatched types - //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR mismatched types - //[bound_co_a_co_b_ret_contra_a]~^^^^^^^^^ ERROR mismatched types + //[bound_a_vs_free_x]~^ ERROR + //[free_x_vs_free_y]~^^ ERROR + //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR + //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR + //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR } } } @@ -103,4 +99,8 @@ fn main() { //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +//[bound_a_b_vs_bound_a]~^^^^^^ ERROR compilation successful +//[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR compilation successful +//[bound_co_a_b_vs_bound_co_a]~^^^^^^^^ ERROR compilation successful +//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful } diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs index 049905467769e..324dc86bd92b8 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.rs +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -1,11 +1,16 @@ // Test that we give a note when the old LUB/GLB algorithm would have -// succeeded but the new code (which is stricter) gives an error. +// succeeded but the new code (which requires equality) gives an +// error. However, now that we handle subtyping correctly, we no +// longer get an error, because we recognize these two types as +// equivalent! +// +// compile-pass fn foo( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { - let z = match 22 { //~ ERROR incompatible types + let z = match 22 { 0 => x, _ => y, }; diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr deleted file mode 100644 index 9c397a8fd2cc5..0000000000000 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0308]: match arms have incompatible types - --> $DIR/old-lub-glb-hr.rs:8:13 - | -LL | let z = match 22 { //~ ERROR incompatible types - | _____________^ -LL | | 0 => x, -LL | | _ => y, - | | - match arm with an incompatible type -LL | | }; - | |_____^ expected bound lifetime parameter, found concrete lifetime - | - = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)` - found type `for<'a> fn(&'a u8, &'a u8)` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions-fn-subtyping-return-static-fail.rs index a8fe562656ebb..242119cc201da 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs @@ -37,8 +37,7 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly - want_F(bar); //~ ERROR E0308 + want_F(bar); want_F(baz); } @@ -46,11 +45,7 @@ fn supply_F() { fn supply_G() { want_G(foo); want_G(bar); - want_G(baz); - //~^ ERROR mismatched types - //~| expected type `for<'cx> fn(&'cx S) -> &'static S` - //~| found type `for<'r> fn(&'r S) -> &'r S {baz}` - //~| expected concrete lifetime, found bound lifetime parameter 'cx + want_G(baz); //~ ERROR } pub fn main() { diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 0bf6e0514d21e..c9ccb9b6ded3d 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -1,21 +1,15 @@ -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static-fail.rs:41:12 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements + --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | -LL | want_F(bar); //~ ERROR E0308 - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx +LL | want_G(baz); //~ ERROR + | ^^^ | - = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` - found type `for<'a> fn(&'a S) -> &S {bar::<'_>}` + = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'cx) })... + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the expression is assignable: + expected for<'cx> fn(&'cx S) -> &'static S + found for<'r> fn(&'r S) -> &'r S -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static-fail.rs:49:12 - | -LL | want_G(baz); - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx - | - = note: expected type `for<'cx> fn(&'cx S) -> &'static S` - found type `for<'r> fn(&'r S) -> &'r S {baz}` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.rs b/src/test/ui/regions/regions-fn-subtyping-return-static.rs index fa5f6a334b0f0..4d6d342f571a5 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs @@ -5,6 +5,8 @@ // *ANY* lifetime and returns a reference with the 'static lifetime. // This can safely be considered to be an instance of `F` because all // lifetimes are sublifetimes of 'static. +// +// compile-pass #![allow(dead_code)] #![allow(unused_variables)] @@ -37,8 +39,7 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly - want_F(bar); //~ ERROR E0308 + want_F(bar); want_F(baz); } diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index 30646fe79659e..61eaf9fcf109b 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -1,12 +1,26 @@ -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static.rs:41:12 +warning: function `want_F` should have a snake case name such as `want_f` + --> $DIR/regions-fn-subtyping-return-static.rs:18:1 | -LL | want_F(bar); //~ ERROR E0308 - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx +LL | fn want_F(f: F) { } + | ^^^^^^^^^^^^^^^^^^^ | - = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` - found type `for<'a> fn(&'a S) -> &S {bar::<'_>}` + = note: #[warn(non_snake_case)] on by default -error: aborting due to previous error +warning: function `want_G` should have a snake case name such as `want_g` + --> $DIR/regions-fn-subtyping-return-static.rs:22:1 + | +LL | fn want_G(f: G) { } + | ^^^^^^^^^^^^^^^^^^^ + +warning: function `supply_F` should have a snake case name such as `supply_f` + --> $DIR/regions-fn-subtyping-return-static.rs:39:1 + | +LL | / fn supply_F() { +LL | | want_F(foo); +LL | | +LL | | want_F(bar); +LL | | +LL | | want_F(baz); +LL | | } + | |_^ -For more information about this error, try `rustc --explain E0308`. From a2d917989c527f6ec27e32411300888c2934611a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 31 Dec 2018 13:45:48 -0500 Subject: [PATCH 12/30] WIP other test changes --- src/test/ui/coherence/coherence-subtyping.stderr | 6 +++--- src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr | 4 ++-- src/test/ui/issues/issue-22872.rs | 1 - src/test/ui/lub-glb/old-lub-glb-object.stderr | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr index 92ac829f8000b..eb68768eed072 100644 --- a/src/test/ui/coherence/coherence-subtyping.stderr +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Contravariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: - --> $DIR/coherence-subtyping.rs:21:1 + --> $DIR/coherence-subtyping.rs:11:1 | LL | impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { | -------------------------------------------------------------- first implementation here @@ -8,7 +8,7 @@ LL | impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` error[E0119]: conflicting implementations of trait `Covariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: - --> $DIR/coherence-subtyping.rs:34:1 + --> $DIR/coherence-subtyping.rs:24:1 | LL | impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { | ---------------------------------------------------------- first implementation here @@ -17,7 +17,7 @@ LL | impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` error[E0119]: conflicting implementations of trait `Invariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: - --> $DIR/coherence-subtyping.rs:47:1 + --> $DIR/coherence-subtyping.rs:37:1 | LL | impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { | ---------------------------------------------------------- first implementation here diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index 1225842665d99..bb1a828f3da4b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -11,8 +11,8 @@ LL | | fn(&'x u32)) } = note: expected type `std::option::Option fn(&'a u32)>` found type `std::option::Option` = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:23), 'a) })... -note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 48:22 - --> $DIR/hr-subtype.rs:48:22 +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 38:22 + --> $DIR/hr-subtype.rs:38:22 | LL | fn supertype<'x,'y:'x,'z:'y>() { | ^^ diff --git a/src/test/ui/issues/issue-22872.rs b/src/test/ui/issues/issue-22872.rs index a6130d21b5d39..8ef4af15bd462 100644 --- a/src/test/ui/issues/issue-22872.rs +++ b/src/test/ui/issues/issue-22872.rs @@ -19,7 +19,6 @@ pub trait Process<'a> { fn push_process

(process: P) where P: Process<'static> { let _: Box Wrap<'b>> = Box::new(Wrapper(process)); //~^ ERROR is not an iterator -//~| ERROR is not satisfied } fn main() {} diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 3a7478b73b85a..2ed180f25dc02 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,4 +1,4 @@ -error[E0308]: match arms have incompatible types +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements --> $DIR/old-lub-glb-object.rs:10:13 | LL | let z = match 22 { //~ ERROR cannot infer From 0b03b9bbcfbac0765d79efbd83b36e9970c56b49 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 31 Oct 2018 13:20:48 -0400 Subject: [PATCH 13/30] remove outdated `rustc_driver` tests they are subsumed by `hr-subtype/hr-subtype.rs` and other tests --- src/librustc_driver/test.rs | 51 ------------------------------------- 1 file changed, 51 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index a5f7d676862e0..9c027f110eb4e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -7,7 +7,6 @@ use errors::{DiagnosticBuilder, Level}; use rustc::hir; use rustc::hir::map as hir_map; use rustc::infer::outlives::env::OutlivesEnvironment; -use rustc::infer::type_variable::TypeVariableOrigin; use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors}; use rustc::middle::region; use rustc::session::config::{OutputFilenames, OutputTypes}; @@ -26,7 +25,6 @@ use syntax::ast; use syntax::feature_gate::UnstableFeatures; use syntax::source_map::{FileName, FilePathMapping, SourceMap}; use syntax::symbol::Symbol; -use syntax_pos::DUMMY_SP; use std::path::PathBuf; use std::sync::mpsc; @@ -431,17 +429,6 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } } } - - /// Checks that `t1 <: t2` is false (this may register additional - /// region checks). - pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub(t1, t2) { - Err(_) => {} - Ok(_) => { - panic!("unexpected success computing sub({:?},{:?})", t1, t2); - } - } - } } #[test] @@ -470,25 +457,6 @@ fn contravariant_region_ptr_err() { }) } -#[test] -fn sub_free_bound_false() { - //! Test that: - //! - //! fn(&'a isize) <: for<'b> fn(&'b isize) - //! - //! *does not* hold. - - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr_free1 = env.t_rptr_free(1); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - env.check_not_sub( - env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - ); - }) -} - #[test] fn sub_bound_free_true() { //! Test that: @@ -508,25 +476,6 @@ fn sub_bound_free_true() { }) } -#[test] -fn sub_free_bound_false_infer() { - //! Test that: - //! - //! fn(_#1) <: for<'b> fn(&'b isize) - //! - //! does NOT hold for any instantiation of `_#1`. - - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_infer1 = env.infcx - .next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - env.check_not_sub( - env.t_fn(&[t_infer1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - ); - }) -} - /// Test substituting a bound region into a function, which introduces another level of binding. /// This requires adjusting the Debruijn index. #[test] From 995192a472220786e22ccdf3658671d5589b30dd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 16 Nov 2018 19:13:55 -0500 Subject: [PATCH 14/30] make `get_highlight_region_for_regionvid` only affect re-vid In NLL, ReVid is all there is, but I might want to repurpose. --- src/librustc/util/ppaux.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 318d7adb19011..cbba4181271fd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -771,7 +771,7 @@ define_print! { define_print! { () ty::RegionKind, (self, f, cx) { display { - if cx.is_verbose || get_highlight_region_for_regionvid().is_some() { + if cx.is_verbose { return self.print_debug(f, cx); } @@ -806,11 +806,16 @@ define_print! { ), } } - ty::ReVar(region_vid) if cx.identify_regions => { - write!(f, "'{}rv", region_vid.index()) + ty::ReVar(region_vid) => { + if get_highlight_region_for_regionvid().is_some() { + write!(f, "{:?}", region_vid) + } else if cx.identify_regions { + write!(f, "'{}rv", region_vid.index()) + } else { + Ok(()) + } } ty::ReScope(_) | - ty::ReVar(_) | ty::ReErased => Ok(()), ty::ReStatic => write!(f, "'static"), ty::ReEmpty => write!(f, "'"), From 6a6d2f4b3f79e8f72fdf3600b4ce9a5671c6abdc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 17 Nov 2018 06:10:30 -0500 Subject: [PATCH 15/30] dump out the exact state in error reporting debugs --- src/librustc/infer/error_reporting/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e34bb9f4f7bd9..be1ec553b9f5a 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1306,6 +1306,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (&sup_origin, &sub_origin) { (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => { + debug!("report_sub_sup_conflict: var_origin={:?}", var_origin); + debug!("report_sub_sup_conflict: sub_region={:?}", sub_region); + debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin); + debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); + debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); + debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace); + debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace); + debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values); + debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values); + if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = ( self.values_str(&sup_trace.values), self.values_str(&sub_trace.values), From 37b0b3e9a36ccbf4a6baace1f5d0f3ccf738d6b9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 17 Nov 2018 06:27:44 -0500 Subject: [PATCH 16/30] generalize region highlights into a struct --- src/librustc/util/ppaux.rs | 124 +++++++++++------- .../borrow_check/error_reporting.rs | 10 +- .../error_reporting/region_name.rs | 9 +- 3 files changed, 91 insertions(+), 52 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index cbba4181271fd..ea0495c5c738c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,17 +21,87 @@ use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; +/// The "region highlights" are used to control region printing during +/// specific error messages. When a "region highlight" is enabled, it +/// gives an alternate way to print specific regions. For now, we +/// always print those regions using a number, so something like `'0`. +/// +/// Regions not selected by the region highlight mode are presently +/// unaffected. +#[derive(Copy, Clone, Default)] +pub struct RegionHighlightMode { + /// If enabled, when we see the selected region inference + /// variable, use `"'N"`; otherwise, use an empty string `""` + /// (which is our ordinary behavior). + highlight_region_vid: Option<(RegionVid, usize)>, + + /// If enabled, when printing a "free region" that originated from + /// the given `ty::BoundRegion`, print it as `'1`. Free regions that would ordinarily + /// have names print as normal. + /// + /// This is used when you have a signature like `fn foo(x: &u32, + /// y: &'a u32)` and we want to give a name to the region of the + /// reference `x`. + highlight_bound_region: Option<(ty::BoundRegion, usize)>, +} + thread_local! { /// Mechanism for highlighting of specific regions for display in NLL region inference errors. /// Contains region to highlight and counter for number to use when highlighting. - static HIGHLIGHT_REGION_FOR_REGIONVID: Cell> = Cell::new(None) + static REGION_HIGHLIGHT_MODE: Cell = + Cell::new(RegionHighlightMode::default()) } -thread_local! { - /// Mechanism for highlighting of specific regions for display in NLL's 'borrow does not live - /// long enough' errors. Contains a region to highlight and a counter to use. - static HIGHLIGHT_REGION_FOR_BOUND_REGION: Cell> = - Cell::new(None) +impl RegionHighlightMode { + pub fn get() -> Self { + REGION_HIGHLIGHT_MODE.with(|c| c.get()) + } + + fn set( + old_mode: Self, + new_mode: Self, + op: impl FnOnce() -> R, + ) -> R { + REGION_HIGHLIGHT_MODE.with(|c| { + c.set(new_mode); + let result = op(); + c.set(old_mode); + result + }) + } + + pub fn highlighting_region_vid(vid: RegionVid, number: usize, op: impl FnOnce() -> R) -> R { + let old_mode = Self::get(); + assert!(old_mode.highlight_region_vid.is_none()); + Self::set( + old_mode, + Self { + highlight_region_vid: Some((vid, number)), + ..old_mode + }, + op, + ) + } + + /// During the execution of `op`, highlight the given bound + /// region. We can only highlight one bound region at a time. See + /// the field `highlight_bound_region` for more detailed notes. + pub fn highlighting_bound_region( + br: ty::BoundRegion, + number: usize, + op: impl FnOnce() -> R, + ) -> R { + let old_mode = Self::get(); + assert!(old_mode.highlight_bound_region.is_none()); + Self::set( + old_mode, + Self { + highlight_bound_region: Some((br, number)), + ..old_mode + }, + op, + ) + } } macro_rules! gen_display_debug_body { @@ -553,42 +623,6 @@ pub fn parameterized(f: &mut F, PrintContext::new().parameterized(f, substs, did, projections) } -fn get_highlight_region_for_regionvid() -> Option<(RegionVid, usize)> { - HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| hr.get()) -} - -pub fn with_highlight_region_for_regionvid( - r: RegionVid, - counter: usize, - op: impl FnOnce() -> R -) -> R { - HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| { - assert_eq!(hr.get(), None); - hr.set(Some((r, counter))); - let r = op(); - hr.set(None); - r - }) -} - -fn get_highlight_region_for_bound_region() -> Option<(ty::BoundRegion, usize)> { - HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| hr.get()) -} - -pub fn with_highlight_region_for_bound_region( - r: ty::BoundRegion, - counter: usize, - op: impl Fn() -> R -) -> R { - HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| { - assert_eq!(hr.get(), None); - hr.set(Some((r, counter))); - let r = op(); - hr.set(None); - r - }) -} - impl<'a, T: Print> Print for &'a T { fn print(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { (*self).print(f, cx) @@ -740,7 +774,7 @@ define_print! { return self.print_debug(f, cx); } - if let Some((region, counter)) = get_highlight_region_for_bound_region() { + if let Some((region, counter)) = RegionHighlightMode::get().highlight_bound_region { if *self == region { return match *self { BrNamed(_, name) => write!(f, "{}", name), @@ -807,7 +841,7 @@ define_print! { } } ty::ReVar(region_vid) => { - if get_highlight_region_for_regionvid().is_some() { + if RegionHighlightMode::get().highlight_region_vid.is_some() { write!(f, "{:?}", region_vid) } else if cx.identify_regions { write!(f, "'{}rv", region_vid.index()) @@ -944,7 +978,7 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some((region, counter)) = get_highlight_region_for_regionvid() { + if let Some((region, counter)) = RegionHighlightMode::get().highlight_region_vid { debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter); return if *self == region { write!(f, "'{:?}", counter) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 6a5b5d172bbe4..83cd28bbdc58c 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -12,7 +12,7 @@ use rustc::mir::{ TerminatorKind, VarBindingForm, }; use rustc::ty::{self, DefIdTree}; -use rustc::util::ppaux::with_highlight_region_for_bound_region; +use rustc::util::ppaux::RegionHighlightMode; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::sync::Lrc; @@ -2177,7 +2177,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, - ) => with_highlight_region_for_bound_region(*br, counter, || ty.to_string()), + ) => RegionHighlightMode::highlighting_bound_region(*br, counter, || ty.to_string()), _ => ty.to_string(), } } @@ -2189,7 +2189,11 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { ty::TyKind::Ref(region, _, _) => match region { ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - with_highlight_region_for_bound_region(*br, counter, || region.to_string()) + RegionHighlightMode::highlighting_bound_region( + *br, + counter, + || region.to_string(), + ) } _ => region.to_string(), }, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 963d4ab3a5466..bff8015511242 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -8,7 +8,7 @@ use rustc::infer::InferCtxt; use rustc::mir::Mir; use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; -use rustc::util::ppaux::with_highlight_region_for_regionvid; +use rustc::util::ppaux::RegionHighlightMode; use rustc_errors::DiagnosticBuilder; use syntax::ast::{Name, DUMMY_NODE_ID}; use syntax::symbol::keywords; @@ -396,7 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { argument_ty: Ty<'tcx>, counter: &mut usize, ) -> Option { - let type_name = with_highlight_region_for_regionvid(needle_fr, *counter, || { + let type_name = RegionHighlightMode::highlighting_region_vid(needle_fr, *counter, || { infcx.extract_type_name(&argument_ty) }); @@ -673,8 +673,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { return None; } - let type_name = with_highlight_region_for_regionvid( - fr, *counter, || infcx.extract_type_name(&return_ty)); + let type_name = RegionHighlightMode::highlighting_region_vid( + fr, *counter, || infcx.extract_type_name(&return_ty), + ); let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir"); From 1597f2a0fca681219c1f495ed3bbe01aa889fb43 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 17 Nov 2018 07:03:26 -0500 Subject: [PATCH 17/30] add the ability to highlight placeholders --- src/librustc/util/ppaux.rs | 83 +++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ea0495c5c738c..55e3f3e6f930a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -43,6 +43,13 @@ pub struct RegionHighlightMode { /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. highlight_bound_region: Option<(ty::BoundRegion, usize)>, + + /// If enabled, when printing a "placeholder" (what we get when + /// substituting a universally quantified region as in `for<'a> T: + /// Foo<'a>`), print out instead `'N`. + /// + /// (Unlike other modes, we can highlight more than one placeholder at a time.) + highlight_placeholders: [Option<(ty::PlaceholderRegion, usize)>; 2], } thread_local! { @@ -53,10 +60,12 @@ thread_local! { } impl RegionHighlightMode { + /// Read and return current region highlight settings (accesses thread-local state).a pub fn get() -> Self { REGION_HIGHLIGHT_MODE.with(|c| c.get()) } + /// Internal helper to update current settings during the execution of `op`. fn set( old_mode: Self, new_mode: Self, @@ -70,6 +79,9 @@ impl RegionHighlightMode { }) } + /// During the execution of `op`, highlight the region inference + /// vairable `vid` as `'N`. We can only highlight one region vid + /// at a time. pub fn highlighting_region_vid(vid: RegionVid, number: usize, op: impl FnOnce() -> R) -> R { let old_mode = Self::get(); assert!(old_mode.highlight_region_vid.is_none()); @@ -102,6 +114,52 @@ impl RegionHighlightMode { op, ) } + + /// During the execution of `op`, highlight the given placeholders + /// with the given numbers. Unlike other modes: non-highlighted + /// placeholders are printed as `'_` (where they might normally print + /// differently. This may want to be tweaked; but we do it for two reasons + /// + /// (a) to draw attention to the placeholders we are trying to highlight + /// (b) because placeholder names can come from other scopes than the one + /// in which the error occurred, so that can be misleading. + /// + /// We can highlight up to two placeholders at a time. + pub fn highlighting_placeholder( + placeholder: ty::PlaceholderRegion, + number: usize, + op: impl FnOnce() -> R, + ) -> R { + let old_mode = Self::get(); + let mut new_mode = old_mode; + let first_avail_slot = new_mode.highlight_placeholders.iter_mut() + .filter(|s| s.is_none()) + .next() + .unwrap_or_else(|| { + panic!( + "can only highlight {} placeholders at a time", + old_mode.highlight_placeholders.len(), + ) + }); + *first_avail_slot = Some((placeholder, number)); + Self::set(old_mode, new_mode, op) + } + + /// Returns true if any placeholders are highlighted. + pub fn any_placeholders_highlighted(&self) -> bool { + self.highlight_placeholders.iter().any(|p| p.is_some()) + } + + /// Returns `Some(N)` if the placeholder `p` is highlighted to print as `'N`. + pub fn placeholder_highlight(&self, p: ty::PlaceholderRegion) -> Option { + self.highlight_placeholders + .iter() + .filter_map(|h| match h { + &Some((h, n)) if h == p => Some(n), + _ => None, + }) + .next() + } } macro_rules! gen_display_debug_body { @@ -802,6 +860,25 @@ define_print! { } } +define_print! { + () ty::PlaceholderRegion, (self, f, cx) { + display { + if cx.is_verbose { + return self.print_debug(f, cx); + } + + let highlight = RegionHighlightMode::get(); + if let Some(counter) = highlight.placeholder_highlight(*self) { + write!(f, "'{}", counter) + } else if highlight.any_placeholders_highlighted() { + write!(f, "'_") + } else { + write!(f, "{}", self.name) + } + } + } +} + define_print! { () ty::RegionKind, (self, f, cx) { display { @@ -818,10 +895,12 @@ define_print! { write!(f, "{}", data.name) } ty::ReLateBound(_, br) | - ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { + ty::ReFree(ty::FreeRegion { bound_region: br, .. }) => { write!(f, "{}", br) } + ty::RePlaceholder(p) => { + write!(f, "{}", p) + } ty::ReScope(scope) if cx.identify_regions => { match scope.data { region::ScopeData::Node => From 0a61d682a194954494df3cdefb926172c5d423c4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 17 Nov 2018 08:18:37 -0500 Subject: [PATCH 18/30] introduce placeholder-placeholder errors for trait matching --- src/librustc/infer/error_reporting/mod.rs | 3 +- .../error_reporting/nice_region_error/mod.rs | 8 +- .../nice_region_error/outlives_closure.rs | 3 +- .../nice_region_error/placeholder_error.rs | 223 ++++++++++++++++++ .../nice_region_error/static_impl_trait.rs | 1 + .../infer/lexical_region_resolve/mod.rs | 8 +- .../associated-types-eq-hr.rs | 8 +- .../associated-types-eq-hr.stderr | 63 ++--- src/test/ui/generator/auto-trait-regions.rs | 3 +- .../ui/generator/auto-trait-regions.stderr | 26 +- src/test/ui/hrtb/hrtb-conflate-regions.stderr | 11 +- .../hrtb-exists-forall-trait-invariant.rs | 2 +- .../hrtb-exists-forall-trait-invariant.stderr | 13 +- 13 files changed, 273 insertions(+), 99 deletions(-) create mode 100644 src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index be1ec553b9f5a..d0cb718f55a25 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -339,6 +339,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } RegionResolutionError::SubSupConflict( + _, var_origin, sub_origin, sub_r, @@ -407,7 +408,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { errors.sort_by_key(|u| match *u { RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(), + RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), }); errors } diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index ecf59daeaf12e..f7ba546fa7f3b 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -8,6 +8,7 @@ use util::common::ErrorReported; mod different_lifetimes; mod find_anon_type; mod named_anon_conflict; +mod placeholder_error; mod outlives_closure; mod static_impl_trait; mod util; @@ -58,10 +59,11 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> { // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of // the nice region errors are required when running under the MIR borrow checker. self.try_report_named_anon_conflict() + .or_else(|| self.try_report_placeholder_conflict()) } pub fn try_report(&self) -> Option { - self.try_report_named_anon_conflict() + self.try_report_from_nll() .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_outlives_closure()) .or_else(|| self.try_report_static_impl_trait()) @@ -69,8 +71,8 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> { pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) { match (&self.error, self.regions) { - (&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup), - (&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup), + (Some(ConcreteFailure(origin, sub, sup)), None) => (origin.span(), sub, sup), + (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => (origin.span(), sub, sup), (None, Some((span, sub, sup))) => (span, sub, sup), (Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"), _ => panic!("trying to report on an incorrect lifetime failure"), diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs index 789796d95cb14..c4c71037d8b35 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -36,7 +36,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { /// ...because it cannot outlive this closure /// ``` pub(super) fn try_report_outlives_closure(&self) -> Option { - if let Some(SubSupConflict(origin, + if let Some(SubSupConflict(_, + origin, ref sub_origin, _, ref sup_origin, diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs new file mode 100644 index 0000000000000..f5e9f3814b467 --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -0,0 +1,223 @@ +use hir::def_id::DefId; +use infer::error_reporting::nice_region_error::NiceRegionError; +use infer::lexical_region_resolve::RegionResolutionError; +use infer::ValuePairs; +use infer::{SubregionOrigin, TypeTrace}; +use traits::{ObligationCause, ObligationCauseCode}; +use ty; +use ty::error::ExpectedFound; +use ty::subst::Substs; +use util::common::ErrorReported; +use util::ppaux::RegionHighlightMode; + +impl NiceRegionError<'me, 'gcx, 'tcx> { + /// When given a `ConcreteFailure` for a function with arguments containing a named region and + /// an anonymous region, emit an descriptive diagnostic error. + pub(super) fn try_report_placeholder_conflict(&self) -> Option { + // Check for the first case: relating two trait-refs, and we + // find a conflict between two placeholders. + match &self.error { + Some(RegionResolutionError::SubSupConflict( + vid, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + ty::RePlaceholder(sub_placeholder), + _, + ty::RePlaceholder(sup_placeholder), + )) => if expected.def_id == found.def_id { + return Some(self.try_report_two_placeholders_trait( + Some(*vid), + cause, + Some(*sub_placeholder), + Some(*sup_placeholder), + expected.def_id, + expected.substs, + found.substs, + )); + } else { + // I actually can't see why this would be the case ever. + }, + + _ => {} + } + + None + } + + // error[E0308]: implementation of `Foo` does not apply to enough lifetimes + // --> /home/nmatsakis/tmp/foo.rs:12:5 + // | + // 12 | all::<&'static u32>(); + // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch + // | + // = note: Due to a where-clause on the function `all`, + // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`. + // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. + fn try_report_two_placeholders_trait( + &self, + vid: Option, + cause: &ObligationCause<'tcx>, + sub_placeholder: Option, + sup_placeholder: Option, + trait_def_id: DefId, + expected_substs: &'tcx Substs<'tcx>, + actual_substs: &'tcx Substs<'tcx>, + ) -> ErrorReported { + let mut err = self.tcx.sess.struct_span_err( + cause.span(&self.tcx), + &format!( + "implementation of `{}` is not general enough", + self.tcx.item_path_str(trait_def_id), + ), + ); + + match cause.code { + ObligationCauseCode::ItemObligation(def_id) => { + err.note(&format!( + "Due to a where-clause on `{}`,", + self.tcx.item_path_str(def_id), + )); + } + _ => (), + } + + let expected_trait_ref = ty::TraitRef { + def_id: trait_def_id, + substs: expected_substs, + }; + let actual_trait_ref = ty::TraitRef { + def_id: trait_def_id, + substs: actual_substs, + }; + + // Search the expected and actual trait references to see (a) + // whether the sub/sup placeholders appear in them (sometimes + // you have a trait ref like `T: Foo`, where the + // placeholder was created as part of an inner type) and (b) + // whether the inference variable appears. In each case, + // assign a counter value in each case if so. + let mut counter = 0; + let mut has_sub = None; + let mut has_sup = None; + let mut has_vid = None; + + self.tcx + .for_each_free_region(&expected_trait_ref, |r| match r { + ty::RePlaceholder(p) => { + if Some(*p) == sub_placeholder { + if has_sub.is_none() { + has_sub = Some(counter); + counter += 1; + } + } else if Some(*p) == sup_placeholder { + if has_sup.is_none() { + has_sup = Some(counter); + counter += 1; + } + } + } + _ => {} + }); + + self.tcx + .for_each_free_region(&actual_trait_ref, |r| match r { + ty::ReVar(v) if Some(*v) == vid => { + if has_vid.is_none() { + has_vid = Some(counter); + counter += 1; + } + } + _ => {} + }); + + maybe_highlight( + sub_placeholder, + has_sub, + RegionHighlightMode::highlighting_placeholder, + || { + maybe_highlight( + sup_placeholder, + has_sup, + RegionHighlightMode::highlighting_placeholder, + || match (has_sub, has_sup) { + (Some(n1), Some(n2)) => { + err.note(&format!( + "`{}` must implement `{}` \ + for any two lifetimes `'{}` and `'{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + std::cmp::min(n1, n2), + std::cmp::max(n1, n2), + )); + } + (Some(n), _) | (_, Some(n)) => { + err.note(&format!( + "`{}` must implement `{}` \ + for any lifetime `'{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + n, + )); + } + (None, None) => { + err.note(&format!( + "`{}` must implement `{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + )); + } + }, + ) + }, + ); + + maybe_highlight( + vid, + has_vid, + RegionHighlightMode::highlighting_region_vid, + || match has_vid { + Some(n) => { + err.note(&format!( + "but `{}` only implements `{}` for some lifetime `'{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + n + )); + } + None => { + err.note(&format!( + "but `{}` only implements `{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + )); + } + }, + ); + + err.emit(); + ErrorReported + } +} + +/// If both `thing` and `counter` are `Some`, invoke +/// `highlighting_func` with their contents (and the `op`). Else just +/// invoke `op`. +fn maybe_highlight( + thing: Option, + counter: Option, + highlighting_func: impl FnOnce(T, usize, F) -> R, + op: F, +) -> R +where + F: FnOnce() -> R, +{ + if let Some(thing) = thing { + if let Some(n) = counter { + return highlighting_func(thing, n, op); + } + } + op() +} diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs index 6d2d2ee93ab50..9fc3bb05cdab1 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -11,6 +11,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { pub(super) fn try_report_static_impl_trait(&self) -> Option { if let Some(ref error) = self.error { if let RegionResolutionError::SubSupConflict( + _, var_origin, sub_origin, sub_r, diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index bbab17f951659..dbf8f270ab0c9 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -73,12 +73,13 @@ pub enum RegionResolutionError<'tcx> { /// `a` (but none of the known bounds are sufficient). GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>), - /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: + /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`: /// - /// Could not infer a value for `v` because `sub_r <= v` (due to - /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and + /// Could not infer a value for `v` (which has origin `v_origin`) + /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and /// `sub_r <= sup_r` does not hold. SubSupConflict( + RegionVid, RegionVariableOrigin, SubregionOrigin<'tcx>, Region<'tcx>, @@ -596,6 +597,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { origin, node_idx, lower_bound.region, upper_bound.region ); errors.push(RegionResolutionError::SubSupConflict( + node_idx, origin, lower_bound.origin.clone(), lower_bound.region, diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs index bc7888f74af22..20fa1e7a48db1 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.rs +++ b/src/test/ui/associated-types/associated-types-eq-hr.rs @@ -89,14 +89,12 @@ pub fn call_bar() { pub fn call_tuple_one() { tuple_one::(); - //~^ ERROR E0495 - //~| ERROR E0495 + //~^ ERROR not general enough } pub fn call_tuple_two() { tuple_two::(); - //~^ ERROR E0495 - //~| ERROR E0495 + //~^ ERROR not general enough } pub fn call_tuple_three() { @@ -105,7 +103,7 @@ pub fn call_tuple_three() { pub fn call_tuple_four() { tuple_four::(); - //~^ ERROR E0495 + //~^ ERROR not general enough } fn main() { } diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 226733da0f63f..d3eaa894b5043 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -34,67 +34,36 @@ LL | | // ok for UintStruct, but not IntStruct LL | | } | |_^ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:91:5 | LL | tuple_one::(); | ^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:20), 'x) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:21), 'y) })... - = note: ...so that the types are compatible: - expected TheTrait<(&'x isize, &'y isize)> - found TheTrait<(&isize, &isize)> + = note: Due to a where-clause on `tuple_one`, + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1` + = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/associated-types-eq-hr.rs:91:5 - | -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ - | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:20), 'x) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:21), 'y) })... - = note: ...so that the types are compatible: - expected TheTrait<(&'x isize, &'y isize)> - found TheTrait<(&isize, &isize)> - -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/associated-types-eq-hr.rs:97:5 - | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ - | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:23), 'x) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:24), 'y) })... - = note: ...so that the types are compatible: - expected TheTrait<(&'x isize, &'y isize)> - found TheTrait<(&isize, &isize)> - -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/associated-types-eq-hr.rs:97:5 +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:96:5 | LL | tuple_two::(); | ^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:23), 'x) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:24), 'y) })... - = note: ...so that the types are compatible: - expected TheTrait<(&'x isize, &'y isize)> - found TheTrait<(&isize, &isize)> + = note: Due to a where-clause on `tuple_two`, + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1` + = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/associated-types-eq-hr.rs:107:5 +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:105:5 | LL | tuple_four::(); | ^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:28), 'x) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:29), 'y) })... - = note: ...so that the types are compatible: - expected TheTrait<(&'x isize, &'y isize)> - found TheTrait<(&isize, &isize)> + = note: Due to a where-clause on `tuple_four`, + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1` + = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2` -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors occurred: E0271, E0495. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 4523e05696a2b..5b52bf3cd04b9 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -47,6 +47,5 @@ fn main() { assert_foo(a); }; assert_foo(gen); - //~^ ERROR E0495 - //~| ERROR E0495 + //~^ ERROR not general enough } diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 3998ffe2522b4..6f748a740328a 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -20,31 +20,15 @@ LL | assert_foo(gen); = note: lifetime RePlaceholder(Placeholder { universe: U35, name: BrAnon(1) })... = note: ...does not necessarily outlive the static lifetime -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:49:5 | LL | assert_foo(gen); | ^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U47, name: BrAnon(2) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U47, name: BrAnon(1) })... - = note: ...so that the types are compatible: - expected Foo - found Foo + = note: `A<'0, '1>` must implement `Foo` for any two lifetimes `'0` and `'1` + = note: but `A<'_, '2>` only implements `Foo` for some lifetime `'2` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements - --> $DIR/auto-trait-regions.rs:49:5 - | -LL | assert_foo(gen); - | ^^^^^^^^^^ - | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U51, name: BrAnon(2) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U51, name: BrAnon(1) })... - = note: ...so that the types are compatible: - expected Foo - found Foo - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0308, E0495. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 24d374e470e32..2ee398e3dd3b2 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,15 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:28:10 | LL | fn b() { want_foo2::(); } //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'a) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:12), 'b) })... - = note: ...so that the types are compatible: - expected Foo<(&'a isize, &'b isize)> - found Foo<(&isize, &isize)> + = note: Due to a where-clause on `want_foo2`, + = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1` + = note: but `SomeStruct` only implements `Foo<(&'2 isize, &'2 isize)>` for some lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs index db589548d0e8e..da3f8ad1b8957 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs @@ -25,5 +25,5 @@ fn main() { // yielding `fn(&!b u32)`, in a fresh universe U1 // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. - foo::<()>(); //~ ERROR cannot infer + foo::<()>(); //~ ERROR not general enough } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index 7a0986ccdd939..6a61181e2407c 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -1,15 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | -LL | foo::<()>(); //~ ERROR cannot infer +LL | foo::<()>(); //~ ERROR not general enough | ^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })... - = note: ...so that the types are compatible: - expected Trait fn(std::cell::Cell<&'b u32>)> - found Trait)> + = note: Due to a where-clause on `foo`, + = note: `()` must implement `Trait fn(std::cell::Cell<&'b u32>)>` + = note: but `()` only implements `Trait)>` for some lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. From 6cbbee1dc7ec5c680bb5c83af0aa1b16b3a03cc0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 18 Nov 2018 13:25:53 -0500 Subject: [PATCH 19/30] apply the new placeholder errors even with just one placeholder --- .../nice_region_error/placeholder_error.rs | 52 ++++++++++++++++++- .../ui/hrtb/hrtb-cache-issue-54302.stderr | 10 ++-- src/test/ui/hrtb/hrtb-just-for-static.rs | 6 +++ src/test/ui/hrtb/hrtb-just-for-static.stderr | 12 ++++- src/test/ui/issues/issue-54302-cases.rs | 8 +-- src/test/ui/issues/issue-54302-cases.stderr | 37 +++++-------- src/test/ui/issues/issue-54302.rs | 2 +- src/test/ui/issues/issue-54302.stderr | 10 ++-- 8 files changed, 90 insertions(+), 47 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index f5e9f3814b467..83fe3da70775d 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -28,7 +28,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { _, ty::RePlaceholder(sup_placeholder), )) => if expected.def_id == found.def_id { - return Some(self.try_report_two_placeholders_trait( + return Some(self.try_report_placeholders_trait( Some(*vid), cause, Some(*sub_placeholder), @@ -41,6 +41,54 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { // I actually can't see why this would be the case ever. }, + Some(RegionResolutionError::SubSupConflict( + vid, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + ty::RePlaceholder(sub_placeholder), + _, + _, + )) => if expected.def_id == found.def_id { + return Some(self.try_report_placeholders_trait( + Some(*vid), + cause, + Some(*sub_placeholder), + None, + expected.def_id, + expected.substs, + found.substs, + )); + } else { + // I actually can't see why this would be the case ever. + }, + + Some(RegionResolutionError::SubSupConflict( + vid, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + _, + _, + ty::RePlaceholder(sup_placeholder), + )) => if expected.def_id == found.def_id { + return Some(self.try_report_placeholders_trait( + Some(*vid), + cause, + None, + Some(*sup_placeholder), + expected.def_id, + expected.substs, + found.substs, + )); + } else { + // I actually can't see why this would be the case ever. + }, + _ => {} } @@ -56,7 +104,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { // = note: Due to a where-clause on the function `all`, // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`. // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. - fn try_report_two_placeholders_trait( + fn try_report_placeholders_trait( &self, vid: Option, cause: &ObligationCause<'tcx>, diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr index 940a6e3f06853..e82fa51524ef1 100644 --- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -1,15 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements +error: implementation of `Deserialize` is not general enough --> $DIR/hrtb-cache-issue-54302.rs:19:5 | LL | assert_deserialize_owned::<&'static str>(); //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'de) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Deserialize<'de> - found Deserialize<'_> + = note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0` + = note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.rs b/src/test/ui/hrtb/hrtb-just-for-static.rs index 3aee241ccd2d7..88d5ce8e64056 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.rs +++ b/src/test/ui/hrtb/hrtb-just-for-static.rs @@ -24,4 +24,10 @@ fn give_static() { want_hrtb::() //~ ERROR } +// AnyInt implements Foo<&'a isize> for any 'a, so it is a match. +impl<'a> Foo<&'a isize> for &'a u32 { } +fn give_some<'a>() { + want_hrtb::<&'a u32>() //~ ERROR +} + fn main() { } diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index d3c2f7d059a6f..6ea415c1734b2 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -9,6 +9,16 @@ LL | want_hrtb::() //~ ERROR = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'a) })... = note: ...does not necessarily outlive the static lifetime -error: aborting due to previous error +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-just-for-static.rs:30:5 + | +LL | want_hrtb::<&'a u32>() //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: Due to a where-clause on `want_hrtb`, + = note: `&'a u32` must implement `Foo<&'0 isize>` for any lifetime `'0` + = note: but `&'1 u32` only implements `Foo<&'1 isize>` for some lifetime `'1` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-54302-cases.rs b/src/test/ui/issues/issue-54302-cases.rs index 286d37b182e31..faa116269ee96 100644 --- a/src/test/ui/issues/issue-54302-cases.rs +++ b/src/test/ui/issues/issue-54302-cases.rs @@ -61,25 +61,25 @@ impl RefFoo for T where for<'a> &'a T: Foo<'static, T> { fn coerce_lifetime1(a: &u32) -> &'static u32 { >::ref_foo(a) - //~^ ERROR cannot infer + //~^ ERROR not general enough } fn coerce_lifetime2(a: &i32) -> &'static i32 { >::ref_foo(a) - //~^ ERROR cannot infer + //~^ ERROR not general enough } fn coerce_lifetime3(a: &u64) -> &'static u64 { >::ref_foo(a) - //~^ ERROR cannot infer + //~^ ERROR not general enough } fn coerce_lifetime4(a: &i64) -> &'static i64 { >::ref_foo(a) - //~^ ERROR cannot infer + //~^ ERROR not general enough } fn main() {} diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr index 09a4e091d2bcf..6469829e789b4 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -1,51 +1,38 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:63:5 | LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Foo<'static, u32> - found Foo<'_, u32> + = note: `&'0 u32` must implement `Foo<'static, u32>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 | LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Foo<'static, i32> - found Foo<'_, i32> + = note: `&'0 i32` must implement `Foo<'static, i32>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 | LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Foo<'static, u64> - found Foo<'_, u64> + = note: `&'0 u64` must implement `Foo<'static, u64>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements +error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 | LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:27), 'a) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Foo<'static, i64> - found Foo<'_, i64> + = note: `&'0 i64` must implement `Foo<'static, i64>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-54302.rs b/src/test/ui/issues/issue-54302.rs index 35cdc73a78fd0..1bfaebc3895d9 100644 --- a/src/test/ui/issues/issue-54302.rs +++ b/src/test/ui/issues/issue-54302.rs @@ -11,7 +11,7 @@ fn main() { // Then why does it implement DeserializeOwned? This compiles. fn assert_deserialize_owned() {} assert_deserialize_owned::<&'static str>(); - //~^ ERROR E0495 + //~^ ERROR not general enough // It correctly does not implement for<'de> Deserialize<'de>. //fn assert_hrtb Deserialize<'de>>() {} diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr index b456d2582ffd6..1b255204b6ef7 100644 --- a/src/test/ui/issues/issue-54302.stderr +++ b/src/test/ui/issues/issue-54302.stderr @@ -1,15 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements +error: implementation of `Deserialize` is not general enough --> $DIR/issue-54302.rs:13:5 | LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'de) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the types are compatible: - expected Deserialize<'de> - found Deserialize<'_> + = note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0` + = note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. From 77924de4a66b55d2c863cf66ff9f427d3ae79788 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 18 Nov 2018 15:25:57 -0500 Subject: [PATCH 20/30] refactor highlighting to take any RegionKind, making it more general --- .../nice_region_error/placeholder_error.rs | 197 +++++++----------- src/librustc/util/ppaux.rs | 150 +++++++------ 2 files changed, 160 insertions(+), 187 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index 83fe3da70775d..4fd1a97007682 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -24,15 +24,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), - ty::RePlaceholder(sub_placeholder), + sub_placeholder @ ty::RePlaceholder(_), _, - ty::RePlaceholder(sup_placeholder), + sup_placeholder @ ty::RePlaceholder(_), )) => if expected.def_id == found.def_id { return Some(self.try_report_placeholders_trait( - Some(*vid), + Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, - Some(*sub_placeholder), - Some(*sup_placeholder), + Some(sub_placeholder), + Some(sup_placeholder), expected.def_id, expected.substs, found.substs, @@ -48,14 +48,14 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), - ty::RePlaceholder(sub_placeholder), + sub_placeholder @ ty::RePlaceholder(_), _, _, )) => if expected.def_id == found.def_id { return Some(self.try_report_placeholders_trait( - Some(*vid), + Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, - Some(*sub_placeholder), + Some(sub_placeholder), None, expected.def_id, expected.substs, @@ -74,10 +74,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { }), _, _, - ty::RePlaceholder(sup_placeholder), + sup_placeholder @ ty::RePlaceholder(_), )) => if expected.def_id == found.def_id { return Some(self.try_report_placeholders_trait( - Some(*vid), + Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, None, Some(*sup_placeholder), @@ -106,10 +106,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. fn try_report_placeholders_trait( &self, - vid: Option, + vid: Option>, cause: &ObligationCause<'tcx>, - sub_placeholder: Option, - sup_placeholder: Option, + sub_placeholder: Option>, + sup_placeholder: Option>, trait_def_id: DefId, expected_substs: &'tcx Substs<'tcx>, actual_substs: &'tcx Substs<'tcx>, @@ -152,120 +152,75 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { let mut has_sup = None; let mut has_vid = None; - self.tcx - .for_each_free_region(&expected_trait_ref, |r| match r { - ty::RePlaceholder(p) => { - if Some(*p) == sub_placeholder { - if has_sub.is_none() { - has_sub = Some(counter); - counter += 1; - } - } else if Some(*p) == sup_placeholder { - if has_sup.is_none() { - has_sup = Some(counter); - counter += 1; - } - } - } - _ => {} - }); + self.tcx.for_each_free_region(&expected_trait_ref, |r| { + if Some(r) == sub_placeholder && has_sub.is_none() { + has_sub = Some(counter); + counter += 1; + } else if Some(r) == sup_placeholder && has_sup.is_none() { + has_sup = Some(counter); + counter += 1; + } + }); - self.tcx - .for_each_free_region(&actual_trait_ref, |r| match r { - ty::ReVar(v) if Some(*v) == vid => { - if has_vid.is_none() { - has_vid = Some(counter); - counter += 1; + self.tcx.for_each_free_region(&actual_trait_ref, |r| { + if Some(r) == vid && has_vid.is_none() { + has_vid = Some(counter); + counter += 1; + } + }); + + RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || { + RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || { + match (has_sub, has_sup) { + (Some(n1), Some(n2)) => { + err.note(&format!( + "`{}` must implement `{}` \ + for any two lifetimes `'{}` and `'{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + std::cmp::min(n1, n2), + std::cmp::max(n1, n2), + )); + } + (Some(n), _) | (_, Some(n)) => { + err.note(&format!( + "`{}` must implement `{}` \ + for any lifetime `'{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + n, + )); + } + (None, None) => { + err.note(&format!( + "`{}` must implement `{}`", + expected_trait_ref.self_ty(), + expected_trait_ref, + )); } } - _ => {} - }); - - maybe_highlight( - sub_placeholder, - has_sub, - RegionHighlightMode::highlighting_placeholder, - || { - maybe_highlight( - sup_placeholder, - has_sup, - RegionHighlightMode::highlighting_placeholder, - || match (has_sub, has_sup) { - (Some(n1), Some(n2)) => { - err.note(&format!( - "`{}` must implement `{}` \ - for any two lifetimes `'{}` and `'{}`", - expected_trait_ref.self_ty(), - expected_trait_ref, - std::cmp::min(n1, n2), - std::cmp::max(n1, n2), - )); - } - (Some(n), _) | (_, Some(n)) => { - err.note(&format!( - "`{}` must implement `{}` \ - for any lifetime `'{}`", - expected_trait_ref.self_ty(), - expected_trait_ref, - n, - )); - } - (None, None) => { - err.note(&format!( - "`{}` must implement `{}`", - expected_trait_ref.self_ty(), - expected_trait_ref, - )); - } - }, - ) - }, - ); + }) + }); - maybe_highlight( - vid, - has_vid, - RegionHighlightMode::highlighting_region_vid, - || match has_vid { - Some(n) => { - err.note(&format!( - "but `{}` only implements `{}` for some lifetime `'{}`", - actual_trait_ref.self_ty(), - actual_trait_ref, - n - )); - } - None => { - err.note(&format!( - "but `{}` only implements `{}`", - actual_trait_ref.self_ty(), - actual_trait_ref, - )); - } - }, - ); + RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid { + Some(n) => { + err.note(&format!( + "but `{}` only implements `{}` for some lifetime `'{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + n + )); + } + None => { + err.note(&format!( + "but `{}` only implements `{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + )); + } + }); err.emit(); ErrorReported } } - -/// If both `thing` and `counter` are `Some`, invoke -/// `highlighting_func` with their contents (and the `op`). Else just -/// invoke `op`. -fn maybe_highlight( - thing: Option, - counter: Option, - highlighting_func: impl FnOnce(T, usize, F) -> R, - op: F, -) -> R -where - F: FnOnce() -> R, -{ - if let Some(thing) = thing { - if let Some(n) = counter { - return highlighting_func(thing, n, op); - } - } - op() -} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 55e3f3e6f930a..0742d0aebe954 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -9,7 +9,7 @@ use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; use ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; use ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; -use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; +use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; use std::cell::Cell; @@ -30,10 +30,9 @@ use hir; /// unaffected. #[derive(Copy, Clone, Default)] pub struct RegionHighlightMode { - /// If enabled, when we see the selected region inference - /// variable, use `"'N"`; otherwise, use an empty string `""` - /// (which is our ordinary behavior). - highlight_region_vid: Option<(RegionVid, usize)>, + /// If enabled, when we see the selected region, use `"'N"` + /// instead of the ordinary behavior. + highlight_regions: [Option<(ty::RegionKind, usize)>; 3], /// If enabled, when printing a "free region" that originated from /// the given `ty::BoundRegion`, print it as `'1`. Free regions that would ordinarily @@ -43,13 +42,6 @@ pub struct RegionHighlightMode { /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. highlight_bound_region: Option<(ty::BoundRegion, usize)>, - - /// If enabled, when printing a "placeholder" (what we get when - /// substituting a universally quantified region as in `for<'a> T: - /// Foo<'a>`), print out instead `'N`. - /// - /// (Unlike other modes, we can highlight more than one placeholder at a time.) - highlight_placeholders: [Option<(ty::PlaceholderRegion, usize)>; 2], } thread_local! { @@ -79,20 +71,72 @@ impl RegionHighlightMode { }) } + /// If `region` and `number` are both `Some`, invoke + /// `highlighting_region`. Otherwise, just invoke `op` directly. + pub fn maybe_highlighting_region( + region: Option>, + number: Option, + op: impl FnOnce() -> R, + ) -> R { + if let Some(k) = region { + if let Some(n) = number { + return Self::highlighting_region(k, n, op); + } + } + + op() + } + /// During the execution of `op`, highlight the region inference /// vairable `vid` as `'N`. We can only highlight one region vid /// at a time. - pub fn highlighting_region_vid(vid: RegionVid, number: usize, op: impl FnOnce() -> R) -> R { + pub fn highlighting_region(region: ty::Region<'_>, number: usize, op: impl FnOnce() -> R) -> R { let old_mode = Self::get(); - assert!(old_mode.highlight_region_vid.is_none()); - Self::set( - old_mode, - Self { - highlight_region_vid: Some((vid, number)), - ..old_mode - }, - op, - ) + let mut new_mode = old_mode; + let first_avail_slot = new_mode.highlight_regions.iter_mut() + .filter(|s| s.is_none()) + .next() + .unwrap_or_else(|| { + panic!( + "can only highlight {} placeholders at a time", + old_mode.highlight_regions.len(), + ) + }); + *first_avail_slot = Some((*region, number)); + Self::set(old_mode, new_mode, op) + } + + /// Convenience wrapper for `highlighting_region` + pub fn highlighting_region_vid( + vid: ty::RegionVid, + number: usize, + op: impl FnOnce() -> R, + ) -> R { + Self::highlighting_region(&ty::ReVar(vid), number, op) + } + + /// Returns true if any placeholders are highlighted. + fn any_region_vids_highlighted(&self) -> bool { + Self::get() + .highlight_regions + .iter() + .any(|h| match h { + Some((ty::ReVar(_), _)) => true, + _ => false, + }) + } + + /// Returns `Some(n)` with the number to use for the given region, + /// if any. + fn region_highlighted(&self, region: ty::Region<'_>) -> Option { + Self::get() + .highlight_regions + .iter() + .filter_map(|h| match h { + Some((r, n)) if r == region => Some(*n), + _ => None, + }) + .next() } /// During the execution of `op`, highlight the given bound @@ -115,50 +159,20 @@ impl RegionHighlightMode { ) } - /// During the execution of `op`, highlight the given placeholders - /// with the given numbers. Unlike other modes: non-highlighted - /// placeholders are printed as `'_` (where they might normally print - /// differently. This may want to be tweaked; but we do it for two reasons - /// - /// (a) to draw attention to the placeholders we are trying to highlight - /// (b) because placeholder names can come from other scopes than the one - /// in which the error occurred, so that can be misleading. - /// - /// We can highlight up to two placeholders at a time. - pub fn highlighting_placeholder( - placeholder: ty::PlaceholderRegion, - number: usize, - op: impl FnOnce() -> R, - ) -> R { - let old_mode = Self::get(); - let mut new_mode = old_mode; - let first_avail_slot = new_mode.highlight_placeholders.iter_mut() - .filter(|s| s.is_none()) - .next() - .unwrap_or_else(|| { - panic!( - "can only highlight {} placeholders at a time", - old_mode.highlight_placeholders.len(), - ) - }); - *first_avail_slot = Some((placeholder, number)); - Self::set(old_mode, new_mode, op) - } - /// Returns true if any placeholders are highlighted. pub fn any_placeholders_highlighted(&self) -> bool { - self.highlight_placeholders.iter().any(|p| p.is_some()) + Self::get() + .highlight_regions + .iter() + .any(|h| match h { + Some((ty::RePlaceholder(_), _)) => true, + _ => false, + }) } /// Returns `Some(N)` if the placeholder `p` is highlighted to print as `'N`. pub fn placeholder_highlight(&self, p: ty::PlaceholderRegion) -> Option { - self.highlight_placeholders - .iter() - .filter_map(|h| match h { - &Some((h, n)) if h == p => Some(n), - _ => None, - }) - .next() + self.region_highlighted(&ty::RePlaceholder(p)) } } @@ -886,6 +900,11 @@ define_print! { return self.print_debug(f, cx); } + // Watch out for region highlights. + if let Some(n) = RegionHighlightMode::get().region_highlighted(self) { + return write!(f, "'{:?}", n); + } + // These printouts are concise. They do not contain all the information // the user might want to diagnose an error, but there is basically no way // to fit that into a short string. Hence the recommendation to use @@ -920,7 +939,7 @@ define_print! { } } ty::ReVar(region_vid) => { - if RegionHighlightMode::get().highlight_region_vid.is_some() { + if RegionHighlightMode::get().any_region_vids_highlighted() { write!(f, "{:?}", region_vid) } else if cx.identify_regions { write!(f, "'{}rv", region_vid.index()) @@ -1057,12 +1076,11 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some((region, counter)) = RegionHighlightMode::get().highlight_region_vid { - debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter); - return if *self == region { - write!(f, "'{:?}", counter) + if RegionHighlightMode::get().any_region_vids_highlighted() { + if let Some(counter) = RegionHighlightMode::get().region_highlighted(&ty::ReVar(*self)) { + return write!(f, "'{:?}", counter); } else { - write!(f, "'_") + return write!(f, "'_"); } } From 7bc3f5585aef5eba62f752eaaf89247972769109 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 18 Nov 2018 19:07:38 -0500 Subject: [PATCH 21/30] apply the same logic to ConcreteFailure errors --- .../nice_region_error/placeholder_error.rs | 50 +++++++++++++++++++ src/test/ui/generator/auto-trait-regions.rs | 3 +- .../ui/generator/auto-trait-regions.stderr | 26 +++------- src/test/ui/hrtb/hrtb-just-for-static.stderr | 12 ++--- src/test/ui/where-clauses/where-for-self-2.rs | 2 +- .../ui/where-clauses/where-for-self-2.stderr | 14 +++--- 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index 4fd1a97007682..4e59c8c43dc09 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -89,6 +89,56 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { // I actually can't see why this would be the case ever. }, + Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(TypeTrace { .. }), + ty::RePlaceholder(_), + ty::RePlaceholder(_), + )) => { + // I actually can't see why this would be the case ever. + }, + + Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_region, + sup_region @ ty::RePlaceholder(_), + )) => if expected.def_id == found.def_id { + return Some(self.try_report_placeholders_trait( + Some(sub_region), + cause, + None, + Some(*sup_region), + expected.def_id, + expected.substs, + found.substs, + )); + } else { + // I actually can't see why this would be the case ever. + }, + + Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_region @ ty::RePlaceholder(_), + sup_region, + )) => if expected.def_id == found.def_id { + return Some(self.try_report_placeholders_trait( + Some(sup_region), + cause, + None, + Some(*sub_region), + expected.def_id, + expected.substs, + found.substs, + )); + } else { + // I actually can't see why this would be the case ever. + }, + _ => {} } diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 5b52bf3cd04b9..46d7289943857 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -28,8 +28,7 @@ fn main() { assert_foo(x); }; assert_foo(gen); - //~^ ERROR mismatched types - //~| ERROR mismatched types + //~^ ERROR implementation of `Foo` is not general enough // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 6f748a740328a..94162cb9e8fb0 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,27 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/auto-trait-regions.rs:30:5 - | -LL | assert_foo(gen); - | ^^^^^^^^^^ lifetime mismatch - | - = note: expected type `Foo` - found type `Foo` - = note: lifetime RePlaceholder(Placeholder { universe: U31, name: BrAnon(1) })... - = note: ...does not necessarily outlive the static lifetime - -error[E0308]: mismatched types +error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:30:5 | LL | assert_foo(gen); - | ^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^ | - = note: expected type `Foo` - found type `Foo` - = note: lifetime RePlaceholder(Placeholder { universe: U35, name: BrAnon(1) })... - = note: ...does not necessarily outlive the static lifetime + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo` for any lifetime `'0` + = note: but `&'1 OnlyFooIfStaticRef` only implements `Foo` for some lifetime `'1` error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:49:5 + --> $DIR/auto-trait-regions.rs:48:5 | LL | assert_foo(gen); | ^^^^^^^^^^ @@ -29,6 +16,5 @@ LL | assert_foo(gen); = note: `A<'0, '1>` must implement `Foo` for any two lifetimes `'0` and `'1` = note: but `A<'_, '2>` only implements `Foo` for some lifetime `'2` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 6ea415c1734b2..ee518b956ab1c 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,13 +1,12 @@ -error[E0308]: mismatched types +error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:24:5 | LL | want_hrtb::() //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected type `Foo<&'a isize>` - found type `Foo<&'static isize>` - = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'a) })... - = note: ...does not necessarily outlive the static lifetime + = note: Due to a where-clause on `want_hrtb`, + = note: `StaticInt` must implement `Foo<&'0 isize>` for any lifetime `'0` + = note: but `StaticInt` only implements `Foo<&'1 isize>` for some lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 @@ -21,4 +20,3 @@ LL | want_hrtb::<&'a u32>() //~ ERROR error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs index c69055fe0cc82..0ce38e69f6b0f 100644 --- a/src/test/ui/where-clauses/where-for-self-2.rs +++ b/src/test/ui/where-clauses/where-for-self-2.rs @@ -18,5 +18,5 @@ fn foo(x: &T) {} fn main() { - foo(&X); //~ ERROR E0308 + foo(&X); //~ ERROR implementation of `Bar` is not general enough } diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 04d7bbabb2a57..06f3659a5c17d 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,14 +1,12 @@ -error[E0308]: mismatched types +error: implementation of `Bar` is not general enough --> $DIR/where-for-self-2.rs:21:5 | -LL | foo(&X); //~ ERROR E0308 - | ^^^ lifetime mismatch +LL | foo(&X); //~ ERROR implementation of `Bar` is not general enough + | ^^^ | - = note: expected type `Bar` - found type `Bar` - = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:10), 'a) })... - = note: ...does not necessarily outlive the static lifetime + = note: Due to a where-clause on `foo`, + = note: `&'0 _` must implement `Bar` for any lifetime `'0` + = note: but `&'1 u32` only implements `Bar` for some lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. From a24e04dff6b9b92bbec791c61a69876401d10512 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 18 Nov 2018 19:13:37 -0500 Subject: [PATCH 22/30] say "the lifetime" instead of "some lifetime" when it feels right In particular, when we want to indicate that there is a connection between the self type and the other types. --- .../nice_region_error/placeholder_error.rs | 27 ++++++++++++++----- .../ui/generator/auto-trait-regions.stderr | 4 +-- src/test/ui/hrtb/hrtb-just-for-static.stderr | 2 +- src/test/ui/issues/issue-54302-cases.stderr | 8 +++--- .../ui/where-clauses/where-for-self-2.stderr | 2 +- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index 4e59c8c43dc09..07a61eb6d776e 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -95,7 +95,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { ty::RePlaceholder(_), )) => { // I actually can't see why this would be the case ever. - }, + } Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(TypeTrace { @@ -219,6 +219,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { } }); + let self_ty_has_vid = self + .tcx + .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid); + RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || { RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || { match (has_sub, has_sup) { @@ -254,12 +258,21 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid { Some(n) => { - err.note(&format!( - "but `{}` only implements `{}` for some lifetime `'{}`", - actual_trait_ref.self_ty(), - actual_trait_ref, - n - )); + if self_ty_has_vid { + err.note(&format!( + "but `{}` only implements `{}` for the lifetime `'{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + n + )); + } else { + err.note(&format!( + "but `{}` only implements `{}` for some lifetime `'{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + n + )); + } } None => { err.note(&format!( diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 94162cb9e8fb0..1b4dfe2df1c0c 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -5,7 +5,7 @@ LL | assert_foo(gen); | ^^^^^^^^^^ | = note: `&'0 OnlyFooIfStaticRef` must implement `Foo` for any lifetime `'0` - = note: but `&'1 OnlyFooIfStaticRef` only implements `Foo` for some lifetime `'1` + = note: but `&'1 OnlyFooIfStaticRef` only implements `Foo` for the lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:48:5 @@ -14,7 +14,7 @@ LL | assert_foo(gen); | ^^^^^^^^^^ | = note: `A<'0, '1>` must implement `Foo` for any two lifetimes `'0` and `'1` - = note: but `A<'_, '2>` only implements `Foo` for some lifetime `'2` + = note: but `A<'_, '2>` only implements `Foo` for the lifetime `'2` error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index ee518b956ab1c..094c449802415 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -16,7 +16,7 @@ LL | want_hrtb::<&'a u32>() //~ ERROR | = note: Due to a where-clause on `want_hrtb`, = note: `&'a u32` must implement `Foo<&'0 isize>` for any lifetime `'0` - = note: but `&'1 u32` only implements `Foo<&'1 isize>` for some lifetime `'1` + = note: but `&'1 u32` only implements `Foo<&'1 isize>` for the lifetime `'1` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr index 6469829e789b4..c1329d331a181 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -5,7 +5,7 @@ LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `&'0 u32` must implement `Foo<'static, u32>` for any lifetime `'0` - = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 @@ -14,7 +14,7 @@ LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `&'0 i32` must implement `Foo<'static, i32>` for any lifetime `'0` - = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 @@ -23,7 +23,7 @@ LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `&'0 u64` must implement `Foo<'static, u64>` for any lifetime `'0` - = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 @@ -32,7 +32,7 @@ LL | >::ref_foo(a) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `&'0 i64` must implement `Foo<'static, i64>` for any lifetime `'0` - = note: but `&'1 _` only implements `Foo<'_, _>` for some lifetime `'1` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` error: aborting due to 4 previous errors diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 06f3659a5c17d..afc80bf4d8ee6 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -6,7 +6,7 @@ LL | foo(&X); //~ ERROR implementation of `Bar` is not general enough | = note: Due to a where-clause on `foo`, = note: `&'0 _` must implement `Bar` for any lifetime `'0` - = note: but `&'1 u32` only implements `Bar` for some lifetime `'1` + = note: but `&'1 u32` only implements `Bar` for the lifetime `'1` error: aborting due to previous error From bc4404c0b501729cc5df05544e5f0784789f4215 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Nov 2018 10:26:04 -0500 Subject: [PATCH 23/30] improve handling for subtype Still not great, but good enough to land this PR. --- src/librustc/infer/error_reporting/mod.rs | 47 ++++++-- .../nice_region_error/placeholder_error.rs | 110 ++++++++++-------- src/librustc/infer/error_reporting/note.rs | 20 ++++ src/librustc/infer/mod.rs | 2 +- src/librustc/ty/error.rs | 20 +--- src/librustc/ty/structural_impls.rs | 10 +- src/librustc/ty/sty.rs | 7 ++ .../higher-ranked-projection.bad.stderr | 22 +--- .../higher-ranked-projection.good.stderr | 2 +- .../higher-ranked-projection.rs | 2 +- .../expect-fn-supply-fn.rs | 2 +- .../expect-fn-supply-fn.stderr | 42 ++----- ...pe.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 13 +-- .../hr-subtype.bound_a_vs_free_x.stderr | 12 +- ...ubtype.bound_inv_a_b_vs_bound_inv_a.stderr | 13 +-- src/test/ui/hrtb/hrtb-exists-forall-fn.rs | 2 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 24 +--- ...igher-ranker-supertraits-transitive.stderr | 4 +- .../ui/hrtb/hrtb-higher-ranker-supertraits.rs | 2 - .../hrtb-higher-ranker-supertraits.stderr | 50 +------- src/test/ui/hrtb/hrtb-perfect-forwarding.rs | 2 +- .../ui/hrtb/hrtb-perfect-forwarding.stderr | 22 +--- src/test/ui/issues/issue-40000.rs | 2 +- src/test/ui/issues/issue-40000.stderr | 26 +---- src/test/ui/lub-glb/old-lub-glb-object.rs | 2 +- src/test/ui/lub-glb/old-lub-glb-object.stderr | 15 +-- .../closure-arg-type-mismatch.rs | 2 - .../closure-arg-type-mismatch.stderr | 48 +------- .../ui/mismatched_types/closure-mismatch.rs | 2 +- .../mismatched_types/closure-mismatch.stderr | 15 +-- ...ons-fn-subtyping-return-static-fail.stderr | 13 +-- ...ion-lifetime-bounds-on-fns-where-clause.rs | 2 +- ...lifetime-bounds-on-fns-where-clause.stderr | 17 ++- ...ple-lifetime-bounds-on-fns-where-clause.rs | 2 +- ...lifetime-bounds-on-fns-where-clause.stderr | 17 ++- .../regions/regions-lifetime-bounds-on-fns.rs | 2 +- .../regions-lifetime-bounds-on-fns.stderr | 17 ++- 37 files changed, 233 insertions(+), 379 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d0cb718f55a25..4cce8343c02c8 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -132,12 +132,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::ReEmpty => ("the empty lifetime".to_owned(), None), + ty::RePlaceholder(_) => (format!("any other region"), None), + // FIXME(#13998) RePlaceholder should probably print like // ReFree rather than dumping Debug output on the user. // // We shouldn't really be having unification failures with ReVar // and ReLateBound though. - ty::RePlaceholder(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { + ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { (format!("lifetime {:?}", region), None) } @@ -324,8 +326,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // the error. If all of these fails, we fall back to a rather // general bit of code that displays the error information RegionResolutionError::ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(region_scope_tree, origin, sub, sup) - .emit(); + if sub.is_placeholder() || sup.is_placeholder() { + self.report_placeholder_failure(region_scope_tree, origin, sub, sup) + .emit(); + } else { + self.report_concrete_failure(region_scope_tree, origin, sub, sup) + .emit(); + } } RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { @@ -346,14 +353,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sup_origin, sup_r, ) => { - self.report_sub_sup_conflict( - region_scope_tree, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, - ); + if sub_r.is_placeholder() { + self.report_placeholder_failure( + region_scope_tree, + sub_origin, + sub_r, + sup_r, + ) + .emit(); + } else if sup_r.is_placeholder() { + self.report_placeholder_failure( + region_scope_tree, + sup_origin, + sub_r, + sup_r, + ) + .emit(); + } else { + self.report_sub_sup_conflict( + region_scope_tree, + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ); + } } } } diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index 07a61eb6d776e..0dda636a9bd53 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -14,9 +14,16 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit an descriptive diagnostic error. pub(super) fn try_report_placeholder_conflict(&self) -> Option { - // Check for the first case: relating two trait-refs, and we - // find a conflict between two placeholders. match &self.error { + /////////////////////////////////////////////////////////////////////////// + // NB. The ordering of cases in this match is very + // sensitive, because we are often matching against + // specific cases and then using an `_` to match all + // others. + + /////////////////////////////////////////////////////////////////////////// + // Check for errors from comparing trait failures -- first + // with two placeholders, then with one. Some(RegionResolutionError::SubSupConflict( vid, _, @@ -27,8 +34,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, sup_placeholder @ ty::RePlaceholder(_), - )) => if expected.def_id == found.def_id { - return Some(self.try_report_placeholders_trait( + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, Some(sub_placeholder), @@ -36,10 +45,8 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { expected.def_id, expected.substs, found.substs, - )); - } else { - // I actually can't see why this would be the case ever. - }, + )) + } Some(RegionResolutionError::SubSupConflict( vid, @@ -51,8 +58,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, _, - )) => if expected.def_id == found.def_id { - return Some(self.try_report_placeholders_trait( + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, Some(sub_placeholder), @@ -60,10 +69,8 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { expected.def_id, expected.substs, found.substs, - )); - } else { - // I actually can't see why this would be the case ever. - }, + )) + } Some(RegionResolutionError::SubSupConflict( vid, @@ -75,8 +82,10 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { _, _, sup_placeholder @ ty::RePlaceholder(_), - )) => if expected.def_id == found.def_id { - return Some(self.try_report_placeholders_trait( + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( Some(self.tcx.mk_region(ty::ReVar(*vid))), cause, None, @@ -84,17 +93,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { expected.def_id, expected.substs, found.substs, - )); - } else { - // I actually can't see why this would be the case ever. - }, - - Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(TypeTrace { .. }), - ty::RePlaceholder(_), - ty::RePlaceholder(_), - )) => { - // I actually can't see why this would be the case ever. + )) } Some(RegionResolutionError::ConcreteFailure( @@ -102,21 +101,21 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), - sub_region, + sub_region @ ty::RePlaceholder(_), sup_region @ ty::RePlaceholder(_), - )) => if expected.def_id == found.def_id { - return Some(self.try_report_placeholders_trait( - Some(sub_region), - cause, + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( None, + cause, + Some(*sub_region), Some(*sup_region), expected.def_id, expected.substs, found.substs, - )); - } else { - // I actually can't see why this would be the case ever. - }, + )) + } Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(TypeTrace { @@ -125,24 +124,43 @@ impl NiceRegionError<'me, 'gcx, 'tcx> { }), sub_region @ ty::RePlaceholder(_), sup_region, - )) => if expected.def_id == found.def_id { - return Some(self.try_report_placeholders_trait( + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( Some(sup_region), cause, - None, Some(*sub_region), + None, expected.def_id, expected.substs, found.substs, - )); - } else { - // I actually can't see why this would be the case ever. - }, + )) + } - _ => {} - } + Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_region, + sup_region @ ty::RePlaceholder(_), + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( + Some(sub_region), + cause, + None, + Some(*sup_region), + expected.def_id, + expected.substs, + found.substs, + )) + } - None + _ => None, + } } // error[E0308]: implementation of `Foo` does not apply to enough lifetimes diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 91da3197d3c1f..e45a4b17cdd9c 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -442,4 +442,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } } + + pub(super) fn report_placeholder_failure( + &self, + region_scope_tree: ®ion::ScopeTree, + placeholder_origin: SubregionOrigin<'tcx>, + sub: Region<'tcx>, + sup: Region<'tcx>, + ) -> DiagnosticBuilder<'tcx> { + // I can't think how to do better than this right now. -nikomatsakis + match placeholder_origin { + infer::Subtype(trace) => { + let terr = TypeError::RegionsPlaceholderMismatch; + self.report_and_explain_type_error(trace, &terr) + } + + _ => { + self.report_concrete_failure(region_scope_tree, placeholder_origin, sub, sup) + } + } + } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 3b9affa6ffb50..461e09819d97d 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -225,7 +225,7 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { pub type PlaceholderMap<'tcx> = BTreeMap>; /// See `error_reporting` module for more details -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ValuePairs<'tcx> { Types(ExpectedFound>), Regions(ExpectedFound>), diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 6b931e39a05da..76e102d88d7ce 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -1,5 +1,5 @@ use hir::def_id::DefId; -use ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use ty::{self, Region, Ty, TyCtxt}; use std::borrow::Cow; use std::fmt; use rustc_target::spec::abi; @@ -9,7 +9,7 @@ use syntax_pos::Span; use hir; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ExpectedFound { pub expected: T, pub found: T, @@ -27,8 +27,7 @@ pub enum TypeError<'tcx> { ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), + RegionsPlaceholderMismatch, Sorts(ExpectedFound>), IntMismatch(ExpectedFound), @@ -102,17 +101,8 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsDoesNotOutlive(..) => { write!(f, "lifetime mismatch") } - RegionsInsufficientlyPolymorphic(br, _) => { - write!(f, - "expected bound lifetime parameter{}{}, found concrete lifetime", - if br.is_named() { " " } else { "" }, - br) - } - RegionsOverlyPolymorphic(br, _) => { - write!(f, - "expected concrete lifetime, found bound lifetime parameter{}{}", - if br.is_named() { " " } else { "" }, - br) + RegionsPlaceholderMismatch => { + write!(f, "one type is more general than the other") } Sorts(values) => ty::tls::with(|tcx| { report_maybe_different(f, &values.expected.sort_string(tcx), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4755adc4cd10d..f9b43f42d5298 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -434,12 +434,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsDoesNotOutlive(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)) } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) - } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) - } + RegionsPlaceholderMismatch => RegionsPlaceholderMismatch, IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), Traits(x) => Traits(x), @@ -1006,8 +1001,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::FixedArraySize)(x), (ty::error::TypeError::ArgCount), (ty::error::TypeError::RegionsDoesNotOutlive)(a, b), - (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b), - (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b), + (ty::error::TypeError::RegionsPlaceholderMismatch), (ty::error::TypeError::IntMismatch)(x), (ty::error::TypeError::FloatMismatch)(x), (ty::error::TypeError::Traits)(x), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index f7adb83f8eb18..a2720bdf385cd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1396,6 +1396,13 @@ impl RegionKind { } } + pub fn is_placeholder(&self) -> bool { + match *self { + ty::RePlaceholder(..) => true, + _ => false, + } + } + pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index b5355e6009975..e4704494e1492 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr @@ -1,24 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0308]: mismatched types --> $DIR/higher-ranked-projection.rs:25:5 | LL | foo(()); - | ^^^ + | ^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:12), 'a) })... - = note: ...so that the types are compatible: - expected Mirror - found Mirror -note: but, the lifetime must be valid for the expression at 25:5... - --> $DIR/higher-ranked-projection.rs:25:5 - | -LL | foo(()); - | ^^^ -note: ...so type `fn(()) {foo::<&(), ()>}` of expression is valid during the expression - --> $DIR/higher-ranked-projection.rs:25:5 - | -LL | foo(()); - | ^^^ + = note: expected type `Mirror` + found type `Mirror` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr index a837df0cd2429..db15ec51d87c6 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr @@ -3,7 +3,7 @@ error: compilation successful | LL | / fn main() { //[good]~ ERROR compilation successful LL | | foo(()); -LL | | //[bad]~^ ERROR E0495 +LL | | //[bad]~^ ERROR E0308 LL | | } | |_^ diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs index 2d2221c6c6392..5b380c982f041 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.rs +++ b/src/test/ui/associated-types/higher-ranked-projection.rs @@ -23,5 +23,5 @@ fn foo(_t: T) #[rustc_error] fn main() { //[good]~ ERROR compilation successful foo(()); - //[bad]~^ ERROR E0495 + //[bad]~^ ERROR E0308 } diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs index 49f6565540b7e..6977fd47a2e85 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs @@ -44,7 +44,7 @@ fn expect_bound_supply_free_from_closure() { // the argument level. type Foo<'a> = fn(&'a u32); with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - //~^ ERROR cannot infer + //~^ ERROR mismatched types }); } diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index d140e9989a3f6..b1cfd6cef1022 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -40,57 +40,29 @@ error[E0308]: mismatched types --> $DIR/expect-fn-supply-fn.rs:30:52 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^ lifetime mismatch + | ^^^^^^^^ one type is more general than the other | = note: expected type `fn(&u32)` found type `for<'r> fn(&'r u32)` - = note: lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) })... -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 30:48 - --> $DIR/expect-fn-supply-fn.rs:30:48 - | -LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/expect-fn-supply-fn.rs:37:53 | LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^ one type is more general than the other | = note: expected type `for<'r> fn(&'r u32)` found type `fn(&'x u32)` - = note: lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... -note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 34:37 - --> $DIR/expect-fn-supply-fn.rs:34:37 - | -LL | fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { - | ^^ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements +error[E0308]: mismatched types --> $DIR/expect-fn-supply-fn.rs:46:53 | LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^ - | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... - = note: ...so that the types are compatible: - expected for<'r> fn(&'r u32) - found fn(&u32) -note: but, the lifetime must be valid for the expression at 46:65... - --> $DIR/expect-fn-supply-fn.rs:46:65 + | ^^^^^^^ one type is more general than the other | -LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | _________________________________________________________________^ -LL | | //~^ ERROR cannot infer -LL | | }); - | |_____^ -note: ...so that the type `fn(&u32)` will meet its required lifetime bounds - --> $DIR/expect-fn-supply-fn.rs:46:53 - | -LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^ + = note: expected type `for<'r> fn(&'r u32)` + found type `fn(&u32)` error: aborting due to 5 previous errors -Some errors occurred: E0308, E0495. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index 4069e3b25ade0..bdfabdabbebb7 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -1,19 +1,16 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements +error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_________________________________________________________________________________________- in this macro invocation | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:26), 'b) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:25), 'a) })... - = note: ...so that the expression is assignable: - expected std::option::Option fn(&'a u32, &'b u32) -> &'a u32> - found std::option::Option fn(&'a u32, &'a u32) -> &'a u32> + = note: expected type `std::option::Option fn(&'a u32, &'b u32) -> &'a u32>` + found type `std::option::Option fn(&'a u32, &'a u32) -> &'a u32>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index bb1a828f3da4b..74b8c89b6e86f 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } @@ -10,16 +10,6 @@ LL | | fn(&'x u32)) } | = note: expected type `std::option::Option fn(&'a u32)>` found type `std::option::Option` - = note: lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:23), 'a) })... -note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 38:22 - --> $DIR/hr-subtype.rs:38:22 - | -LL | fn supertype<'x,'y:'x,'z:'y>() { - | ^^ -... -LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), -LL | | fn(&'x u32)) } - | |___________________________________________- in this macro invocation error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 1a806bd2cb550..8168941e2777c 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -1,19 +1,16 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements +error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________________________________________________- in this macro invocation | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:25), 'a) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:26), 'b) })... - = note: ...so that the expression is assignable: - expected std::option::Option fn(Inv<'a>, Inv<'b>)> - found std::option::Option fn(Inv<'a>, Inv<'a>)> + = note: expected type `std::option::Option fn(Inv<'a>, Inv<'b>)>` + found type `std::option::Option fn(Inv<'a>, Inv<'a>)>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.rs b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs index bba1f4dfb86c2..24182d76b3581 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs @@ -19,5 +19,5 @@ fn main() { // yielding `fn(&!b u32)`, in a fresh universe U1 // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. - let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer + let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 75ba89f58da1b..4a2a619298cd5 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -1,24 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0308]: mismatched types --> $DIR/hrtb-exists-forall-fn.rs:22:34 | -LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer - | ^^^ +LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types + | ^^^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'b) })... - = note: ...so that the expression is assignable: - expected for<'b> fn(&'b u32) - found fn(&u32) -note: but, the lifetime must be valid for the call at 22:34... - --> $DIR/hrtb-exists-forall-fn.rs:22:34 - | -LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer - | ^^^^^ -note: ...so type `fn(&u32)` of expression is valid during the expression - --> $DIR/hrtb-exists-forall-fn.rs:22:34 - | -LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer - | ^^^^^ + = note: expected type `for<'b> fn(&'b u32)` + found type `fn(&u32)` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index b02764184fbe9..0d7b5cbf82348 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -2,12 +2,10 @@ error[E0308]: mismatched types --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | LL | want_bar_for_any_ccx(b); //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected type `for<'ccx> Bar<'ccx>` found type `Bar<'static>` - = note: lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:16), 'ccx) })... - = note: ...does not necessarily outlive the static lifetime error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs index 638587f428d78..3d2d403462d8b 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs @@ -16,7 +16,6 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F) { want_foo_for_some_tcx(f); want_foo_for_any_tcx(f); //~ ERROR E0308 - //~^ ERROR E0308 } fn want_foo_for_any_tcx(f: &F) @@ -34,7 +33,6 @@ fn want_bar_for_some_ccx<'x,B>(b: &B) want_bar_for_some_ccx(b); want_bar_for_any_ccx(b); //~ ERROR E0308 - //~^ ERROR E0308 } fn want_bar_for_any_ccx(b: &B) diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr index 71ed59ce2ff7e..31dbeec2a551b 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -2,62 +2,20 @@ error[E0308]: mismatched types --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 | LL | want_foo_for_any_tcx(f); //~ ERROR E0308 - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected type `for<'tcx> Foo<'tcx>` found type `Foo<'x>` - = note: lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:15), 'tcx) })... -note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 14:26 - --> $DIR/hrtb-higher-ranker-supertraits.rs:14:26 - | -LL | fn want_foo_for_some_tcx<'x,F>(f: &'x F) - | ^^ - -error[E0308]: mismatched types - --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 - | -LL | want_foo_for_any_tcx(f); //~ ERROR E0308 - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected type `for<'tcx> Foo<'tcx>` - found type `Foo<'x>` -note: the lifetime 'x as defined on the function body at 14:26... - --> $DIR/hrtb-higher-ranker-supertraits.rs:14:26 - | -LL | fn want_foo_for_some_tcx<'x,F>(f: &'x F) - | ^^ - = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U4, name: BrNamed(crate0:DefIndex(1:15), 'tcx) }) error[E0308]: mismatched types - --> $DIR/hrtb-higher-ranker-supertraits.rs:36:5 + --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5 | LL | want_bar_for_any_ccx(b); //~ ERROR E0308 - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected type `for<'ccx> Bar<'ccx>` found type `Bar<'x>` - = note: lifetime RePlaceholder(Placeholder { universe: U8, name: BrNamed(crate0:DefIndex(1:19), 'ccx) })... -note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 29:26 - --> $DIR/hrtb-higher-ranker-supertraits.rs:29:26 - | -LL | fn want_bar_for_some_ccx<'x,B>(b: &B) - | ^^ - -error[E0308]: mismatched types - --> $DIR/hrtb-higher-ranker-supertraits.rs:36:5 - | -LL | want_bar_for_any_ccx(b); //~ ERROR E0308 - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected type `for<'ccx> Bar<'ccx>` - found type `Bar<'x>` -note: the lifetime 'x as defined on the function body at 29:26... - --> $DIR/hrtb-higher-ranker-supertraits.rs:29:26 - | -LL | fn want_bar_for_some_ccx<'x,B>(b: &B) - | ^^ - = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U8, name: BrNamed(crate0:DefIndex(1:19), 'ccx) }) -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs index 31dad39efc3f5..7bd89960e42e5 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs @@ -43,7 +43,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T) // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. - foo_hrtb_bar_not(&mut t); //~ ERROR E0495 + foo_hrtb_bar_not(&mut t); //~ ERROR E0308 } fn foo_hrtb_bar_hrtb(mut t: T) diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr index 2de60a79a85bd..ec3bf8a1a1be3 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -1,22 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0308]: mismatched types --> $DIR/hrtb-perfect-forwarding.rs:46:5 | -LL | foo_hrtb_bar_not(&mut t); //~ ERROR E0495 - | ^^^^^^^^^^^^^^^^ +LL | foo_hrtb_bar_not(&mut t); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrNamed(crate0:DefIndex(1:23), 'a) })... - = note: ...so that the types are compatible: - expected Foo<&'a isize> - found Foo<&isize> -note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 39:21... - --> $DIR/hrtb-perfect-forwarding.rs:39:21 - | -LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) - | ^^ - = note: ...so that the types are compatible: - expected Bar<&isize> - found Bar<&'b isize> + = note: expected type `Foo<&'a isize>` + found type `Foo<&isize>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-40000.rs b/src/test/ui/issues/issue-40000.rs index c7d1900ada958..320992c0764cf 100644 --- a/src/test/ui/issues/issue-40000.rs +++ b/src/test/ui/issues/issue-40000.rs @@ -3,5 +3,5 @@ fn main() { fn foo(x: Box) {} let bar = Box::new(|x: &i32| {}) as Box; - foo(bar); //~ ERROR E0495 + foo(bar); //~ ERROR E0308 } diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 3aa1da8680c02..d7966cea52bb0 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -1,26 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0308]: mismatched types --> $DIR/issue-40000.rs:6:9 | -LL | foo(bar); //~ ERROR E0495 - | ^^^ +LL | foo(bar); //~ ERROR E0308 + | ^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U8, name: BrAnon(0) })... - = note: ...so that the types are compatible: - expected dyn for<'r> std::ops::Fn(&'r i32) - found dyn std::ops::Fn(&i32) -note: but, the lifetime must be valid for the block suffix following statement 2 at 5:5... - --> $DIR/issue-40000.rs:5:5 - | -LL | / let bar = Box::new(|x: &i32| {}) as Box; -LL | | foo(bar); //~ ERROR E0495 -LL | | } - | |_^ -note: ...so that variable is valid at time of its declaration - --> $DIR/issue-40000.rs:5:9 - | -LL | let bar = Box::new(|x: &i32| {}) as Box; - | ^^^ + = note: expected type `dyn for<'r> std::ops::Fn(&'r i32)` + found type `dyn std::ops::Fn(&i32)` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs index 132df608af71a..9be7a813603d4 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.rs +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -7,7 +7,7 @@ fn foo( x: &for<'a, 'b> Foo<&'a u8, &'b u8>, y: &for<'a> Foo<&'a u8, &'a u8>, ) { - let z = match 22 { //~ ERROR cannot infer + let z = match 22 { //~ ERROR E0308 0 => x, _ => y, }; diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 2ed180f25dc02..17d3648156b51 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,19 +1,16 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements +error[E0308]: mismatched types --> $DIR/old-lub-glb-object.rs:10:13 | -LL | let z = match 22 { //~ ERROR cannot infer +LL | let z = match 22 { //~ ERROR E0308 | _____________^ LL | | 0 => x, LL | | _ => y, LL | | }; - | |_____^ + | |_____^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U5, name: BrNamed(crate0:DefIndex(1:11), 'a) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U5, name: BrNamed(crate0:DefIndex(1:12), 'b) })... - = note: ...so that the types are compatible: - expected dyn for<'a, 'b> Foo<&'a u8, &'b u8> - found dyn for<'a> Foo<&'a u8, &'a u8> + = note: expected type `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found type `dyn for<'a> Foo<&'a u8, &'a u8>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs index f71a1736d4d3f..437150666be0c 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -9,6 +9,4 @@ fn baz(_: F) {} fn _test<'a>(f: fn(*mut &'a u32)) { baz(f); //~ ERROR mismatched types //~| ERROR mismatched types - //~| ERROR mismatched types - //~| ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 2cd63099bb756..a6628006587c1 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -26,63 +26,21 @@ error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 | LL | baz(f); //~ ERROR mismatched types - | ^^^ lifetime mismatch + | ^^^ one type is more general than the other | = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` found type `std::ops::Fn<(*mut &'a u32,)>` - = note: lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) })... -note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 9:10 - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ - -error[E0308]: mismatched types - --> $DIR/closure-arg-type-mismatch.rs:10:5 - | -LL | baz(f); //~ ERROR mismatched types - | ^^^ lifetime mismatch - | - = note: expected type `std::ops::FnOnce<(*mut &u32,)>` - found type `std::ops::FnOnce<(*mut &'a u32,)>` - = note: lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) })... -note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 9:10 - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 | LL | baz(f); //~ ERROR mismatched types - | ^^^ lifetime mismatch - | - = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` - found type `std::ops::Fn<(*mut &'a u32,)>` -note: the lifetime 'a as defined on the function body at 9:10... - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ - = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U2, name: BrAnon(0) }) - -error[E0308]: mismatched types - --> $DIR/closure-arg-type-mismatch.rs:10:5 - | -LL | baz(f); //~ ERROR mismatched types - | ^^^ lifetime mismatch + | ^^^ one type is more general than the other | = note: expected type `std::ops::FnOnce<(*mut &u32,)>` found type `std::ops::FnOnce<(*mut &'a u32,)>` -note: the lifetime 'a as defined on the function body at 9:10... - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ - = note: ...does not necessarily outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrAnon(0) }) -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors Some errors occurred: E0308, E0631. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs index 0f28e5dfd7ee0..152a525493732 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -5,5 +5,5 @@ impl Foo for T {} fn baz(_: T) {} fn main() { - baz(|_| ()); //~ ERROR E0495 + baz(|_| ()); //~ ERROR E0308 } diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index f028817a935a7..0d87bc228755f 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,15 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0308]: mismatched types --> $DIR/closure-mismatch.rs:8:5 | -LL | baz(|_| ()); //~ ERROR E0495 - | ^^^ +LL | baz(|_| ()); //~ ERROR E0308 + | ^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U6, name: BrAnon(0) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U6, name: BrAnon(0) })... - = note: ...so that the types are compatible: - expected for<'r> std::ops::Fn<(&'r (),)> - found std::ops::Fn<(&(),)> + = note: expected type `for<'r> std::ops::Fn<(&'r (),)>` + found type `std::ops::Fn<(&(),)>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index c9ccb9b6ded3d..a9234e43191ea 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -1,15 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements +error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | LL | want_G(baz); //~ ERROR - | ^^^ + | ^^^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'cx) })... - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the expression is assignable: - expected for<'cx> fn(&'cx S) -> &'static S - found for<'r> fn(&'r S) -> &'r S + = note: expected type `for<'cx> fn(&'cx S) -> &'static S` + found type `for<'r> fn(&'r S) -> &'r S` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs index e5514d32c4e9f..ab4c6d9cf9198 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs @@ -17,7 +17,7 @@ fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 + let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types } fn e() { diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr index 3824755fa06f5..47e1d0efdc77b 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -16,19 +16,16 @@ LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { LL | a(x, y); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0308]: mismatched types --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 - | ^ +LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types + | ^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...so that the expression is assignable: - expected for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize) - found for<'r, 's> fn(&'r mut &isize, &'s mut &isize) + = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors -Some errors occurred: E0495, E0623. -For more information about an error, try `rustc --explain E0495`. +Some errors occurred: E0308, E0623. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs index 3e635300d7b68..066522548ad45 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs @@ -19,7 +19,7 @@ fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0495 + let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308 } fn e() { diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr index f694d31264070..1e7b99053f77f 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -27,19 +27,16 @@ LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { LL | a(x, y, z); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0308]: mismatched types --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 | -LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0495 - | ^ +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308 + | ^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...so that the expression is assignable: - expected for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize) - found for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) + = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` + found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)` error: aborting due to 4 previous errors -Some errors occurred: E0495, E0623. -For more information about an error, try `rustc --explain E0495`. +Some errors occurred: E0308, E0623. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs index 6ebfc3f80d252..7d7f62e19792f 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs @@ -17,7 +17,7 @@ fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { fn d() { // 'a and 'b are early bound in the function `a` because they appear // inconstraints: - let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 + let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308 } fn e() { diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr index 20e28e8877fca..a43ee7ec3ace0 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -16,19 +16,16 @@ LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { LL | a(x, y); //~ ERROR lifetime mismatch [E0623] | ^ ...but data from `y` flows into `x` here -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0308]: mismatched types --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0495 - | ^ +LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308 + | ^ one type is more general than the other | - = note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U1, name: BrAnon(1) })... - = note: ...so that the expression is assignable: - expected for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize) - found for<'r, 's> fn(&'r mut &isize, &'s mut &isize) + = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors -Some errors occurred: E0495, E0623. -For more information about an error, try `rustc --explain E0495`. +Some errors occurred: E0308, E0623. +For more information about an error, try `rustc --explain E0308`. From cf2f7cccb4fc170cd395f47569e8280e7081bf25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Nov 2018 10:29:50 -0500 Subject: [PATCH 24/30] pacify the mercilous tidy --- src/librustc/util/ppaux.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0742d0aebe954..79405b124001d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -90,7 +90,11 @@ impl RegionHighlightMode { /// During the execution of `op`, highlight the region inference /// vairable `vid` as `'N`. We can only highlight one region vid /// at a time. - pub fn highlighting_region(region: ty::Region<'_>, number: usize, op: impl FnOnce() -> R) -> R { + pub fn highlighting_region( + region: ty::Region<'_>, + number: usize, + op: impl FnOnce() -> R, + ) -> R { let old_mode = Self::get(); let mut new_mode = old_mode; let first_avail_slot = new_mode.highlight_regions.iter_mut() @@ -1076,12 +1080,10 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if RegionHighlightMode::get().any_region_vids_highlighted() { - if let Some(counter) = RegionHighlightMode::get().region_highlighted(&ty::ReVar(*self)) { - return write!(f, "'{:?}", counter); - } else { - return write!(f, "'_"); - } + if let Some(counter) = RegionHighlightMode::get().region_highlighted(&ty::ReVar(*self)) { + return write!(f, "'{:?}", counter); + } else if RegionHighlightMode::get().any_region_vids_highlighted() { + return write!(f, "'_"); } write!(f, "'_#{}r", self.index()) From 1db7193162dc1058c11a0eb920bef91434bfe31c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Nov 2018 10:47:34 -0500 Subject: [PATCH 25/30] address tmandry nits --- src/test/ui/coherence/coherence-subtyping.rs | 32 ++----------------- .../ui/coherence/coherence-subtyping.stderr | 30 ++++------------- src/test/ui/hrtb/hrtb-exists-forall-fn.rs | 13 +++----- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 2 +- 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/src/test/ui/coherence/coherence-subtyping.rs b/src/test/ui/coherence/coherence-subtyping.rs index 2ac9156017829..fb9a7fbf7aba5 100644 --- a/src/test/ui/coherence/coherence-subtyping.rs +++ b/src/test/ui/coherence/coherence-subtyping.rs @@ -1,40 +1,14 @@ // Test that two distinct impls which match subtypes of one another // yield coherence errors (or not) depending on the variance. -trait Contravariant { +trait TheTrait { fn foo(&self) { } } -impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { +impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } -impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - //~^ ERROR -} - -/////////////////////////////////////////////////////////////////////////// - -trait Covariant { - fn foo(&self) { } -} - -impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { -} - -impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - //~^ ERROR -} - -/////////////////////////////////////////////////////////////////////////// - -trait Invariant { - fn foo(&self) { } -} - -impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { -} - -impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { +impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { //~^ ERROR } diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr index eb68768eed072..1f9b2cb6fdfa3 100644 --- a/src/test/ui/coherence/coherence-subtyping.stderr +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -1,30 +1,12 @@ -error[E0119]: conflicting implementations of trait `Contravariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: +error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: --> $DIR/coherence-subtyping.rs:11:1 | -LL | impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { - | -------------------------------------------------------------- first implementation here +LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { + | --------------------------------------------------------- first implementation here ... -LL | impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` +LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` -error[E0119]: conflicting implementations of trait `Covariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: - --> $DIR/coherence-subtyping.rs:24:1 - | -LL | impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { - | ---------------------------------------------------------- first implementation here -... -LL | impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` - -error[E0119]: conflicting implementations of trait `Invariant` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`: - --> $DIR/coherence-subtyping.rs:37:1 - | -LL | impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { - | ---------------------------------------------------------- first implementation here -... -LL | impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` - -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.rs b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs index 24182d76b3581..828331cb950ed 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs @@ -3,21 +3,16 @@ // In particular, we test this pattern in trait solving, where it is not connected // to any part of the source code. -trait Trait {} - fn foo<'a>() -> fn(&'a u32) { panic!() } fn main() { - // Here, proving that `(): Trait fn(&'b u32)>` uses the impl: + // Here, proving that `fn(&'a u32) <: for<'b> fn(&'b u32)`: // - // - The impl provides the clause `forall<'a> { (): Trait }` - // - We instantiate `'a` existentially to get `(): Trait` - // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` - // - This requires (among other things) instantiating `'b` universally, - // yielding `fn(&!b u32)`, in a fresh universe U1 - // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. + // - instantiates `'b` with a placeholder `!b`, + // - requires that `&!b u32 <: &'a u32` and hence that `!b: 'a`, + // - but we can never know this. let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 4a2a619298cd5..6301ed45ac277 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/hrtb-exists-forall-fn.rs:22:34 + --> $DIR/hrtb-exists-forall-fn.rs:17:34 | LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types | ^^^^^ one type is more general than the other From c04563e1b00551bbc395d5366df3dc98227a05a5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Nov 2018 10:56:24 -0500 Subject: [PATCH 26/30] add some comments about lifetimes etc --- src/librustc/ty/util.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 0fa4c98be6370..e50095c94d76b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -621,6 +621,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'tcx> ty::TyS<'tcx> { + /// Checks whether values of this type `T` are *moved* or *copied* + /// when referenced -- this amounts to a check for whether `T: + /// Copy`, but note that we **don't** consider lifetimes when + /// doing this check. This means that we may generate MIR which + /// does copies even when the type actually doesn't satisfy the + /// full requirements for the `Copy` trait (cc #29149) -- this + /// winds up being reported as an error during NLL borrow check. pub fn moves_by_default(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -629,6 +636,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { !tcx.at(span).is_copy_raw(param_env.and(self)) } + /// Checks whether values of this type `T` have a size known at + /// compile time (i.e., whether `T: Sized`). Lifetimes are ignored + /// for the purposes of this check, so it can be an + /// over-approximation in generic contexts, where one can have + /// strange rules like `>::Bar: Sized` that + /// actually carry lifetime requirements. pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>)-> bool @@ -636,6 +649,11 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx_at.is_sized_raw(param_env.and(self)) } + /// Checks whether values of this type `T` implement the `Freeze` + /// trait -- frozen types are those that do not contain a + /// `UnsafeCell` anywhere. This is a language concept used to + /// determine how to handle `static` values, the trait itself is + /// not exposed to end users. pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, From 13ea9b877c68c62a52140f47d5e38adf5ee6c808 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Nov 2018 11:57:22 -0500 Subject: [PATCH 27/30] pacify the mercilous eddyb ;) --- src/librustc/ty/util.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e50095c94d76b..c98c575fce28c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -652,8 +652,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { /// Checks whether values of this type `T` implement the `Freeze` /// trait -- frozen types are those that do not contain a /// `UnsafeCell` anywhere. This is a language concept used to - /// determine how to handle `static` values, the trait itself is - /// not exposed to end users. + /// distinguish "true immutability", which is relevant to + /// optimization as well as the rules around static values. Note + /// that the `Freeze` trait is not exposed to end users and is + /// effectively an implementation detail. pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, From 2c17af0bf79276cda6d97c19a78f21edcee22d19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Nov 2018 10:24:38 -0500 Subject: [PATCH 28/30] track if any region constraints involved placeholders --- src/librustc/infer/mod.rs | 7 ++++- src/librustc/infer/region_constraints/mod.rs | 33 ++++++++++++++------ src/librustc/traits/select.rs | 7 ++--- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 461e09819d97d..0a5e399aaad75 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -867,10 +867,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r } + /// Scan the constraints produced since `snapshot` began and returns: + /// + /// - None -- if none of them involve "region outlives" constraints + /// - Some(true) -- if there are `'a: 'b` constraints where `'a` or `'b` is a placehodler + /// - Some(false) -- if there are `'a: 'b` constraints but none involve placeholders pub fn region_constraints_added_in_snapshot( &self, snapshot: &CombinedSnapshot<'a, 'tcx>, - ) -> bool { + ) -> Option { self.borrow_region_constraints().region_constraints_added_in_snapshot( &snapshot.region_constraints_snapshot, ) diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index b29eb67dfa225..56ae850226c91 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -128,6 +128,16 @@ pub enum Constraint<'tcx> { RegSubReg(Region<'tcx>, Region<'tcx>), } +impl Constraint<'_> { + pub fn involves_placeholders(&self) -> bool { + match self { + Constraint::VarSubVar(_, _) => false, + Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), + Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), + } + } +} + /// VerifyGenericBound(T, _, R, RS): The parameter type `T` (or /// associated type) must outlive the region `R`. `T` is known to /// outlive `RS`. Therefore verify that `R <= RS[i]` for some @@ -324,6 +334,8 @@ impl TaintDirections { } } +pub struct ConstraintInfo {} + impl<'tcx> RegionConstraintCollector<'tcx> { pub fn new() -> Self { Self::default() @@ -485,7 +497,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) -> RegionVid { let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); - let u_vid = self.unification_table + let u_vid = self + .unification_table .new_key(unify_key::RegionVidKey { min_vid: vid }); assert_eq!(vid, u_vid); if self.in_snapshot() { @@ -517,7 +530,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { assert!(self.in_snapshot()); - let constraints_to_kill: Vec = self.undo_log + let constraints_to_kill: Vec = self + .undo_log .iter() .enumerate() .rev() @@ -820,17 +834,18 @@ impl<'tcx> RegionConstraintCollector<'tcx> { .filter_map(|&elt| match elt { AddVar(vid) => Some(vid), _ => None, - }) - .collect() + }).collect() } - pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> bool { + /// See [`RegionInference::region_constraints_added_in_snapshot`] + pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option { self.undo_log[mark.length..] .iter() - .any(|&elt| match elt { - AddConstraint(_) => true, - _ => false, - }) + .map(|&elt| match elt { + AddConstraint(constraint) => Some(constraint.involves_placeholders()), + _ => None, + }).max() + .unwrap_or(None) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f5e96286d184e..373ec2d5e490f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -639,10 +639,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> Result { self.infcx.probe(|snapshot| -> Result { let result = op(self)?; - if !self.infcx.region_constraints_added_in_snapshot(snapshot) { - Ok(result) - } else { - Ok(result.max(EvaluatedToOkModuloRegions)) + match self.infcx.region_constraints_added_in_snapshot(snapshot) { + None => Ok(result), + Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), } }) } From 4c8fd2e80af577b105428ae5403ba13f289a7cf5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Nov 2018 11:20:05 -0500 Subject: [PATCH 29/30] try to detect affected code and direct people to #56105 --- src/librustc/traits/coherence.rs | 39 ++++++++++++++++--- src/librustc/traits/mod.rs | 3 +- src/librustc/traits/specialize/mod.rs | 6 +++ .../traits/specialize/specialization_graph.rs | 1 + .../coherence/inherent_impls_overlap.rs | 4 ++ .../ui/coherence/coherence-subtyping.stderr | 2 + 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 980c98d2a2d50..b3d732ebcd7dc 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -4,6 +4,7 @@ //! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html //! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html +use infer::CombinedSnapshot; use hir::def_id::{DefId, LOCAL_CRATE}; use syntax_pos::DUMMY_SP; use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause}; @@ -33,6 +34,17 @@ pub enum Conflict { pub struct OverlapResult<'tcx> { pub impl_header: ty::ImplHeader<'tcx>, pub intercrate_ambiguity_causes: Vec, + + /// True if the overlap might've been permitted before the shift + /// to universes. + pub involves_placeholder: bool, +} + +pub fn add_placeholder_note(err: &mut ::errors::DiagnosticBuilder<'_>) { + err.note(&format!( + "this behavior recently changed as a result of a bug fix; \ + see rust-lang/rust#56105 for details" + )); } /// If there are types that satisfy both impls, invokes `on_overlap` @@ -104,13 +116,22 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, ' /// Can both impl `a` and impl `b` be satisfied by a common type (including /// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, - a_def_id: DefId, - b_def_id: DefId) - -> Option> -{ +fn overlap<'cx, 'gcx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + a_def_id: DefId, + b_def_id: DefId, +) -> Option> { debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); + selcx.infcx().probe(|snapshot| overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)) +} + +fn overlap_within_probe( + selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + a_def_id: DefId, + b_def_id: DefId, + snapshot: &CombinedSnapshot<'_, 'tcx>, +) -> Option> { // For the purposes of this check, we don't bring any placeholder // types into scope; instead, we replace the generic types with // fresh type variables, and hence we do our evaluations in an @@ -158,7 +179,13 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header); let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - Some(OverlapResult { impl_header, intercrate_ambiguity_causes }) + + let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { + Some(true) => true, + _ => false, + }; + + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 0377b98d3f863..b42d742b7f841 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -43,7 +43,8 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; -pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult}; +pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; +pub use self::coherence::{OrphanCheckErr, OverlapResult}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::project::MismatchedProjectionTypes; pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type}; diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index f5d68ddb5bd46..63f52a34dfa70 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -15,6 +15,7 @@ use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use lint; use traits::{self, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; +use traits::coherence; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use syntax_pos::DUMMY_SP; @@ -32,6 +33,7 @@ pub struct OverlapError { pub trait_desc: String, pub self_desc: Option, pub intercrate_ambiguity_causes: Vec, + pub involves_placeholder: bool, } /// Given a subst for the requested impl, translate it to a subst @@ -370,6 +372,10 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( cause.add_intercrate_ambiguity_hint(&mut err); } + if overlap.involves_placeholder { + coherence::add_placeholder_note(&mut err); + } + err.emit(); } } else { diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index fd68917e53991..db3547b2b7479 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -164,6 +164,7 @@ impl<'a, 'gcx, 'tcx> Children { None }, intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, + involves_placeholder: overlap.involves_placeholder, } }; diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index e568320ba8e73..8d27a77b29c6c 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -73,6 +73,10 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { cause.add_intercrate_ambiguity_hint(&mut err); } + if overlap.involves_placeholder { + traits::add_placeholder_note(&mut err); + } + err.emit(); } } diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr index 1f9b2cb6fdfa3..b29a918f2d982 100644 --- a/src/test/ui/coherence/coherence-subtyping.stderr +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -6,6 +6,8 @@ LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { ... LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + | + = note: this behavior recently changed as a result of a bug fix; see #XXX for details error: aborting due to previous error From 8e89184a7beb03d58d3a3969dddc1d78964dec37 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Nov 2018 11:59:06 -0500 Subject: [PATCH 30/30] rename `type_moves_by_default` to `type_is_copy_modulo_regions` --- src/librustc/infer/mod.rs | 7 ++++--- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 15 ++++++++------- src/librustc/ty/query/mod.rs | 2 +- src/librustc/ty/util.rs | 18 +++++++++--------- src/librustc_lint/builtin.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 18 +++++++++++------- src/librustc_mir/build/misc.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 4 ++-- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 7 +++++-- src/librustc_typeck/check/demand.rs | 6 +++--- src/librustc_typeck/check/op.rs | 12 ++++++------ .../ui/coherence/coherence-subtyping.stderr | 2 +- 15 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 0a5e399aaad75..2d3fb137fafdd 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1400,18 +1400,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .verify_generic_bound(origin, kind, a, bound); } - pub fn type_moves_by_default( + pub fn type_is_copy_modulo_regions( &self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span, ) -> bool { let ty = self.resolve_type_vars_if_possible(&ty); + // Even if the type may have no inference variables, during // type-checking closure types are in local tables only. if !self.in_progress_tables.is_some() || !ty.has_closure_types() { if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { - return ty.moves_by_default(self.tcx.global_tcx(), param_env, span); + return ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span); } } @@ -1421,7 +1422,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - !traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) } /// Obtains the latest type of the given closure; this may be a diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f9bcbb3222955..c1aa25b6b75c2 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -976,7 +976,7 @@ fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx move_reason: MoveReason) -> ConsumeMode { - if mc.type_moves_by_default(param_env, cmt.ty, cmt.span) { + if !mc.type_is_copy_modulo_regions(param_env, cmt.ty, cmt.span) { Move(move_reason) } else { Copy diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 207382d5e1f45..370f0d1a6c6d7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -443,15 +443,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - pub fn type_moves_by_default(&self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span) - -> bool { - self.infcx.map(|infcx| infcx.type_moves_by_default(param_env, ty, span)) + pub fn type_is_copy_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool { + self.infcx.map(|infcx| infcx.type_is_copy_modulo_regions(param_env, ty, span)) .or_else(|| { self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| { - ty.moves_by_default(self.tcx.global_tcx(), param_env, span) + ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span) }) }) .unwrap_or(true) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 842aea07614dd..4d026b97233ee 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -382,7 +382,7 @@ define_queries! { <'tcx> /// might want to use `reveal_all()` method to change modes. [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, - /// Trait selection queries. These are best used by invoking `ty.moves_by_default()`, + /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, /// `ty.is_copy()`, etc, since that will prune the environment where possible. [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c98c575fce28c..ac062a2378611 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -203,7 +203,7 @@ impl<'tcx> ty::ParamEnv<'tcx> { let cause = ObligationCause { span, ..ObligationCause::dummy() }; let ctx = traits::FulfillmentContext::new(); match traits::fully_normalize(&infcx, ctx, cause, self, &ty) { - Ok(ty) => if infcx.type_moves_by_default(self, ty, span) { + Ok(ty) => if !infcx.type_is_copy_modulo_regions(self, ty, span) { infringing.push(field); } Err(errors) => { @@ -628,12 +628,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { /// does copies even when the type actually doesn't satisfy the /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. - pub fn moves_by_default(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span) - -> bool { - !tcx.at(span).is_copy_raw(param_env.and(self)) + pub fn is_copy_modulo_regions(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span) + -> bool { + tcx.at(span).is_copy_raw(param_env.and(self)) } /// Checks whether values of this type `T` have a size known at @@ -947,11 +947,11 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `ManuallyDrop` doesn't have a destructor regardless of field types. ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, - // Issue #22536: We first query type_moves_by_default. It sees a + // Issue #22536: We first query `is_copy_modulo_regions`. It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no // cleanup/drop/zeroing) ... - _ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false, + _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, // ... (issue #22536 continued) but as an optimization, still use // prior logic of asking for the structural "may drop". diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cd4cbcc13a6f2..27b65b4ec48a4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -540,7 +540,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { return; } let param_env = ty::ParamEnv::empty(); - if !ty.moves_by_default(cx.tcx, param_env, item.span) { + if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) { return; } if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() { diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 796a2f79f7554..59e9fa23ece46 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -503,13 +503,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]), }; - // In order to have a Copy operand, the type T of the value must be Copy. Note that we - // prove that T: Copy, rather than using the type_moves_by_default test. This is - // important because type_moves_by_default ignores the resulting region obligations and - // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored - // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds - // fully apply: in effect, the rule is that if a value of some type could implement - // Copy, then it must. + // In order to have a Copy operand, the type T of the + // value must be Copy. Note that we prove that T: Copy, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from Copy impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use Copy before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement Copy, then + // it must. self.cx.prove_trait_ref( trait_ref, location.to_locations(), diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 472f05a101f9e..5b20d412f0dd5 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -71,7 +71,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.hir.tcx(); let ty = place.ty(&self.local_decls, tcx).to_ty(tcx); - if self.hir.type_moves_by_default(ty, DUMMY_SP) { + if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { Operand::Move(place) } else { Operand::Copy(place) diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 60c8022a374be..07f3c38c62c52 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -223,8 +223,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { self.check_overflow } - pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.infcx.type_moves_by_default(self.param_env, ty, span) + pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { + self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) } } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index f758e48887715..c104af7a7d81b 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -545,7 +545,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, match bm { ty::BindByValue(..) => { let pat_ty = cx.tables.node_id_to_type(p.hir_id); - if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { + if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { check_move(p, sub.as_ref().map(|p| &**p), span_vec); } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 4c123d4a44b05..2aa44cc181a56 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -310,7 +310,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("build_clone_shim(def_id={:?})", def_id); let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); - let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span); + let is_copy = self_ty.is_copy_modulo_regions(tcx, tcx.param_env(def_id), builder.span); let dest = Place::Local(RETURN_PLACE); let src = Place::Local(Local::new(1+0)).deref(); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0b0845ef945d0..eb151b56bed65 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -224,8 +224,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { "non-field projection {:?} from union?", place) }; - if elem_ty.moves_by_default(self.tcx, self.param_env, - self.source_info.span) { + if !elem_ty.is_copy_modulo_regions( + self.tcx, + self.param_env, + self.source_info.span, + ) { self.require_unsafe( "assignment to non-`Copy` union field", "the previous content of the field will be dropped, which \ diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 84ca77663a6ab..7a788f2de7f2f 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -353,9 +353,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Maybe add `*`? Only if `T: Copy`. _ => { - if !self.infcx.type_moves_by_default(self.param_env, - checked, - sp) { + if self.infcx.type_is_copy_modulo_regions(self.param_env, + checked, + sp) { // do not suggest if the span comes from a macro (#52783) if let (Ok(code), true) = (cm.span_to_snippet(sp), sp == expr.span) { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8cf97970a1556..7c871601af308 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -262,9 +262,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut suggested_deref = false; if let Ref(_, mut rty, _) = lhs_ty.sty { if { - !self.infcx.type_moves_by_default(self.param_env, - rty, - lhs_expr.span) && + self.infcx.type_is_copy_modulo_regions(self.param_env, + rty, + lhs_expr.span) && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)) @@ -334,9 +334,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut suggested_deref = false; if let Ref(_, mut rty, _) = lhs_ty.sty { if { - !self.infcx.type_moves_by_default(self.param_env, - rty, - lhs_expr.span) && + self.infcx.type_is_copy_modulo_regions(self.param_env, + rty, + lhs_expr.span) && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)) diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr index b29a918f2d982..1fc5c39d5c9fd 100644 --- a/src/test/ui/coherence/coherence-subtyping.stderr +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -7,7 +7,7 @@ LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` | - = note: this behavior recently changed as a result of a bug fix; see #XXX for details + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details error: aborting due to previous error