about summary refs log tree commit diff
path: root/src/test/ui
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-04-30 20:15:20 +0200
committerGitHub <noreply@github.com>2020-04-30 20:15:20 +0200
commit09f3c908bb4e65154d974a8a9d38e57f00d8ae04 (patch)
treeaa32bbb2b635217db09218da0d9d4db872ddfa0b /src/test/ui
parenteece58a8e35c444afba6fa34873bc0244e32cd29 (diff)
parentcb9458d3ff7f64c309bc80776d71e4f73705f4ce (diff)
downloadrust-09f3c908bb4e65154d974a8a9d38e57f00d8ae04.tar.gz
rust-09f3c908bb4e65154d974a8a9d38e57f00d8ae04.zip
Rollup merge of #70950 - nikomatsakis:leak-check-nll-2, r=matthewjasper
extend NLL checker to understand `'empty` combined with universes

This PR extends the NLL region checker to understand `'empty` combined with universes. In particular, it means that the NLL region checker no longer considers `exists<R2> { forall<R1> { R1: R2 } }` to be provable. This is work towards https://github.com/rust-lang/rust/issues/59490, but we're not all the way there. One thing in particular it does not address is error messages.

The modifications to the NLL region inference code turned out to be simpler than expected. The main change is to require that if `R1: R2` then `universe(R1) <= universe(R2)`.

This constraint follows from the region lattice (shown below), because we assume then that `R2` is "at least" `empty(Universe(R2))`, and hence if `R1: R2` (i.e., `R1 >= R2` on the lattice) then `R1` must be in some universe that can name `'empty(Universe(R2))`, which requires that `Universe(R1) <= Universe(R2)`.

```
static ----------+-----...------+       (greatest)
|                |              |
early-bound and  |              |
free regions     |              |
|                |              |
scope regions    |              |
|                |              |
empty(root)   placeholder(U1)   |
|            /                  |
|           /         placeholder(Un)
empty(U1) --         /
|                   /
...                /
|                 /
empty(Un) --------                      (smallest)
```

I also made what turned out to be a somewhat unrelated change to add a special region to represent `'empty(U0)`, which we use (somewhat hackily) to indicate well-formedness checks in some parts of the compiler. This fixes #68550.

I did some investigation into fixing the error message situation. That's a bit trickier: the existing "nice region error" code around placeholders relies on having better error tracing than NLL currently provides, so that it knows (e.g.) that the constraint arose from applying a trait impl and things like that. I feel like I was hoping *not* to do such fine-grained tracing in NLL, and it seems like we...largely...got away with that. I'm not sure yet if we'll have to add more tracing information or if there is some sort of alternative.

It's worth pointing out though that I've not kind of shifted my opinion on whose job it should be to enforce lifetimes: I tend to think we ought to be moving back towards *something like* the leak-check (just not the one we *had*). If we took that approach, it would actually resolve this aspect of the error message problem, because we would be resolving 'higher-ranked errors' in the trait solver itself, and hence we wouldn't have to thread as much causal information back to the region checker. I think it would also help us with removing the leak check while not breaking some of the existing crates out there.

Regardless, I think it's worth landing this change, because it was relatively simple and it aligns the set of programs that NLL accepts with those that are accepted by the main region checker, and hence should at least *help* us in migration (though I guess we still also have to resolve the existing crates that rely on leak check for coherence).

r? @matthewjasper
Diffstat (limited to 'src/test/ui')
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr4
-rw-r--r--src/test/ui/hrtb/due-to-where-clause.nll.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr2
-rw-r--r--src/test/ui/nll/issue-68550.rs15
-rw-r--r--src/test/ui/nll/issue-68550.stderr16
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs36
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr20
-rw-r--r--src/test/ui/nll/type-check-pointer-comparisons.rs8
-rw-r--r--src/test/ui/nll/type-check-pointer-comparisons.stderr14
10 files changed, 109 insertions, 10 deletions
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
index c69595a3f4d..da584e8ad4e 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
@@ -34,7 +34,7 @@ LL | |     (a, b)
 LL | | }
    | |_^
    |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#4r
+   = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/ret-impl-trait-no-fg.rs:9:1
@@ -48,7 +48,7 @@ LL | |     (a, b)
 LL | | }
    | |_^
    |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
+   = note: hidden type `(&u8, &u8)` captures lifetime '_#6r
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/hrtb/due-to-where-clause.nll.stderr b/src/test/ui/hrtb/due-to-where-clause.nll.stderr
index e476047a7a6..90803a0adb0 100644
--- a/src/test/ui/hrtb/due-to-where-clause.nll.stderr
+++ b/src/test/ui/hrtb/due-to-where-clause.nll.stderr
@@ -2,7 +2,7 @@ error: higher-ranked subtype error
   --> $DIR/due-to-where-clause.rs:2:5
    |
 LL |     test::<FooS>(&mut 42);
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
index 5bfc446f6a5..129af80ce4a 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
@@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
    |
-   = note: hidden type `Ordinary<'_>` captures lifetime '_#8r
+   = note: hidden type `Ordinary<'_>` captures lifetime '_#9r
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
index 7291eee7b9e..de6d5edcae5 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
@@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
    |
-   = note: hidden type `Ordinary<'_>` captures lifetime '_#5r
+   = note: hidden type `Ordinary<'_>` captures lifetime '_#6r
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-68550.rs b/src/test/ui/nll/issue-68550.rs
new file mode 100644
index 00000000000..6bfd18de18c
--- /dev/null
+++ b/src/test/ui/nll/issue-68550.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #68550.
+//
+// The `&'static A:` where clause was triggering
+// ICEs because it wound up being compiled to reference
+// the `'empty(U0)` region.
+
+fn run<'a, A>(x: A)
+where
+    A: 'static,
+    &'static A: ,
+{
+    let _: &'a A = &x; //~ ERROR `x` does not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-68550.stderr b/src/test/ui/nll/issue-68550.stderr
new file mode 100644
index 00000000000..e234ebb04e1
--- /dev/null
+++ b/src/test/ui/nll/issue-68550.stderr
@@ -0,0 +1,16 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-68550.rs:12:20
+   |
+LL | fn run<'a, A>(x: A)
+   |        -- lifetime `'a` defined here
+...
+LL |     let _: &'a A = &x;
+   |            -----   ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'a`
+LL | }
+   | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
new file mode 100644
index 00000000000..d3964a7f515
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
@@ -0,0 +1,36 @@
+// Test that the NLL solver cannot find a solution
+// for `exists<R1> { forall<R1> { R2: R1 } }`.
+//
+// In this test, the impl should match `fn(T)` for some `T`,
+// but we ask it to match `for<'a> fn(&'a ())`. Due to argument
+// contravariance, this effectively requires a `T = &'b ()` where
+// `forall<'a> { 'a: 'b }`. Therefore, we get an error.
+//
+// Note the use of `-Zno-leak-check` and `feature(nll)` here. These
+// are presently required in order to skip the leak-check errors.
+//
+// c.f. Issue #57642.
+//
+// compile-flags:-Zno-leak-check
+
+#![feature(nll)]
+
+trait Y {
+    type F;
+    fn make_f() -> Self::F;
+}
+
+impl<T> Y for fn(T) {
+    type F = fn(T);
+
+    fn make_f() -> Self::F {
+        |_| {}
+    }
+}
+
+fn main() {
+    let _x = <fn(&())>::make_f();
+    //~^ higher-ranked subtype error
+    //~| higher-ranked subtype error
+    //~| higher-ranked subtype error
+}
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
new file mode 100644
index 00000000000..70fb877d716
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -0,0 +1,20 @@
+error: higher-ranked subtype error
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/nll/type-check-pointer-comparisons.rs b/src/test/ui/nll/type-check-pointer-comparisons.rs
index 3c900356fab..298a6ef7ab3 100644
--- a/src/test/ui/nll/type-check-pointer-comparisons.rs
+++ b/src/test/ui/nll/type-check-pointer-comparisons.rs
@@ -21,13 +21,13 @@ fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
 }
 
 fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) {
-    // Ideally this should compile with the operands swapped as well, but HIR
-    // type checking prevents it (and stops compilation) for now.
-    f == g; // OK
+    f == g;
+    //~^ ERROR higher-ranked subtype error
 }
 
 fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) {
-    f == g; // OK
+    f == g;
+    //~^ ERROR higher-ranked subtype error
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr
index f350b861eb6..0fc7480260f 100644
--- a/src/test/ui/nll/type-check-pointer-comparisons.stderr
+++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr
@@ -76,5 +76,17 @@ LL |     f == g;
 
 help: `'a` and `'b` must be the same: replace one with the other
 
-error: aborting due to 6 previous errors
+error: higher-ranked subtype error
+  --> $DIR/type-check-pointer-comparisons.rs:24:5
+   |
+LL |     f == g;
+   |     ^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/type-check-pointer-comparisons.rs:29:5
+   |
+LL |     f == g;
+   |     ^^^^^^
+
+error: aborting due to 8 previous errors