about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/traits/util.rs78
-rw-r--r--src/test/compile-fail/issue-18937.rs12
-rw-r--r--src/test/compile-fail/traits-elaborate-type-region-proj.rs27
-rw-r--r--src/test/compile-fail/traits-elaborate-type-region-unrelated.rs27
-rw-r--r--src/test/run-pass/issue-18937-1.rs30
-rw-r--r--src/test/run-pass/traits-elaborate-type-region.rs58
6 files changed, 212 insertions, 20 deletions
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index a0792dcf4dd..0c5ff3cd279 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -1,3 +1,4 @@
+
 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
@@ -11,6 +12,7 @@
 use hir::def_id::DefId;
 use ty::subst::{Subst, Substs};
 use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
+use ty::outlives::Component;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
 
@@ -166,27 +168,63 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
             ty::Predicate::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
-            ty::Predicate::RegionOutlives(..) |
-            ty::Predicate::TypeOutlives(..) => {
-                // Currently, we do not "elaborate" predicates like
-                // `'a : 'b` or `T : 'a`.  We could conceivably do
-                // more here.  For example,
-                //
-                //     &'a int : 'b
-                //
-                // implies that
-                //
-                //     'a : 'b
-                //
-                // and we could get even more if we took WF
-                // constraints into account. For example,
-                //
-                //     &'a &'b int : 'c
-                //
-                // implies that
+
+            ty::Predicate::RegionOutlives(..) => {
+                // Nothing to elaborate from `'a: 'b`.
+            }
+
+            ty::Predicate::TypeOutlives(ref data) => {
+                // We know that `T: 'a` for some type `T`. We can
+                // often elaborate this. For example, if we know that
+                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
+                // we know `&'a U: 'b`, then we know that `'a: 'b` and
+                // `U: 'b`.
                 //
-                //     'b : 'a
-                //     'a : 'c
+                // We can basically ignore bound regions here. So for
+                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
+                // `'a: 'b`.
+
+                // Ignore `for<'a> T: 'a` -- we might in the future
+                // consider this as evidence that `Foo: 'static`, but
+                // I'm a bit wary of such constructions and so for now
+                // I want to be conservative. --nmatsakis
+                let ty_max = data.skip_binder().0;
+                let r_min = data.skip_binder().1;
+                if r_min.is_bound() {
+                    return;
+                }
+
+                let visited = &mut self.visited;
+                self.stack.extend(
+                    tcx.outlives_components(ty_max)
+                       .into_iter()
+                       .filter_map(|component| match component {
+                           Component::Region(r) => if r.is_bound() {
+                               None
+                           } else {
+                               Some(ty::Predicate::RegionOutlives(
+                                   ty::Binder(ty::OutlivesPredicate(r, r_min))))
+                           },
+
+                           Component::Param(p) => {
+                               let ty = tcx.mk_param(p.idx, p.name);
+                               Some(ty::Predicate::TypeOutlives(
+                                   ty::Binder(ty::OutlivesPredicate(ty, r_min))))
+                           },
+
+                           Component::UnresolvedInferenceVariable(_) => {
+                               None
+                           },
+
+                           Component::Projection(_) |
+                           Component::EscapingProjection(_) => {
+                               // We can probably do more here. This
+                               // corresponds to a case like `<T as
+                               // Foo<'a>>::U: 'b`.
+                               None
+                           },
+                       })
+                       .filter(|p| visited.insert(p)));
             }
         }
     }
diff --git a/src/test/compile-fail/issue-18937.rs b/src/test/compile-fail/issue-18937.rs
index ea186055147..321359cb96c 100644
--- a/src/test/compile-fail/issue-18937.rs
+++ b/src/test/compile-fail/issue-18937.rs
@@ -1,3 +1,15 @@
+// Copyright 2016 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.
+
+// Regression test for #18937.
+
 use std::fmt;
 
 #[derive(Debug)]
diff --git a/src/test/compile-fail/traits-elaborate-type-region-proj.rs b/src/test/compile-fail/traits-elaborate-type-region-proj.rs
new file mode 100644
index 00000000000..42a2e820d2e
--- /dev/null
+++ b/src/test/compile-fail/traits-elaborate-type-region-proj.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#![allow(dead_code)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized, U> {
+    fn foo() where T: 'a;
+}
+
+// `U::Item: 'a` does not imply that `U: 'a`
+impl<'a, U: Iterator> Master<'a, U::Item, U> for () {
+    fn foo() where U: 'a { }
+    //~^ ERROR parameter type `V` may not live long enough
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/compile-fail/traits-elaborate-type-region-unrelated.rs b/src/test/compile-fail/traits-elaborate-type-region-unrelated.rs
new file mode 100644
index 00000000000..3c11b8bb1ef
--- /dev/null
+++ b/src/test/compile-fail/traits-elaborate-type-region-unrelated.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#![allow(dead_code)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized, U> {
+    fn foo() where T: 'a;
+}
+
+// `U: 'a` does not imply `V: 'a`
+impl<'a, U, V> Master<'a, U, V> for () {
+    fn foo() where V: 'a { }
+    //~^ ERROR parameter type `V` may not live long enough
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/run-pass/issue-18937-1.rs b/src/test/run-pass/issue-18937-1.rs
new file mode 100644
index 00000000000..7a24d087b44
--- /dev/null
+++ b/src/test/run-pass/issue-18937-1.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+// Test that we are able to type-check this example. In particular,
+// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
+// when `T=[U]` it implies that `U: 'a`).
+//
+// Regr. test for live code we found in the wild when fixing #18937.
+
+pub trait Leak<T : ?Sized> {
+    fn leak<'a>(self) -> &'a T where T: 'a;
+}
+
+impl<U> Leak<[U]> for Vec<U> {
+    fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
+        let r: *mut [U] = &mut self[..];
+        std::mem::forget(self);
+        unsafe { &mut *r }
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/run-pass/traits-elaborate-type-region.rs b/src/test/run-pass/traits-elaborate-type-region.rs
new file mode 100644
index 00000000000..4621c2ca4be
--- /dev/null
+++ b/src/test/run-pass/traits-elaborate-type-region.rs
@@ -0,0 +1,58 @@
+// Copyright 2016 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.
+
+#![allow(dead_code)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized> {
+    fn foo() where T: 'a;
+}
+
+// [U]: 'a => U: 'a
+impl<'a, U> Master<'a, [U]> for () {
+    fn foo() where U: 'a { }
+}
+
+// &'b U: 'a => 'b: 'a, U: 'a
+impl<'a, 'b, U> Master<'a, &'b U> for () {
+    fn foo() where 'b: 'a, U: 'a { }
+}
+
+// &'b [U]: 'a => 'b: 'a, U: 'a
+impl<'a, 'b, U> Master<'a, &'b [U]> for () {
+    fn foo() where 'b: 'a, U: 'a { }
+}
+
+// Foo<'b>: 'a => 'b: 'a
+struct Foo<'a> { x: &'a () }
+impl<'a, 'b> Master<'a, Foo<'b>> for () {
+    fn foo() where 'b: 'a { }
+}
+
+// Bar<'b, T>: 'a => 'b: 'a, T: 'a
+struct Bar<'a, T: 'a> { x: &'a T }
+impl<'a, 'b, T> Master<'a, Bar<'b, T>> for () {
+    fn foo() where 'b: 'a, T: 'a { }
+}
+
+// fn(T): 'a => T: 'a
+impl<'a, T> Master<'a, fn(T)> for () {
+    fn foo() where T: 'a { }
+}
+
+// fn() -> T: 'a => T: 'a
+impl<'a, T> Master<'a, fn() -> T> for () {
+    fn foo() where T: 'a { }
+}
+
+fn main() {
+    println!("Hello, world!");
+}