Rollup merge of #40319 - eddyb:it's-"unsize"-not-"unsound", r=nikomatsakis
Disallow subtyping between T and U in T: Unsize<U>. Because `&mut T` can be coerced to `&mut U`, `T` and `U` must be unified invariantly. Fixes #40288. E.g. coercing `&mut [&'a X; N]` to `&mut [&'b X]` must require `'a` be equal to `'b`, otherwise you can convert between `&'a X` and `&'b X` (in either direction), potentially unsoundly lengthening lifetimes. Subtyping here was introduced with `Unsize` in #24619 (landed in 1.1, original PR is #23785).
This commit is contained in:
commit
c886815e94
@ -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);
|
||||
|
||||
|
@ -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<Item = &'b hir::Expr>
|
||||
{
|
||||
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<Item = &'b hir::Expr>
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Vec<traits::PredicateObligation<'tcx>>>,
|
||||
}
|
||||
|
||||
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<T>`
|
||||
// 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<Target>`.
|
||||
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,52 +649,24 @@ 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
|
||||
}))
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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<Item = &'b hir::Expr>
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Adjustment {
|
||||
kind: adjust,
|
||||
target: ty
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Attempt to coerce an expression to a type, and return the
|
||||
/// adjusted type of the expression, if successful.
|
||||
@ -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() {
|
||||
|
41
src/test/compile-fail/issue-40288-2.rs
Normal file
41
src/test/compile-fail/issue-40288-2.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn prove_static<T: 'static + ?Sized>(_: &'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<T, U: ?Sized> {
|
||||
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")));
|
||||
}
|
30
src/test/compile-fail/issue-40288.rs
Normal file
30
src/test/compile-fail/issue-40288.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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]);
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
|
||||
// `Box<SomeTrait>` 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<SomeTrait>) {
|
||||
@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
|
||||
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
|
||||
// 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() {
|
||||
|
@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
|
||||
|
||||
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
|
||||
// A outlives 'a AND 'b...but not 'c.
|
||||
box v as Box<SomeTrait+'a> //~ ERROR lifetime bound not satisfied
|
||||
box v as Box<SomeTrait+'a> //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
|
||||
|
||||
fn static_proc(x: &isize) -> Box<FnMut()->(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() { }
|
||||
|
@ -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>(T);
|
||||
|
@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||
-> Box<Get<&'min i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v //~ ERROR mismatched types
|
||||
v //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||
@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||
where 'max : 'min
|
||||
{
|
||||
// Previously OK:
|
||||
v //~ ERROR mismatched types
|
||||
v //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||
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<Get<&'min i32>>)
|
||||
-> Box<Get<&'max i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v //~ ERROR mismatched types
|
||||
v //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||
-> Box<Get<&'min i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v //~ ERROR mismatched types
|
||||
v //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||
-> Box<Get<&'max i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v //~ ERROR mismatched types
|
||||
v //~ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
48
src/test/run-pass/coerce-unsize-subtype.rs
Normal file
48
src/test/run-pass/coerce-unsize-subtype.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> 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() {}
|
Loading…
Reference in New Issue
Block a user