diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e9916bd77e758..cd02dbd91c26c 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -764,9 +764,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - self.note_error_origin(diag, &cause); self.check_and_note_conflicting_crates(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span); + self.check_and_note_conflicting_crates(diag, terr, span); + + // It reads better to have the error origin as the final + // thing. + self.note_error_origin(diag, &cause); } pub fn report_and_explain_type_error(&self, @@ -774,6 +778,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { + debug!("report_and_explain_type_error(trace={:?}, terr={:?})", + trace, + terr); + let span = trace.cause.span; let failure_str = trace.cause.as_failure_str(); let mut diag = match trace.cause.code { diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index d7afeba7dc96b..954c22156486b 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -15,6 +15,7 @@ use super::Subtype; use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; +use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; /// "Greatest lower bound" (common subtype) @@ -74,7 +75,26 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_glb(a, b, self.a_is_expected) + debug!("binders(a={:?}, b={:?})", a, b); + let was_error = self.infcx().probe(|_snapshot| { + self.fields.higher_ranked_glb(a, b, self.a_is_expected).is_err() + }); + debug!("binders: was_error={:?}", was_error); + + // When higher-ranked types are involved, computing the LUB is + // very challenging, switch to invariance. This is obviously + // overly conservative but works ok in practice. + match self.relate_with_variance(ty::Variance::Invariant, a, b) { + Ok(_) => Ok(a.clone()), + Err(err) => { + debug!("binders: error occurred, was_error={:?}", was_error); + if !was_error { + Err(TypeError::OldStyleLUB(Box::new(err))) + } else { + Err(err) + } + } + } } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 6736751a5a2c2..e1f0623a8f183 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,6 +19,7 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_inference::{TaintDirections}; +use std::collections::BTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -245,7 +246,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FxHashMap>, + a_map: &BTreeMap>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -341,7 +342,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FxHashMap>, + a_map: &BTreeMap>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -410,7 +411,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &FxHashMap>, + a_map: &BTreeMap>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { @@ -433,7 +434,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &FxHashMap>) + map: &BTreeMap>) -> Vec { map.iter() .map(|(_, &r)| match *r { diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 04b470b29fc5e..d854959329e8d 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -15,6 +15,7 @@ use super::Subtype; use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; +use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; /// "Least upper bound" (common supertype) @@ -74,7 +75,26 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_lub(a, b, self.a_is_expected) + debug!("binders(a={:?}, b={:?})", a, b); + let was_error = self.infcx().probe(|_snapshot| { + self.fields.higher_ranked_lub(a, b, self.a_is_expected).is_err() + }); + debug!("binders: was_error={:?}", was_error); + + // When higher-ranked types are involved, computing the LUB is + // very challenging, switch to invariance. This is obviously + // overly conservative but works ok in practice. + match self.relate_with_variance(ty::Variance::Invariant, a, b) { + Ok(_) => Ok(a.clone()), + Err(err) => { + debug!("binders: error occurred, was_error={:?}", was_error); + if !was_error { + Err(TypeError::OldStyleLUB(Box::new(err))) + } else { + Err(err) + } + } + } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 79eeebfb25031..08ca37271a694 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,6 +32,7 @@ use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{Cell, RefCell, Ref}; +use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -139,7 +140,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = FxHashMap>; +pub type SkolemizationMap<'tcx> = BTreeMap>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -1260,7 +1261,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, FxHashMap>) + -> (T, BTreeMap>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5cfa72c07126f..228ca76ed9a7a 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -54,6 +54,8 @@ pub enum TypeError<'tcx> { ProjectionBoundsLength(ExpectedFound), TyParamDefaultMismatch(ExpectedFound>), ExistentialMismatch(ExpectedFound<&'tcx ty::Slice>>), + + OldStyleLUB(Box>), } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -170,6 +172,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { report_maybe_different(f, format!("trait `{}`", values.expected), format!("trait `{}`", values.found)) } + OldStyleLUB(ref err) => { + write!(f, "{}", err) + } } } } @@ -293,6 +298,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { db.span_note(found.origin_span, "...that also applies to the same type variable here"); } + OldStyleLUB(err) => { + db.note("this was previously accepted by the compiler but has been phased out"); + db.note("for more information, see https://github.com/rust-lang/rust/issues/45852"); + + self.note_and_explain_type_err(db, &err, sp); + } _ => {} } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 149999e0eee0f..bee119992230f 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -43,7 +43,8 @@ use middle::const_val::ConstVal; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; -use util::nodemap::{FxHashMap, FxHashSet}; +use std::collections::BTreeMap; +use util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. @@ -324,14 +325,14 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: FxHashMap> + map: BTreeMap> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, FxHashMap>) + -> (T, BTreeMap>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -438,7 +439,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx, current_depth: 1, fld_r, - map: FxHashMap() + map: BTreeMap::default() } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 5f1448cd1f18e..e5c24b4fcf921 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -428,7 +428,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { TyParamDefaultMismatch(ref x) => { return tcx.lift(x).map(TyParamDefaultMismatch) } - ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch) + ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), + OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB), }) } } @@ -1174,6 +1175,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { Sorts(x) => Sorts(x.fold_with(folder)), TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)), ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)), + OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)), } } @@ -1191,6 +1193,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { b.visit_with(visitor) }, Sorts(x) => x.visit_with(visitor), + OldStyleLUB(ref x) => x.visit_with(visitor), TyParamDefaultMismatch(ref x) => x.visit_with(visitor), ExistentialMismatch(x) => x.visit_with(visitor), Mismatch | diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9e02065145d27..78ce959e5c94e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -353,28 +353,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } - pub fn t_rptr_static(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static, - self.tcx().types.isize) - } - - pub fn t_rptr_empty(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty, - self.tcx().types.isize) - } - pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> { self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2) } - pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { - self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2) - } - - pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { - self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2) - } - /// Checks that `t1 <: t2` is true (this may register additional /// region checks). pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { @@ -399,37 +381,6 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } } } - - /// Checks that `LUB(t1,t2) == t_lub` - pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { - match self.lub(t1, t2) { - Ok(InferOk { obligations, value: t }) => { - // None of these tests should require nested obligations: - assert!(obligations.is_empty()); - - self.assert_eq(t, t_lub); - } - Err(ref e) => panic!("unexpected error in LUB: {}", e), - } - } - - /// Checks that `GLB(t1,t2) == t_glb` - pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) { - debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb); - match self.glb(t1, t2) { - Err(e) => panic!("unexpected error computing LUB: {:?}", e), - Ok(InferOk { obligations, value: t }) => { - // None of these tests should require nested obligations: - assert!(obligations.is_empty()); - - self.assert_eq(t, t_glb); - - // sanity check for good measure: - self.assert_subtype(t, t1); - self.assert_subtype(t, t2); - } - } - } } #[test] @@ -508,169 +459,6 @@ fn sub_free_bound_false_infer() { }) } -#[test] -fn lub_free_bound_infer() { - //! Test result of: - //! - //! LUB(fn(_#1), for<'b> fn(&'b isize)) - //! - //! This should yield `fn(&'_ isize)`. We check - //! that it yields `fn(&'x isize)` for some free `'x`, - //! anyhow. - - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(1); - env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); - }); -} - -#[test] -fn lub_bound_bound() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_bound2 = env.t_rptr_late_bound(2); - env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound2], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); - }) -} - -#[test] -fn lub_bound_free() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(1); - env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); - }) -} - -#[test] -fn lub_bound_static() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_static = env.t_rptr_static(); - env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_static], env.tcx().types.isize), - env.t_fn(&[t_rptr_static], env.tcx().types.isize)); - }) -} - -#[test] -fn lub_bound_bound_inverse_order() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_bound2 = env.t_rptr_late_bound(2); - env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1), - env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1), - env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1)); - }) -} - -#[test] -fn lub_free_free() { - 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_free2 = env.t_rptr_free(2); - let t_rptr_static = env.t_rptr_static(); - env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free2], env.tcx().types.isize), - env.t_fn(&[t_rptr_static], env.tcx().types.isize)); - }) -} - -#[test] -fn lub_returning_scope() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr_scope10 = env.t_rptr_scope(10); - let t_rptr_scope11 = env.t_rptr_scope(11); - let t_rptr_empty = env.t_rptr_empty(); - env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize), - env.t_fn(&[t_rptr_scope11], env.tcx().types.isize), - env.t_fn(&[t_rptr_empty], env.tcx().types.isize)); - }); -} - -#[test] -fn glb_free_free_with_common_scope() { - 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_free2 = env.t_rptr_free(2); - let t_rptr_scope = env.t_rptr_scope(1); - env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free2], env.tcx().types.isize), - env.t_fn(&[t_rptr_scope], env.tcx().types.isize)); - }) -} - -#[test] -fn glb_bound_bound() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_bound2 = env.t_rptr_late_bound(2); - env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound2], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); - }) -} - -#[test] -fn glb_bound_free() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(1); - env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); - }) -} - -#[test] -fn glb_bound_free_infer() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); - - // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize), - // which should yield for<'b> fn(&'b isize) -> isize - env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_infer1], env.tcx().types.isize), - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); - - // as a side-effect, computing GLB should unify `_` with - // `&'_ isize` - let t_resolve1 = env.infcx.shallow_resolve(t_infer1); - match t_resolve1.sty { - ty::TyRef(..) => {} - _ => { - panic!("t_resolve1={:?}", t_resolve1); - } - } - }) -} - -#[test] -fn glb_bound_static() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_static = env.t_rptr_static(); - env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_static], 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/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs new file mode 100644 index 0000000000000..85c90bb375fc7 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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. + +fn foo( + x: fn(&u8, &u8), + y: for<'a> fn(&'a u8, &'a u8), +) { + let z = match 22 { + 0 => x, + _ => y, + }; +} + +fn bar( + x: fn(&u8, &u8), + y: for<'a> fn(&'a u8, &'a u8), +) { + let z = match 22 { + // No error with an explicit cast: + 0 => x as for<'a> fn(&'a u8, &'a u8), + _ => y, + }; +} + +fn main() { +} diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr new file mode 100644 index 0000000000000..4a310a5e6b296 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -0,0 +1,22 @@ +error[E0308]: match arms have incompatible types + --> $DIR/old-lub-glb-hr.rs:18:13 + | +18 | let z = match 22 { + | _____________^ +19 | | 0 => x, +20 | | _ => y, +21 | | }; + | |_____^ 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)` + = note: this was previously accepted by the compiler but has been phased out + = note: for more information, see https://github.com/rust-lang/rust/issues/45852 +note: match arm with an incompatible type + --> $DIR/old-lub-glb-hr.rs:20:14 + | +20 | _ => y, + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs new file mode 100644 index 0000000000000..7cf89b68be197 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -0,0 +1,38 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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. + +trait Foo { } + +fn foo( + x: &for<'a, 'b> Foo<&'a u8, &'b u8>, + y: &for<'a> Foo<&'a u8, &'a u8>, +) { + let z = match 22 { + 0 => x, + _ => y, + }; +} + +fn bar( + x: &for<'a, 'b> Foo<&'a u8, &'b u8>, + y: &for<'a> Foo<&'a u8, &'a u8>, +) { + // Accepted with explicit case: + let z = match 22 { + 0 => x as &for<'a> Foo<&'a u8, &'a u8>, + _ => y, + }; +} + +fn main() { +} diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr new file mode 100644 index 0000000000000..a1077f40bf561 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -0,0 +1,22 @@ +error[E0308]: match arms have incompatible types + --> $DIR/old-lub-glb-object.rs:20:13 + | +20 | let z = match 22 { + | _____________^ +21 | | 0 => x, +22 | | _ => y, +23 | | }; + | |_____^ expected bound lifetime parameter 'a, found concrete lifetime + | + = note: expected type `&for<'a, 'b> Foo<&'a u8, &'b u8>` + found type `&for<'a> Foo<&'a u8, &'a u8>` + = note: this was previously accepted by the compiler but has been phased out + = note: for more information, see https://github.com/rust-lang/rust/issues/45852 +note: match arm with an incompatible type + --> $DIR/old-lub-glb-object.rs:22:14 + | +22 | _ => y, + | ^ + +error: aborting due to previous error +