diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 65105872881..c43291557f7 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -453,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 obligations = 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 @@ -475,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(), _ => { - obligations.push(obligation); + coercion.obligations.push(obligation); continue; } }; @@ -503,11 +517,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - success(Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, - }, target, obligations) + Ok(coercion) } fn coerce_from_safe_fn(&self, diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index fb75b9aa1dd..e37b6a2bb9c 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 dd94dfe1e08..c0dd5200f6c 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 c5cf43e355d..ad6c5a31bbb 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 fb726e31af5..17fd55b031b 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 b4e527972e4..e8ada6a1755 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 1795ac95358..d3bf92e85f4 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 ad059a467f5..0e94e35df28 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 9edb510b826..aa3e06c015d 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 00000000000..b19708f5a89 --- /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() {}