diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4c4ace0d8baf9..38ea1e4a19b91 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2461,7 +2461,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_trait, target) + self.infcx.eq_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2520,7 +2520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, a, b) + self.infcx.eq_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_struct, target) + self.infcx.eq_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index ca0ab8f1e8c77..1aab4853a4f64 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; @@ -149,6 +150,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) where I: IntoIterator + { + let fcx = self.fcx; + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + } + + pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) + -> InferOk<'tcx, ()> + where I: IntoIterator { let methods: Vec<_> = self.steps .iter() @@ -176,8 +185,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } - for obligation in self.obligations { - self.fcx.register_predicate(obligation); + InferOk { + value: (), + obligations: self.obligations } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 53759cc115d1c..c43291557f7fa 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -64,7 +64,8 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, @@ -75,9 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; -use util::common::indent; -use std::cell::RefCell; use std::collections::VecDeque; use std::ops::Deref; @@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, - unsizing_obligations: RefCell>>, } impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { @@ -95,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; +type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } +fn identity<'tcx>() -> Adjust<'tcx> { + Adjust::DerefRef { + autoderefs: 0, + autoref: None, + unsize: false, + } +} + +fn success<'tcx>(kind: Adjust<'tcx>, + target: Ty<'tcx>, + obligations: traits::PredicateObligations<'tcx>) + -> CoerceResult<'tcx> { + Ok(InferOk { + value: Adjustment { + kind, + target + }, + obligations + }) +} + impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, cause: cause, use_lub: false, - unsizing_obligations: RefCell::new(vec![]), } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - self.fcx.register_predicates(obligations); - value - }) } }) } - /// Unify two types (using sub or lub) and produce a noop coercion. - fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - self.unify(&a, &b).and_then(|ty| self.identity(ty)) - } - - /// Synthesize an identity adjustment. - fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, Adjust::DerefRef { - autoderefs: 0, - autoref: None, - unsize: false, - })) + /// Unify two types (using sub or lub) and produce a specific coercion. + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) + -> CoerceResult<'tcx> { + self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { + success(kind, ty, obligations) + }) } fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> @@ -158,11 +165,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return self.identity(b); + return success(identity(), b, vec![]); } if a.is_never() { - return Ok((b, Adjust::NeverToAny)); + return success(Adjust::NeverToAny, b, vec![]); } // Consider coercing the subtype to a DST @@ -208,7 +215,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and_identity(a, b) + self.unify_and(a, b, identity()) } } } @@ -240,7 +247,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and_identity(a, b), + _ => return self.unify_and(a, b, identity()), }; let span = self.cause.span; @@ -248,7 +255,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut first_error = None; let mut r_borrow_var = None; let mut autoderef = self.autoderef(span, a); - let mut success = None; + let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { if autoderefs == 0 { @@ -346,8 +353,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mt_b.mutbl, // [1] above }); match self.unify(derefd_ty_a, b) { - Ok(ty) => { - success = Some((ty, autoderefs)); + Ok(ok) => { + found = Some((ok, autoderefs)); break; } Err(err) => { @@ -363,7 +370,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (ty, autoderefs) = match success { + let (InferOk { value: ty, mut obligations }, autoderefs) = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -372,12 +379,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - // This commits the obligations to the fulfillcx. After this succeeds, - // this snapshot can't be rolled back. - autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); - - // Now apply the autoref. We have to extract the region out of - // the final ref type we got. if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as @@ -391,8 +392,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return self.identity(ty); + return success(identity(), ty, obligations); } + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), @@ -402,11 +406,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty, autoderefs, autoref); - Ok((ty, Adjust::DerefRef { + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + + success(Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, unsize: false, - })) + }, ty, obligations) } @@ -445,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => (source, None), }; - let source = source.adjust_for_autoref(self.tcx, reborrow); + let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); + + let adjust = Adjust::DerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: true, + }; + + // Setup either a subtyping or a LUB relationship between + // the `CoerceUnsized` target type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let coerce_target = self.next_ty_var(origin); + let mut coercion = self.unify_and(coerce_target, target, adjust)?; let mut selcx = traits::SelectionContext::new(self); // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut leftover_predicates = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx - .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); + .predicate_for_trait_def(cause, coerce_unsized_did, 0, + coerce_source, &[coerce_target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -467,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - leftover_predicates.push(obligation); + coercion.obligations.push(obligation); continue; } }; @@ -495,33 +517,26 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - *self.unsizing_obligations.borrow_mut() = leftover_predicates; - - let adjustment = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, - }; - debug!("Success, coerced with {:?}", adjustment); - Ok((target, adjustment)) + Ok(coercion) } fn coerce_from_safe_fn(&self, a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>) + b: Ty<'tcx>, + to_unsafe: Adjust<'tcx>, + normal: Adjust<'tcx>) -> CoerceResult<'tcx> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); + return self.unify_and(unsafe_a, b, to_unsafe); } _ => {} } } - self.unify_and_identity(a, b) + self.unify_and(a, b, normal) } fn coerce_from_fn_pointer(&self, @@ -536,7 +551,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - self.coerce_from_safe_fn(a, fn_ty_a, b) + self.coerce_from_safe_fn(a, fn_ty_a, b, + Adjust::UnsafeFnPointer, identity()) } fn coerce_from_fn_item(&self, @@ -554,10 +570,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) - .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, + Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -582,7 +598,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.cause.span, feature_gate::GateIssue::Language, feature_gate::CLOSURE_TO_FN_COERCION); - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -607,10 +623,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and_identity(pointer_ty, b) - .map(|(ty, _)| (ty, Adjust::ClosureFnPointer)) + self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -625,7 +640,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } }; @@ -634,50 +649,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mutbl_b, ty: mt_a.ty, }); - let (ty, noop) = self.unify_and_identity(a_unsafe, b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?; - // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - Ok((ty, - if is_ref { - Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - } - } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer - } else { - noop - })) - } -} - -fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Adjustment<'tcx>> - where E: Fn() -> I, - I: IntoIterator -{ - - let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; - - let fcx = coerce.fcx; - if let Adjust::DerefRef { unsize: true, .. } = adjust { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + self.unify_and(a_unsafe, b, if is_ref { + Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } + } else if mt_a.mutbl != mutbl_b { + Adjust::MutToConstPointer + } else { + identity() + }) } - - Ok(Adjustment { - kind: adjust, - target: ty - }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -694,9 +681,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); - let mut coerce = Coerce::new(self, cause); + let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; + let ok = coerce.coerce(&|| Some(expr), source, target)?; + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { @@ -773,9 +761,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); match result { - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } @@ -816,7 +805,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { @@ -828,7 +817,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); for expr in exprs() { diff --git a/src/test/compile-fail/issue-40288-2.rs b/src/test/compile-fail/issue-40288-2.rs new file mode 100644 index 0000000000000..c1e8cb8b6defb --- /dev/null +++ b/src/test/compile-fail/issue-40288-2.rs @@ -0,0 +1,41 @@ +// 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. + +fn prove_static(_: &'static T) {} + +fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = [x]; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let slice: &mut [_] = &mut out; + slice[0] = y; + } + out[0] +} + +struct Struct { + head: T, + _tail: U +} + +fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = Struct { head: x, _tail: [()] }; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let dst: &mut Struct<_, [()]> = &mut out; + dst.head = y; + } + out.head +} + +fn main() { + prove_static(lifetime_transmute_slice("", &String::from("foo"))); + prove_static(lifetime_transmute_struct("", &String::from("bar"))); +} diff --git a/src/test/compile-fail/issue-40288.rs b/src/test/compile-fail/issue-40288.rs new file mode 100644 index 0000000000000..b5418e85bec78 --- /dev/null +++ b/src/test/compile-fail/issue-40288.rs @@ -0,0 +1,30 @@ +// 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. + +fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) { + for val in &mut *to { + *val = refr; + } +} + +fn main() { + let ref init = 0i32; + let ref mut refr = 1i32; + + let mut out = [init]; + + save_ref(&*refr, &mut out); + + // This shouldn't be allowed as `refr` is borrowed + *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed + + // Prints 3?! + println!("{:?}", out[0]); +} diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index fb75b9aa1dd94..e37b6a2bb9c99 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR lifetime bound not satisfied + //~^ ERROR cannot infer //~| ERROR cannot infer } diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index dd94dfe1e0823..c0dd5200f6cb4 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR lifetime bound not satisfied + ss.r //~ ERROR cannot infer an appropriate lifetime } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR lifetime bound not satisfied + ss.r = b; //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index c5cf43e355d5a..ad6c5a31bbbd3 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR lifetime bound not satisfied + box v as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index fb726e31af586..17fd55b031b61 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime + Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index b4e527972e476..e8ada6a175571 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR lifetime bound not satisfied - //~^ ERROR cannot infer + x //~ ERROR cannot infer an appropriate lifetime + //~^ ERROR cannot infer an appropriate lifetime } struct Wrapper(T); diff --git a/src/test/compile-fail/variance-contravariant-arg-object.rs b/src/test/compile-fail/variance-contravariant-arg-object.rs index 1795ac95358d7..d3bf92e85f411 100644 --- a/src/test/compile-fail/variance-contravariant-arg-object.rs +++ b/src/test/compile-fail/variance-contravariant-arg-object.rs @@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) @@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box>) where 'max : 'min { // Previously OK: - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-covariant-arg-object.rs b/src/test/compile-fail/variance-covariant-arg-object.rs index ad059a467f570..0e94e35df2839 100644 --- a/src/test/compile-fail/variance-covariant-arg-object.rs +++ b/src/test/compile-fail/variance-covariant-arg-object.rs @@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) where 'max : 'min { // Previously OK, now an error as traits are invariant. - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-invariant-arg-object.rs b/src/test/compile-fail/variance-invariant-arg-object.rs index 9edb510b826a1..aa3e06c015d50 100644 --- a/src/test/compile-fail/variance-invariant-arg-object.rs +++ b/src/test/compile-fail/variance-invariant-arg-object.rs @@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs new file mode 100644 index 0000000000000..b19708f5a8931 --- /dev/null +++ b/src/test/run-pass/coerce-unsize-subtype.rs @@ -0,0 +1,48 @@ +// 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. + +// pretty-expanded FIXME #23616 + +use std::rc::Rc; + +fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {} + +// The two arguments are a subtype of their LUB, after coercion. +fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) { + lub_short(xs, ys); +} + +// The argument coerces to a subtype of the return type. +fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] { + xs +} + +// Rc is covariant over T just like &T. +fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> { + xs +} + +// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]` +// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`), +// regardless of the order they appear (in if-else/match/array). +fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]` +// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but +// rather the `&'b [&'a T]` LUB. +fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +fn main() {}