]> git.lizzy.rs Git - rust.git/commitdiff
Use subtyping on the target of unsizing coercions.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 9 Mar 2017 03:54:52 +0000 (05:54 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 9 Mar 2017 19:43:45 +0000 (21:43 +0200)
src/librustc_typeck/check/coercion.rs
src/test/compile-fail/object-lifetime-default-elision.rs
src/test/compile-fail/object-lifetime-default-from-box-error.rs
src/test/compile-fail/regions-close-over-type-parameter-multiple.rs
src/test/compile-fail/regions-proc-bound-capture.rs
src/test/compile-fail/regions-trait-object-subtyping.rs
src/test/compile-fail/variance-contravariant-arg-object.rs
src/test/compile-fail/variance-covariant-arg-object.rs
src/test/compile-fail/variance-invariant-arg-object.rs
src/test/run-pass/coerce-unsize-subtype.rs [new file with mode: 0644]

index 651058728816ef231cbfee9c5c6d98582dfee155..c43291557f7fa4034959ac0f2fb1eb06a89c03ac 100644 (file)
@@ -453,18 +453,32 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             }
             _ => (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<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
@@ -475,7 +489,7 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             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 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             }
         }
 
-        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,
index fb75b9aa1dd941ac83d9537b1f714f4c5743ad6d..e37b6a2bb9c99aa0993c5c3525edc5c322efc696 100644 (file)
@@ -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
 }
 
index dd94dfe1e0823463701bafc0f68dba06963dc831..c0dd5200f6cb4e97be5e24eddf6f1d699f27052a 100644 (file)
@@ -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() {
index c5cf43e355d5aae777bef840103e56e29cf40c33..ad6c5a31bbbd3fbc4076af08cde2723acd0992ad 100644 (file)
@@ -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() {
index fb726e31af586a5ba81e434d086ccf8d3f7af9d1..17fd55b031b61463513dc077928a330bb5ffe6ac 100644 (file)
@@ -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() { }
index b4e527972e4765b6339e457ed769e6ab1e844301..e8ada6a1755719205422e74f43591b9bf8ea138f 100644 (file)
@@ -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);
index 1795ac95358d7c6c29c2bde494f0212b16ad6076..d3bf92e85f411a5207e03786dc844487d7417dcf 100644 (file)
@@ -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() { }
index ad059a467f570bb2d4b9e5ef872d907ff1f8522c..0e94e35df2839895fdc389f970eeb6396db708e0 100644 (file)
@@ -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() { }
index 9edb510b826a12df92df2fe2ea40966ca9ac98fa..aa3e06c015d503829e89c839c2beb07e52a40e4e 100644 (file)
@@ -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() { }
diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs
new file mode 100644 (file)
index 0000000..b19708f
--- /dev/null
@@ -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() {}