Use subtyping on the target of unsizing coercions.
This commit is contained in:
parent
74bc7fda8c
commit
cfb41aedd3
10 changed files with 80 additions and 22 deletions
|
@ -453,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => (source, None),
|
_ => (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);
|
let mut selcx = traits::SelectionContext::new(self);
|
||||||
|
|
||||||
// Use a FIFO queue for this custom fulfillment procedure.
|
// Use a FIFO queue for this custom fulfillment procedure.
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
let mut obligations = vec![];
|
|
||||||
|
|
||||||
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
||||||
let cause = ObligationCause::misc(self.cause.span, self.body_id);
|
let cause = ObligationCause::misc(self.cause.span, self.body_id);
|
||||||
queue.push_back(self.tcx
|
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
|
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||||
|
@ -475,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
let trait_ref = match obligation.predicate {
|
let trait_ref = match obligation.predicate {
|
||||||
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
|
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
obligations.push(obligation);
|
coercion.obligations.push(obligation);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -503,11 +517,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
success(Adjust::DerefRef {
|
Ok(coercion)
|
||||||
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
|
||||||
autoref: reborrow,
|
|
||||||
unsize: true,
|
|
||||||
}, target, obligations)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_from_safe_fn(&self,
|
fn coerce_from_safe_fn(&self,
|
||||||
|
|
|
@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
|
||||||
// which fails to type check.
|
// which fails to type check.
|
||||||
|
|
||||||
ss
|
ss
|
||||||
//~^ ERROR lifetime bound not satisfied
|
//~^ ERROR cannot infer
|
||||||
//~| 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
|
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
|
||||||
// is illegal.
|
// 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>) {
|
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>) {
|
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
|
||||||
// Here we override the lifetimes explicitly, and so naturally we get an error.
|
// 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() {
|
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> {
|
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
|
||||||
// A outlives 'a AND 'b...but not '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() {
|
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> {
|
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
|
||||||
// This is illegal, because the region bound on `proc` is '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() { }
|
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 {
|
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
|
||||||
// Without knowing 'a:'b, we can't coerce
|
// Without knowing 'a:'b, we can't coerce
|
||||||
x //~ ERROR lifetime bound not satisfied
|
x //~ ERROR cannot infer an appropriate lifetime
|
||||||
//~^ ERROR cannot infer
|
//~^ ERROR cannot infer an appropriate lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Wrapper<T>(T);
|
struct Wrapper<T>(T);
|
||||||
|
|
|
@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||||
-> Box<Get<&'min i32>>
|
-> Box<Get<&'min i32>>
|
||||||
where 'max : 'min
|
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>>)
|
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
|
where 'max : 'min
|
||||||
{
|
{
|
||||||
// Previously OK:
|
// Previously OK:
|
||||||
v //~ ERROR mismatched types
|
v //~ ERROR cannot infer an appropriate lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||||
where 'max : 'min
|
where 'max : 'min
|
||||||
{
|
{
|
||||||
// Previously OK, now an error as traits are invariant.
|
// 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>>)
|
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||||
-> Box<Get<&'max i32>>
|
-> Box<Get<&'max i32>>
|
||||||
where 'max : 'min
|
where 'max : 'min
|
||||||
{
|
{
|
||||||
v //~ ERROR mismatched types
|
v //~ ERROR cannot infer an appropriate lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
||||||
-> Box<Get<&'min i32>>
|
-> Box<Get<&'min i32>>
|
||||||
where 'max : 'min
|
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>>)
|
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||||
-> Box<Get<&'max i32>>
|
-> Box<Get<&'max i32>>
|
||||||
where 'max : 'min
|
where 'max : 'min
|
||||||
{
|
{
|
||||||
v //~ ERROR mismatched types
|
v //~ ERROR cannot infer an appropriate lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
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…
Add table
Reference in a new issue