diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e34bb9f4f7b..4cce8343c02 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) => { @@ -339,20 +346,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } RegionResolutionError::SubSupConflict( + _, var_origin, sub_origin, sub_r, 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, + ); + } } } } @@ -407,7 +433,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 } @@ -1306,6 +1332,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), 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 ecf59daeaf1..f7ba546fa7f 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 789796d95cb..c4c71037d8b 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 00000000000..0dda636a9bd --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -0,0 +1,307 @@ +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 { + 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, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_placeholder @ ty::RePlaceholder(_), + _, + sup_placeholder @ ty::RePlaceholder(_), + )) + 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), + Some(sup_placeholder), + expected.def_id, + expected.substs, + found.substs, + )) + } + + Some(RegionResolutionError::SubSupConflict( + vid, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_placeholder @ ty::RePlaceholder(_), + _, + _, + )) + 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), + None, + expected.def_id, + expected.substs, + found.substs, + )) + } + + Some(RegionResolutionError::SubSupConflict( + vid, + _, + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + _, + _, + sup_placeholder @ ty::RePlaceholder(_), + )) + if expected.def_id == found.def_id => + { + Some(self.try_report_placeholders_trait( + Some(self.tcx.mk_region(ty::ReVar(*vid))), + cause, + None, + Some(*sup_placeholder), + expected.def_id, + expected.substs, + found.substs, + )) + } + + Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), + sub_region @ ty::RePlaceholder(_), + sup_region @ ty::RePlaceholder(_), + )) + 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, + )) + } + + 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 => + { + Some(self.try_report_placeholders_trait( + Some(sup_region), + cause, + Some(*sub_region), + None, + expected.def_id, + expected.substs, + found.substs, + )) + } + + 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, + } + } + + // 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_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| { + 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| { + if Some(r) == vid && has_vid.is_none() { + has_vid = Some(counter); + counter += 1; + } + }); + + 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) { + (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, + )); + } + } + }) + }); + + RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid { + Some(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!( + "but `{}` only implements `{}`", + actual_trait_ref.self_ty(), + actual_trait_ref, + )); + } + }); + + err.emit(); + ErrorReported + } +} 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 6d2d2ee93ab..9fc3bb05cda 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/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 91da3197d3c..e45a4b17cdd 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/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 3a3a21d0f1d..709e8c0ba9b 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; + 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); + // 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); - // 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 - ); + // 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); + 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)?; + // 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)?; + debug!("higher_ranked_sub: OK result={:?}", result); - // 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)) - }); + 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); - - debug!("higher_ranked_match: a_match={:?}", a_match); - debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map); - - // Equate types now that bound regions have been replaced. - self.equate(a_is_expected).relate(&a_match, &b_match)?; - - // 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] - - // [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 - - (placeholder, (br, tainted_regions)) - }) - .collect(); - - // 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 }) - }); - } -} - -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 de64800ee8d..dbf8f270ab0 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>, @@ -215,23 +216,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 +573,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!( @@ -566,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, @@ -580,9 +612,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 c000e3aa013..2d3fb137faf 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}; @@ -226,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>), @@ -868,6 +867,20 @@ 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>, + ) -> Option { + 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); } @@ -939,39 +952,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 { @@ -1380,46 +1386,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, @@ -1434,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); } } @@ -1455,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(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/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 66ebbe111db..56ae850226c 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`. @@ -130,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 @@ -326,6 +334,8 @@ impl TaintDirections { } } +pub struct ConstraintInfo {} + impl<'tcx> RegionConstraintCollector<'tcx> { pub fn new() -> Self { Self::default() @@ -487,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() { @@ -519,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() @@ -822,37 +834,18 @@ impl<'tcx> RegionConstraintCollector<'tcx> { .filter_map(|&elt| match elt { AddVar(vid) => Some(vid), _ => None, - }) - .collect() + }).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(); + /// See [`RegionInference::region_constraints_added_in_snapshot`] + pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option { + self.undo_log[mark.length..] + .iter() + .map(|&elt| match elt { + AddConstraint(constraint) => Some(constraint.involves_placeholders()), + _ => None, + }).max() + .unwrap_or(None) } } diff --git a/src/librustc/infer/region_constraints/taint.rs b/src/librustc/infer/region_constraints/taint.rs deleted file mode 100644 index 6743f37972a..00000000000 --- 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/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f9bcbb32229..c1aa25b6b75 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 207382d5e1f..370f0d1a6c6 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/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index f96c4e9014b..92004ece26d 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/coherence.rs b/src/librustc/traits/coherence.rs index 980c98d2a2d..b3d732ebcd7 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/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0e63ef666c7..21352ac1053 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 556b97dc9bc..2e00d4d4b7c 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![]) @@ -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/mod.rs b/src/librustc/traits/mod.rs index 49bd04782b2..b42d742b7f8 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}; @@ -628,14 +629,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 +651,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 +678,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 1554afdeefd..31342c250e2 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/project.rs b/src/librustc/traits/project.rs index 952b37b89f2..732ca70dc78 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/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index 4c1d65c46c5..fdae7d83373 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 bd347764cc6..373ec2d5e49 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -29,7 +29,6 @@ use super::{ use dep_graph::{DepKind, DepNodeIndex}; use hir::def_id::DefId; -use infer; use infer::{InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; use mir::interpret::GlobalId; @@ -45,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}; @@ -328,7 +326,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, @@ -337,6 +336,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. /// @@ -400,9 +401,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, } @@ -412,13 +427,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, @@ -531,33 +547,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)) - } - - /// 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 // @@ -639,11 +628,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, obligation: &PredicateObligation<'tcx>, ) -> Result { - self.probe(|this, _| { + 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)?; + match self.infcx.region_constraints_added_in_snapshot(snapshot) { + None => Ok(result), + Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + } + }) + } + /// Evaluates the predicates in `predicates` recursively. Note that /// this applies projections in the predicates, and therefore /// is run within an inference probe. @@ -714,92 +716,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) => { @@ -1013,6 +933,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) { @@ -1075,7 +1000,7 @@ 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.evaluation_probe(|this| { let candidate = (*candidate).clone(); match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => this.evaluate_predicates_recursively( @@ -1706,8 +1631,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(|_| { + self.match_projection_obligation_against_definition_bounds(obligation) }); if result { @@ -1718,16 +1643,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 { @@ -1759,13 +1683,11 @@ 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(), - &placeholder_map, - snapshot, ) }) }); @@ -1783,12 +1705,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 } @@ -1800,20 +1718,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() } @@ -1862,7 +1771,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.probe(move |this, _| { + self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { this.evaluate_predicates_recursively(stack.list(), obligations.iter()) @@ -2015,14 +1924,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.probe(|this, snapshot| { - if let Ok(placeholder_map) = this.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); } }); }, @@ -2093,11 +1998,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() @@ -2111,7 +2016,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"); @@ -2131,11 +2036,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() }) }) @@ -2352,7 +2257,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(); @@ -2379,7 +2284,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, } @@ -2680,20 +2585,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(|_| { + let (skol_ty, _) = 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, @@ -2702,8 +2607,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &[], ); obligations.push(skol_obligation); - this.infcx() - .plug_leaks(placeholder_map, snapshot, obligations) + obligations }) }) .collect() @@ -2794,9 +2698,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(|_| { let result = - this.match_projection_obligation_against_definition_bounds(obligation, snapshot); + self.match_projection_obligation_against_definition_bounds(obligation); assert!(result); }) } @@ -2913,19 +2817,17 @@ 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(|_| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, placeholder_map) = this.infcx() + let (trait_ref, _) = 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, trait_def_id, &trait_ref.substs, - placeholder_map, - snapshot, ) }); @@ -2950,18 +2852,16 @@ 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(|_| { + let substs = self.rematch_impl(impl_def_id, obligation); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - this.vtable_impl( + self.vtable_impl( impl_def_id, substs, cause, obligation.recursion_depth + 1, obligation.param_env, - placeholder_map, - snapshot, ) }) } @@ -2973,12 +2873,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( @@ -2987,8 +2885,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { param_env, impl_def_id, &substs.value, - placeholder_map, - snapshot, ); debug!( @@ -3041,7 +2937,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); @@ -3117,21 +3013,19 @@ 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(|_| { + 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; 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, trait_def_id, &substs, - placeholder_map, - snapshot, ); debug!( @@ -3341,10 +3235,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); @@ -3546,13 +3440,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", @@ -3567,14 +3457,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 @@ -3584,7 +3467,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; @@ -3616,22 +3499,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( @@ -3787,8 +3659,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(); @@ -3850,8 +3720,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 } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index f5d68ddb5bd..63f52a34dfa 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 fd68917e539..db3547b2b74 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/ty/error.rs b/src/librustc/ty/error.rs index 6b931e39a05..76e102d88d7 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/query/mod.rs b/src/librustc/ty/query/mod.rs index 842aea07614..4d026b97233 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/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4755adc4cd1..f9b43f42d52 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 f7adb83f8eb..a2720bdf385 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/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1d30ccb87b5..ac062a23786 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) => { @@ -621,14 +621,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'tcx> ty::TyS<'tcx> { - 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)) + /// 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 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 + /// 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,13 @@ 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 + /// 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>, @@ -851,11 +871,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 +887,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 +903,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>, @@ -921,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/util/ppaux.rs b/src/librustc/util/ppaux.rs index 318d7adb190..79405b12400 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; @@ -21,17 +21,163 @@ use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; -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) +/// 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, 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 + /// 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'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) + /// 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 REGION_HIGHLIGHT_MODE: Cell = + Cell::new(RegionHighlightMode::default()) +} + +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, + op: impl FnOnce() -> R, + ) -> R { + REGION_HIGHLIGHT_MODE.with(|c| { + c.set(new_mode); + let result = op(); + c.set(old_mode); + result + }) + } + + /// 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( + 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() + .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 + /// 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, + ) + } + + /// Returns true if any placeholders are highlighted. + pub fn any_placeholders_highlighted(&self) -> bool { + 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.region_highlighted(&ty::RePlaceholder(p)) + } } macro_rules! gen_display_debug_body { @@ -553,42 +699,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 +850,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), @@ -768,13 +878,37 @@ 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 { - if cx.is_verbose || get_highlight_region_for_regionvid().is_some() { + if cx.is_verbose { 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 @@ -784,10 +918,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 => @@ -806,11 +942,16 @@ define_print! { ), } } - ty::ReVar(region_vid) if cx.identify_regions => { - write!(f, "'{}rv", region_vid.index()) + ty::ReVar(region_vid) => { + if RegionHighlightMode::get().any_region_vids_highlighted() { + 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, "'"), @@ -939,13 +1080,10 @@ 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() { - debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter); - return if *self == region { - write!(f, "'{:?}", counter) - } else { - 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()) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index a5f7d676862..9c027f110eb 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] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cd4cbcc13a6..27b65b4ec48 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/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 6a5b5d172bb..83cd28bbdc5 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 963d4ab3a54..bff80155112 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"); 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 8bb67521f44..b3e1237a450 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 472f05a101f..5b20d412f0d 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 60c8022a374..07f3c38c62c 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 f758e488877..c104af7a7d8 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 4c123d4a44b..2aa44cc181a 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 0b0845ef945..eb151b56bed 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/cast.rs b/src/librustc_typeck/check/cast.rs index 6ad707e3d2c..9d418704f48 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/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 84ca77663a6..7a788f2de7f 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 8cf97970a15..7c871601af3 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/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 65539d3b107..53e44d53e6a 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 diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index e568320ba8e..8d27a77b29c 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/run-pass/coherence/coherence-subtyping.rs b/src/test/run-pass/coherence/coherence-subtyping.rs deleted file mode 100644 index b7aa57b5c31..00000000000 --- a/src/test/run-pass/coherence/coherence-subtyping.rs +++ /dev/null @@ -1,39 +0,0 @@ -// run-pass -// Test that two distinct impls which match subtypes of one another -// yield coherence errors (or not) depending on the variance. - -trait Contravariant { - fn foo(&self) { } -} - -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 { -} - -/////////////////////////////////////////////////////////////////////////// - -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 { -} - -/////////////////////////////////////////////////////////////////////////// - -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 { -} - -fn main() { } 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 d0245a07e40..20fa1e7a48d 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,33 @@ 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::(); - - tuple_one::(); - //~^ ERROR E0277 - //~| ERROR type mismatch - - tuple_two::(); - //~^ ERROR E0277 - //~| ERROR type mismatch - - tuple_three::(); - - tuple_four::(); - //~^ ERROR E0277 } + +pub fn call_tuple_one() { + tuple_one::(); + //~^ ERROR not general enough +} + +pub fn call_tuple_two() { + tuple_two::(); + //~^ ERROR not general enough +} + +pub fn call_tuple_three() { + tuple_three::(); +} + +pub fn call_tuple_four() { + tuple_four::(); + //~^ 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 5e04dc5f8c5..d3eaa894b50 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,36 @@ 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 - | -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 | | } - | |_^ - -error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` - --> $DIR/associated-types-eq-hr.rs:87: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 | | } - | |_^ - -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied +error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:91:5 | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ | - = 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: 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[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` - --> $DIR/associated-types-eq-hr.rs:91:5 +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:96: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: 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[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: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:105: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: 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, E0277. -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/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index cc69e849fe1..e4704494e14 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,12 @@ -error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` +error[E0308]: mismatched types --> $DIR/higher-ranked-projection.rs:25:5 | LL | foo(()); - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | ^^^ one type is more general than the other | -note: required by `foo` - --> $DIR/higher-ranked-projection.rs:14:1 - | -LL | / fn foo(_t: T) -LL | | where for<'a> &'a T: Mirror -LL | | {} - | |__^ + = note: expected type `Mirror` + found type `Mirror` 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 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 632fe493e1f..db15ec51d87 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 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 be6300c4182..5b380c982f0 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 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 8c7d3cbad33..6977fd47a2e 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 mismatched types + }); } 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 9c857431067..b1cfd6cef10 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,33 @@ 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| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `for<'a, 'r> fn(fn(&'a u32), &'r i32) -> _` + | ^^^^^^^^ one type is more general than the other | -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 | | } - | |_^ + = note: expected type `fn(&u32)` + found type `for<'r> fn(&'r u32)` -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) -> _` + | ^^^^^^^^^^^ one type is more general than the other | -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 | | } - | |_^ + = note: expected type `for<'r> fn(&'r u32)` + found type `fn(&'x u32)` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:46:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:46:53 | -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) -> _` +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^ one type is more general than the other | -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 | | } - | |_^ + = note: expected type `for<'r> fn(&'r u32)` + found type `fn(&u32)` error: aborting due to 5 previous errors -Some errors occurred: E0308, E0631. -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/coherence/coherence-subtyping.rs b/src/test/ui/coherence/coherence-subtyping.rs new file mode 100644 index 00000000000..fb9a7fbf7ab --- /dev/null +++ b/src/test/ui/coherence/coherence-subtyping.rs @@ -0,0 +1,15 @@ +// Test that two distinct impls which match subtypes of one another +// yield coherence errors (or not) depending on the variance. + +trait TheTrait { + fn foo(&self) { } +} + +impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { +} + +impl TheTrait 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 00000000000..1fc5c39d5c9 --- /dev/null +++ b/src/test/ui/coherence/coherence-subtyping.stderr @@ -0,0 +1,14 @@ +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 TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { + | --------------------------------------------------------- first implementation here +... +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 rust-lang/rust#56105 for details + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 2110e8a5407..46d72899438 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -27,7 +27,8 @@ fn main() { yield; assert_foo(x); }; - assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied + assert_foo(gen); + //~^ ERROR implementation of `Foo` is not general enough // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); @@ -44,5 +45,6 @@ fn main() { yield; assert_foo(a); }; - assert_foo(gen); //~ ERROR the requirement `for<'r, 's> 'r : 's` is not satisfied + assert_foo(gen); + //~^ 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 a301dc2ff9a..1b4dfe2df1c 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,37 +1,20 @@ -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: implementation of `Foo` is not general enough --> $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` - | - = 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 - | -LL | fn assert_foo(f: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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 - | -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: `&'0 OnlyFooIfStaticRef` must implement `Foo` for any lifetime `'0` + = 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 | -LL | fn assert_foo(f: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 the lifetime `'2` error: aborting due to 2 previous errors -Some errors occurred: E0277, E0279. -For more information about an error, try `rustc --explain E0277`. 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 8e2b0b8c600..bdfabdabbeb 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 @@ -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 + | ^^^^^^^^^^^ 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) } 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 dbb50181390..25b74d855bb 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 5fcb63e17bf..25b74d855bb 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 5fcb63e17bf..25b74d855bb 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 db9892b48a6..74b8c89b6e8 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 + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } 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 e9fb73411bd..25b74d855bb 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 d0e80faa68e..25b74d855bb 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 5fcb63e17bf..25b74d855bb 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 3605ecf4f86..25b74d855bb 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 fae6e9b5c89..8168941e277 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 @@ -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 + | ^^^^^^^^^^^ 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>)) } 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 5fcb63e17bf..25b74d855bb 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 5fcb63e17bf..25b74d855bb 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 4157953fb90..ad4f39f8405 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/hrtb/hrtb-cache-issue-54302.rs b/src/test/ui/hrtb/hrtb-cache-issue-54302.rs new file mode 100644 index 00000000000..a20d03c7747 --- /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 00000000000..e82fa51524e --- /dev/null +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -0,0 +1,11 @@ +error: implementation of `Deserialize` is not general enough + --> $DIR/hrtb-cache-issue-54302.rs:19:5 + | +LL | assert_deserialize_owned::<&'static str>(); //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.rs b/src/test/ui/hrtb/hrtb-conflate-regions.rs index 8953a847213..391303676d7 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 e2a99ea8472..2ee398e3dd3 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,20 +1,12 @@ -error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied +error: implementation of `Foo` is not general enough --> $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: 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 E0277`. 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 00000000000..828331cb950 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.rs @@ -0,0 +1,18 @@ +// 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. + +fn foo<'a>() -> fn(&'a u32) { + panic!() +} + +fn main() { + // Here, proving that `fn(&'a u32) <: for<'b> fn(&'b u32)`: + // + // - 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 new file mode 100644 index 00000000000..6301ed45ac2 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $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 + | + = 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 E0308`. 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 00000000000..8801760056e --- /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 00000000000..da1bb7cd5fd --- /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 00000000000..da3f8ad1b89 --- /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 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 new file mode 100644 index 00000000000..6a61181e240 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -0,0 +1,12 @@ +error: implementation of `Trait` is not general enough + --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 + | +LL | foo::<()>(); //~ ERROR not general enough + | ^^^^^^^^^ + | + = 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 + 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 99001d7053c..f9ae1429ee4 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 d233ed47524..0d7b5cbf823 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,12 @@ -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 + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = 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>` 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 f430a10d2a7..3d2d403462d 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs @@ -15,7 +15,7 @@ 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 } fn want_foo_for_any_tcx(f: &F) @@ -32,7 +32,7 @@ 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 } 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 fe485c5b259..31dbeec2a55 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -1,40 +1,21 @@ -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 + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = 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 - | -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 | | } - | |_^ + = note: expected type `for<'tcx> Foo<'tcx>` + found type `Foo<'x>` -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied +error[E0308]: mismatched types --> $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` +LL | want_bar_for_any_ccx(b); //~ ERROR E0308 + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = 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 | | } - | |_^ + = note: expected type `for<'ccx> Bar<'ccx>` + found type `Bar<'x>` error: aborting due to 2 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 c162c777c0b..88d5ce8e640 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.rs +++ b/src/test/ui/hrtb/hrtb-just-for-static.rs @@ -21,7 +21,13 @@ 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 +} + +// 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 38865fac86d..094c4498024 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,20 +1,22 @@ -error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied +error: implementation of `Foo` is not general enough --> $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 + | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: the following implementations were found: - > -note: required by `want_hrtb` - --> $DIR/hrtb-just-for-static.rs:8:1 + = 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 | -LL | / fn want_hrtb() -LL | | where T : for<'a> Foo<&'a isize> -LL | | { -LL | | } - | |_^ +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 the lifetime `'1` -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs index 90e1773a3f6..7bd89960e42 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 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 6cada7ac78f..ec3bf8a1a1b 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -1,23 +1,12 @@ -error[E0277]: the trait bound `for<'a> T: Bar<&'a isize>` is not satisfied +error[E0308]: mismatched types --> $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 E0308 + | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = 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 - | -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 | | } - | |_^ + = 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 E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-22872.rs b/src/test/ui/issues/issue-22872.rs index a6130d21b5d..8ef4af15bd4 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/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index 231080add9b..ebd096f1dde 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 2d1e1d07a26..320992c0764 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 E0308 } diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 3ff58703481..d7966cea52b 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types --> $DIR/issue-40000.rs:6:9 | -LL | foo(bar); //~ ERROR mismatched types - | ^^^ expected concrete lifetime, found bound lifetime parameter +LL | foo(bar); //~ ERROR E0308 + | ^^^ one type is more general than the other | - = note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>` - found type `std::boxed::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 diff --git a/src/test/ui/issues/issue-54302-cases.rs b/src/test/ui/issues/issue-54302-cases.rs index 0c852a2eb63..faa116269ee 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 not general enough } fn coerce_lifetime2(a: &i32) -> &'static i32 { >::ref_foo(a) - //~^ ERROR the requirement `for<'a> 'a : ` is not satisfied + //~^ ERROR not general enough } fn coerce_lifetime3(a: &u64) -> &'static u64 { >::ref_foo(a) - //~^ ERROR type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` + //~^ ERROR not general enough } fn coerce_lifetime4(a: &i64) -> &'static i64 { >::ref_foo(a) - //~^ ERROR type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` + //~^ 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 0ed88463277..c1329d331a1 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -1,65 +1,38 @@ -error[E0277]: the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied +error: implementation of `Foo` is not general enough --> $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: `&'0 u32` must implement `Foo<'static, u32>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` -error[E0279]: the requirement `for<'a> 'a : ` is not satisfied (`expected bound lifetime parameter 'a, found concrete lifetime`) +error: implementation of `Foo` is not general enough --> $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: `&'0 i32` must implement `Foo<'static, i32>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` -error[E0271]: type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` +error: implementation of `Foo` is not general enough --> $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: `&'0 u64` must implement `Foo<'static, u64>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` -error[E0271]: type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` +error: implementation of `Foo` is not general enough --> $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: `&'0 i64` must implement `Foo<'static, i64>` for any lifetime `'0` + = note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1` error: aborting due to 4 previous errors -Some errors occurred: E0271, E0277, E0279. -For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-54302.rs b/src/test/ui/issues/issue-54302.rs index c681d37cdae..1bfaebc3895 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 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 2d95aa2b156..1b255204b6e 100644 --- a/src/test/ui/issues/issue-54302.stderr +++ b/src/test/ui/issues/issue-54302.stderr @@ -1,17 +1,11 @@ -error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) +error: implementation of `Deserialize` is not general enough --> $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: `&'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 E0279`. 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 04990546776..324dc86bd92 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 9c397a8fd2c..00000000000 --- 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/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs index 309f2d0ea76..9be7a813603 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 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 243414c19c0..17d3648156b 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,16 +1,15 @@ -error[E0308]: match arms have incompatible types +error[E0308]: mismatched types --> $DIR/old-lub-glb-object.rs:10:13 | -LL | let z = match 22 { //~ ERROR incompatible types +LL | let z = match 22 { //~ ERROR E0308 | _____________^ LL | | 0 => x, LL | | _ => y, - | | - match arm with an incompatible type LL | | }; - | |_____^ expected bound lifetime parameter 'a, found concrete lifetime + | |_____^ one type is more general than the other | - = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>` - found type `&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 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 c5d9e4b9b76..437150666be 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,6 @@ 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 } 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 5dd6887005e..a6628006587 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,25 @@ 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 + | ^^^ one type is more general than the other | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 - | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` + found type `std::ops::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 + | ^^^ one type is more general than the other | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 - | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected type `std::ops::FnOnce<(*mut &u32,)>` + found type `std::ops::FnOnce<(*mut &'a u32,)>` error: aborting due to 5 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 40a4641fe71..152a5254937 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 E0308 } diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index e55047e96c2..0d87bc22875 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,32 +1,12 @@ -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` +error[E0308]: mismatched types --> $DIR/closure-mismatch.rs:8:5 | -LL | baz(|_| ()); //~ ERROR type mismatch - | ^^^ expected bound lifetime parameter, found concrete lifetime +LL | baz(|_| ()); //~ ERROR E0308 + | ^^^ one type is more general than the other | - = 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: expected type `for<'r> std::ops::Fn<(&'r (),)>` + found type `std::ops::Fn<(&(),)>` -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) {} - | ^^^^^^^^^^^^^^^^^^^^ +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors occurred: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +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 a8fe562656e..242119cc201 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 0bf6e0514d2..a9234e43191 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,12 @@ error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static-fail.rs:41:12 + --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | -LL | want_F(bar); //~ ERROR E0308 - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx - | - = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` - found type `for<'a> fn(&'a S) -> &S {bar::<'_>}` - -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 +LL | want_G(baz); //~ ERROR + | ^^^ one type is more general than the other | = note: expected type `for<'cx> fn(&'cx S) -> &'static S` - found type `for<'r> fn(&'r S) -> &'r S {baz}` + found type `for<'r> fn(&'r S) -> &'r S` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. 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 5c8b3d3ba69..47e1d0efdc7 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 @@ -20,10 +20,10 @@ error[E0308]: mismatched types --> $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 + | ^ one type is more general than the other | = 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::<'_, '_>}` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors 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 8e7f4ccad9c..066522548ad 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 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 01899349bf7..1e7b99053f7 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 @@ -30,11 +30,11 @@ LL | a(x, y, z); //~ ERROR lifetime mismatch [E0623] 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 mismatched types - | ^ expected concrete lifetime, found bound lifetime parameter +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308 + | ^ one type is more general than the other | = 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::<'_, '_, '_>}` + found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)` error: aborting due to 4 previous errors 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 fa5f6a334b0..4d6d342f571 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 30646fe7965..61eaf9fcf10 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`. 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 2f35883cc99..7d7f62e1979 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 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 c4d4a159a9c..a43ee7ec3ac 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -19,11 +19,11 @@ LL | a(x, y); //~ ERROR lifetime mismatch [E0623] error[E0308]: mismatched types --> $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 E0308 + | ^ one type is more general than the other | = 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::<'_, '_>}` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors 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 10b25c73403..0ce38e69f6b 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 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 dbe68b82c24..afc80bf4d8e 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,12 @@ -error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied +error: implementation of `Bar` is not general enough --> $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 implementation of `Bar` is not general enough + | ^^^ | - = 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: Due to a where-clause on `foo`, + = note: `&'0 _` must implement `Bar` for any lifetime `'0` + = note: but `&'1 u32` only implements `Bar` for the lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`.