Skip to content

Commit cfb41ae

Browse files
committed
Use subtyping on the target of unsizing coercions.
1 parent 74bc7fd commit cfb41ae

10 files changed

+80
-22
lines changed

src/librustc_typeck/check/coercion.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -453,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
453453
}
454454
_ => (source, None),
455455
};
456-
let source = source.adjust_for_autoref(self.tcx, reborrow);
456+
let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
457+
458+
let adjust = Adjust::DerefRef {
459+
autoderefs: if reborrow.is_some() { 1 } else { 0 },
460+
autoref: reborrow,
461+
unsize: true,
462+
};
463+
464+
// Setup either a subtyping or a LUB relationship between
465+
// the `CoerceUnsized` target type and the expected type.
466+
// We only have the latter, so we use an inference variable
467+
// for the former and let type inference do the rest.
468+
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
469+
let coerce_target = self.next_ty_var(origin);
470+
let mut coercion = self.unify_and(coerce_target, target, adjust)?;
457471

458472
let mut selcx = traits::SelectionContext::new(self);
459473

460474
// Use a FIFO queue for this custom fulfillment procedure.
461475
let mut queue = VecDeque::new();
462-
let mut obligations = vec![];
463476

464477
// Create an obligation for `Source: CoerceUnsized<Target>`.
465478
let cause = ObligationCause::misc(self.cause.span, self.body_id);
466479
queue.push_back(self.tcx
467-
.predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
480+
.predicate_for_trait_def(cause, coerce_unsized_did, 0,
481+
coerce_source, &[coerce_target]));
468482

469483
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
470484
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -475,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
475489
let trait_ref = match obligation.predicate {
476490
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
477491
_ => {
478-
obligations.push(obligation);
492+
coercion.obligations.push(obligation);
479493
continue;
480494
}
481495
};
@@ -503,11 +517,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
503517
}
504518
}
505519

506-
success(Adjust::DerefRef {
507-
autoderefs: if reborrow.is_some() { 1 } else { 0 },
508-
autoref: reborrow,
509-
unsize: true,
510-
}, target, obligations)
520+
Ok(coercion)
511521
}
512522

513523
fn coerce_from_safe_fn(&self,

src/test/compile-fail/object-lifetime-default-elision.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
7979
// which fails to type check.
8080

8181
ss
82-
//~^ ERROR lifetime bound not satisfied
82+
//~^ ERROR cannot infer
8383
//~| ERROR cannot infer
8484
}
8585

src/test/compile-fail/object-lifetime-default-from-box-error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
2525
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
2626
// is illegal.
2727

28-
ss.r //~ ERROR lifetime bound not satisfied
28+
ss.r //~ ERROR cannot infer an appropriate lifetime
2929
}
3030

3131
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
@@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
3838
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
3939
// Here we override the lifetimes explicitly, and so naturally we get an error.
4040

41-
ss.r = b; //~ ERROR lifetime bound not satisfied
41+
ss.r = b; //~ ERROR cannot infer an appropriate lifetime
4242
}
4343

4444
fn main() {

src/test/compile-fail/regions-close-over-type-parameter-multiple.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
2727

2828
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
2929
// A outlives 'a AND 'b...but not 'c.
30-
box v as Box<SomeTrait+'a> //~ ERROR lifetime bound not satisfied
30+
box v as Box<SomeTrait+'a> //~ ERROR cannot infer an appropriate lifetime
3131
}
3232

3333
fn main() {

src/test/compile-fail/regions-proc-bound-capture.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
1616

1717
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
1818
// This is illegal, because the region bound on `proc` is 'static.
19-
Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime
19+
Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime
2020
}
2121

2222
fn main() { }

src/test/compile-fail/regions-trait-object-subtyping.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
2222

2323
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
2424
// Without knowing 'a:'b, we can't coerce
25-
x //~ ERROR lifetime bound not satisfied
26-
//~^ ERROR cannot infer
25+
x //~ ERROR cannot infer an appropriate lifetime
26+
//~^ ERROR cannot infer an appropriate lifetime
2727
}
2828

2929
struct Wrapper<T>(T);

src/test/compile-fail/variance-contravariant-arg-object.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
2121
-> Box<Get<&'min i32>>
2222
where 'max : 'min
2323
{
24-
v //~ ERROR mismatched types
24+
v //~ ERROR cannot infer an appropriate lifetime
2525
}
2626

2727
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
2828
-> Box<Get<&'max i32>>
2929
where 'max : 'min
3030
{
3131
// Previously OK:
32-
v //~ ERROR mismatched types
32+
v //~ ERROR cannot infer an appropriate lifetime
3333
}
3434

3535
fn main() { }

src/test/compile-fail/variance-covariant-arg-object.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
2222
where 'max : 'min
2323
{
2424
// Previously OK, now an error as traits are invariant.
25-
v //~ ERROR mismatched types
25+
v //~ ERROR cannot infer an appropriate lifetime
2626
}
2727

2828
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
2929
-> Box<Get<&'max i32>>
3030
where 'max : 'min
3131
{
32-
v //~ ERROR mismatched types
32+
v //~ ERROR cannot infer an appropriate lifetime
3333
}
3434

3535
fn main() { }

src/test/compile-fail/variance-invariant-arg-object.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
1818
-> Box<Get<&'min i32>>
1919
where 'max : 'min
2020
{
21-
v //~ ERROR mismatched types
21+
v //~ ERROR cannot infer an appropriate lifetime
2222
}
2323

2424
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
2525
-> Box<Get<&'max i32>>
2626
where 'max : 'min
2727
{
28-
v //~ ERROR mismatched types
28+
v //~ ERROR cannot infer an appropriate lifetime
2929
}
3030

3131
fn main() { }
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// pretty-expanded FIXME #23616
12+
13+
use std::rc::Rc;
14+
15+
fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
16+
17+
// The two arguments are a subtype of their LUB, after coercion.
18+
fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
19+
lub_short(xs, ys);
20+
}
21+
22+
// The argument coerces to a subtype of the return type.
23+
fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
24+
xs
25+
}
26+
27+
// Rc<T> is covariant over T just like &T.
28+
fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
29+
xs
30+
}
31+
32+
// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
33+
// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`),
34+
// regardless of the order they appear (in if-else/match/array).
35+
fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
36+
let _order1 = [xs, ys];
37+
let _order2 = [ys, xs];
38+
}
39+
40+
// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
41+
// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but
42+
// rather the `&'b [&'a T]` LUB.
43+
fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
44+
let _order1 = [xs, ys];
45+
let _order2 = [ys, xs];
46+
}
47+
48+
fn main() {}

0 commit comments

Comments
 (0)