about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2018-09-29 00:22:35 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-10-01 22:44:45 +0300
commit1069c0e38f28539ab29c32921435b3f28eb63808 (patch)
treee013610f0cc2eec2807baa30beebadb8a16da024
parent9d44e9eb7ce65d1ae13db56c56713de4f4ef95bd (diff)
add a special case for literal `'static: 'a` where-clauses
This makes evaluation more consistent with fulfillment.
-rw-r--r--src/librustc/traits/select.rs46
-rw-r--r--src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs33
2 files changed, 64 insertions, 15 deletions
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 0e087153673..860914d1984 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -727,26 +727,42 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 if r_a == r_b {
                     // for<'a> 'a: 'a. OK
                     Ok(EvaluatedToOk)
+                } else if **r_a == ty::ReStatic {
+                    // 'static: 'x always holds.
+                    //
+                    // This special case is handled somewhat inconsistently - if we
+                    // have an inference variable that is supposed to be equal to
+                    // `'static`, then we don't allow it to be equated to an LBR,
+                    // but if we have a literal `'static`, then we *do*.
+                    //
+                    // This is actually consistent with how our region inference works.
+                    //
+                    // It would appear that this sort of inconsistency would
+                    // cause "instability" problems with evaluation caching. However,
+                    // evaluation caching is only for trait predicates, and when
+                    // trait predicates create nested obligations, they contain
+                    // inference variables for all the regions in the trait - the
+                    // only way this codepath can be reached from trait predicate
+                    // evaluation is when the user typed an explicit `where 'static: 'a`
+                    // lifetime bound (in which case we want to return EvaluatedToOk).
+                    //
+                    // If we ever want to handle inference variables that might be
+                    // equatable with ReStatic, we need to make sure we are not confused by
+                    // technically-allowed-by-RFC-447-but-probably-should-not-be
+                    // impls such as
+                    // ```Rust
+                    // impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's
+                    // ```
+                    Ok(EvaluatedToOk)
                 } else if r_a.is_late_bound() || r_b.is_late_bound() {
                     // There is no current way to prove `for<'a> 'a: 'x`
                     // unless `'a = 'x`, because there are no bounds involving
                     // lifetimes.
 
-                    // It is possible to solve `for<'a> 'x: 'a` where `'x`
-                    // is a free region by forcing `'x = 'static`. However,
-                    // fulfillment does not *quite* do this ATM (it calls
-                    // `region_outlives_predicate`, which is OK if `'x` is
-                    // literally ReStatic, but is *not* OK if `'x` is any
-                    // sort of inference variable, even if it *is* equal
-                    // to `'static`).
-
-                    // If we ever want to handle that sort of obligations,
-                    // we need to make sure we are not confused by
-                    // technically-allowed-by-RFC-447-but-probably-should-not-be
-                    // impls such as
-                    // ```Rust
-                    // impl<'a, 's, T> X<'s> for T where T: Debug + 's, 'a: 's
-                    // ```
+                    // It might be possible to prove `for<'a> 'x: 'a` by forcing `'x`
+                    // to be `'static`. However, this is not currently done by type
+                    // inference unless `'x` is literally ReStatic. See the comment
+                    // above.
 
                     // We don't want to allow this sort of reasoning in intercrate
                     // mode, for backwards-compatibility reasons.
diff --git a/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs b/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs
new file mode 100644
index 00000000000..1051bec6307
--- /dev/null
+++ b/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs
@@ -0,0 +1,33 @@
+// Copyright 2018 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.
+
+// run-pass
+
+trait Foo<'a> {
+    fn xyz(self);
+}
+impl<'a, T> Foo<'a> for T where 'static: 'a {
+    fn xyz(self) {}
+}
+
+trait Bar {
+    fn uvw(self);
+}
+impl<T> Bar for T where for<'a> T: Foo<'a> {
+    fn uvw(self) { self.xyz(); }
+}
+
+fn foo<T>(t: T) where T: Bar {
+    t.uvw();
+}
+
+fn main() {
+    foo(0);
+}