about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-21 12:17:03 +0000
committerbors <bors@rust-lang.org>2022-11-21 12:17:03 +0000
commit7fe6f36224e92db6fbde952e0b7e50863161f6ee (patch)
tree581f4b1ae8eb562da89b71d1bdf4a0fc3d8d5f05 /src
parent736c675d2ab65bcde6554e1b73340c2dbc27c85a (diff)
parentb37feca804ece8eed650465faab65f5c53494b33 (diff)
downloadrust-7fe6f36224e92db6fbde952e0b7e50863161f6ee.tar.gz
rust-7fe6f36224e92db6fbde952e0b7e50863161f6ee.zip
Auto merge of #103491 - cjgillot:self-rpit, r=oli-obk
Support using `Self` or projections inside an RPIT/async fn

I reuse the same idea as https://github.com/rust-lang/rust/pull/103449 to use variances to encode whether a lifetime parameter is captured by impl-trait.

The current implementation of async and RPIT replace all lifetimes from the parent generics by `'static`.  This PR changes the scheme
```rust
impl<'a> Foo<'a> {
    fn foo<'b, T>() -> impl Into<Self> + 'b { ... }
}

opaque Foo::<'_a>::foo::<'_b, T>::opaque<'b>: Into<Foo<'_a>> + 'b;
impl<'a> Foo<'a> {
    // OLD
    fn foo<'b, T>() -> Foo::<'static>::foo::<'static, T>::opaque::<'b> { ... }
                             ^^^^^^^ the `Self` becomes `Foo<'static>`

    // NEW
    fn foo<'b, T>() -> Foo::<'a>::foo::<'b, T>::opaque::<'b> { ... }
                             ^^ the `Self` stays `Foo<'a>`
}
```

There is the same issue with projections. In the example, substitute `Self` by `<T as Trait<'b>>::Assoc` in the sugared version, and `Foo<'_a>` by `<T as Trait<'_b>>::Assoc` in the desugared one.

This allows to support `Self` in impl-trait, since we do not replace lifetimes by `'static` any more.  The same trick allows to use projections like `T::Assoc` where `Self` is allowed.  The feature is gated behind a `impl_trait_projections` feature gate.

The implementation relies on 2 tweaking rules for opaques in 2 places:
- we only relate substs that correspond to captured lifetimes during TypeRelation;
- we only list captured lifetimes in choice region computation.

For simplicity, I encoded the "capturedness" of lifetimes as a variance, `Bivariant` vs `Invariant` for unused vs captured lifetimes. The `variances_of` query used to ICE for opaques.

Impl-trait that do not reference `Self` or projections will have their variances as:
- `o` (invariant) for each parent type or const;
- `*` (bivariant) for each parent lifetime --> will not participate in borrowck;
- `o` (invariant) for each own lifetime.

Impl-trait that does reference `Self` and/or projections will have some parent lifetimes marked as `o` (as the example above), and participate in type relation and borrowck.  In the example above, `variances_of(opaque) = ['_a: o, '_b: *, T: o, 'b: o]`.

r? types
cc `@compiler-errors` , as you asked about the issue with `Self` and projections.
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/async-await/feature-self-return-type.rs28
-rw-r--r--src/test/ui/async-await/feature-self-return-type.stderr15
-rw-r--r--src/test/ui/async-await/in-trait/async-associated-types.rs4
-rw-r--r--src/test/ui/async-await/in-trait/async-associated-types.stderr57
-rw-r--r--src/test/ui/async-await/issue-61949-self-return-type.rs2
-rw-r--r--src/test/ui/async-await/issue-61949-self-return-type.stderr24
-rw-r--r--src/test/ui/async-await/issues/issue-78600.stderr7
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr15
-rw-r--r--src/test/ui/impl-trait/feature-self-return-type.rs102
-rw-r--r--src/test/ui/impl-trait/feature-self-return-type.stderr39
-rw-r--r--src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr5
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr7
14 files changed, 230 insertions, 79 deletions
diff --git a/src/test/ui/async-await/feature-self-return-type.rs b/src/test/ui/async-await/feature-self-return-type.rs
new file mode 100644
index 00000000000..41f887430c1
--- /dev/null
+++ b/src/test/ui/async-await/feature-self-return-type.rs
@@ -0,0 +1,28 @@
+// edition:2018
+#![feature(impl_trait_projections)]
+
+// This test checks that we emit the correct borrowck error when `Self` is used as a return type.
+// See #61949 for context.
+
+pub struct Foo<'a> {
+    pub bar: &'a i32,
+}
+
+impl<'a> Foo<'a> {
+    pub async fn new(_bar: &'a i32) -> Self {
+        Foo {
+            bar: &22
+        }
+    }
+}
+
+pub async fn foo() {
+    let x = {
+        let bar = 22;
+        Foo::new(&bar).await
+        //~^ ERROR `bar` does not live long enough
+    };
+    drop(x);
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/feature-self-return-type.stderr b/src/test/ui/async-await/feature-self-return-type.stderr
new file mode 100644
index 00000000000..8924683684f
--- /dev/null
+++ b/src/test/ui/async-await/feature-self-return-type.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `bar` does not live long enough
+  --> $DIR/feature-self-return-type.rs:22:18
+   |
+LL |     let x = {
+   |         - borrow later stored here
+LL |         let bar = 22;
+LL |         Foo::new(&bar).await
+   |                  ^^^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `bar` 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/async-await/in-trait/async-associated-types.rs b/src/test/ui/async-await/in-trait/async-associated-types.rs
index a6f928f3b1b..974f5aaff83 100644
--- a/src/test/ui/async-await/in-trait/async-associated-types.rs
+++ b/src/test/ui/async-await/in-trait/async-associated-types.rs
@@ -1,8 +1,8 @@
-// check-fail
-// known-bug: #102682
+// check-pass
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
+#![feature(impl_trait_projections)]
 #![allow(incomplete_features)]
 
 use std::fmt::Debug;
diff --git a/src/test/ui/async-await/in-trait/async-associated-types.stderr b/src/test/ui/async-await/in-trait/async-associated-types.stderr
deleted file mode 100644
index 0985150eee0..00000000000
--- a/src/test/ui/async-await/in-trait/async-associated-types.stderr
+++ /dev/null
@@ -1,57 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/async-associated-types.rs:16:6
-   |
-LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
-   |      ^^
-note: ...so that the types are compatible
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   = note: expected `(&'a U, &'b T)`
-              found `(&U, &T)`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the types are compatible
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   = note: expected `MyTrait<'static, 'static, T>`
-              found `MyTrait<'_, '_, T>`
-
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
-  --> $DIR/async-associated-types.rs:16:10
-   |
-LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
-   |          ^^
-note: ...so that the types are compatible
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   = note: expected `(&'a U, &'b T)`
-              found `(&U, &T)`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the types are compatible
-  --> $DIR/async-associated-types.rs:19:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
-   |                                           ^^^^^^^^^^^^^^
-   = note: expected `MyTrait<'static, 'static, T>`
-              found `MyTrait<'_, '_, T>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/async-await/issue-61949-self-return-type.rs b/src/test/ui/async-await/issue-61949-self-return-type.rs
index 43429ba2329..d73dbc6e828 100644
--- a/src/test/ui/async-await/issue-61949-self-return-type.rs
+++ b/src/test/ui/async-await/issue-61949-self-return-type.rs
@@ -1,4 +1,5 @@
 // edition:2018
+// gate-test-impl_trait_projections
 
 // This test checks that `Self` is prohibited as a return type. See #61949 for context.
 
@@ -19,6 +20,7 @@ async fn foo() {
     let x = {
         let bar = 22;
         Foo::new(&bar).await
+        //~^ ERROR `bar` does not live long enough
     };
     drop(x);
 }
diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr
index 52b726e186e..638b197bc02 100644
--- a/src/test/ui/async-await/issue-61949-self-return-type.stderr
+++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr
@@ -1,9 +1,25 @@
-error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
-  --> $DIR/issue-61949-self-return-type.rs:10:40
+error[E0658]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+  --> $DIR/issue-61949-self-return-type.rs:11:40
    |
 LL |     pub async fn new(_bar: &'a i32) -> Self {
    |                                        ^^^^ help: consider spelling out the type instead: `Foo<'a>`
+   |
+   = note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information
+   = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable
+
+error[E0597]: `bar` does not live long enough
+  --> $DIR/issue-61949-self-return-type.rs:22:18
+   |
+LL |     let x = {
+   |         - borrow later stored here
+LL |         let bar = 22;
+LL |         Foo::new(&bar).await
+   |                  ^^^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `bar` dropped here while still borrowed
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0760`.
+Some errors have detailed explanations: E0597, E0658.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/src/test/ui/async-await/issues/issue-78600.stderr b/src/test/ui/async-await/issues/issue-78600.stderr
index 92b66147106..37eafa996c5 100644
--- a/src/test/ui/async-await/issues/issue-78600.stderr
+++ b/src/test/ui/async-await/issues/issue-78600.stderr
@@ -1,11 +1,14 @@
-error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0658]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/issue-78600.rs:6:33
    |
 LL |     async fn new(i: &'a i32) -> Result<Self, ()> {
    |                                 ^^^^^^^----^^^^^
    |                                        |
    |                                        help: consider spelling out the type instead: `S<'a>`
+   |
+   = note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information
+   = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0760`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index bd8d3d3d24e..a9fa2da569f 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -19,17 +19,20 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                         ++++++++++++
 
-error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0658]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/bound-normalization-fail.rs:41:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information
+   = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable
 
-error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'a>>::Assoc`
   --> $DIR/bound-normalization-fail.rs:41:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'a>>::Assoc`
 ...
 LL |         Foo(())
    |         ------- return type was inferred to be `Foo<()>` here
@@ -40,13 +43,13 @@ note: expected this to be `()`
 LL |     type Output = T;
    |                   ^
    = note:    expected unit type `()`
-           found associated type `<T as lifetimes::Trait<'static>>::Assoc`
-help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
+           found associated type `<T as lifetimes::Trait<'a>>::Assoc`
+help: consider constraining the associated type `<T as lifetimes::Trait<'a>>::Assoc` to `()`
    |
 LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                                 ++++++++++++
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0271, E0760.
+Some errors have detailed explanations: E0271, E0658.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/feature-self-return-type.rs b/src/test/ui/impl-trait/feature-self-return-type.rs
new file mode 100644
index 00000000000..51877e9cc3c
--- /dev/null
+++ b/src/test/ui/impl-trait/feature-self-return-type.rs
@@ -0,0 +1,102 @@
+// edition:2018
+#![feature(impl_trait_projections)]
+
+// This test checks that we emit the correct borrowck error when `Self` or a projection is used as
+// a return type.  See #61949 for context.
+
+mod with_self {
+    pub struct Foo<'a> {
+        pub bar: &'a i32,
+    }
+
+    impl<'a> Foo<'a> {
+        pub fn new(_bar: &'a i32) -> impl Into<Self> {
+            Foo {
+                bar: &22
+            }
+        }
+    }
+
+    fn foo() {
+        let x = {
+            let bar = 22;
+            Foo::new(&bar).into()
+            //~^ ERROR `bar` does not live long enough
+        };
+        drop(x);
+    }
+}
+
+struct Foo<T>(T);
+
+trait FooLike {
+    type Output;
+}
+
+impl<T> FooLike for Foo<T> {
+    type Output = T;
+}
+
+mod impl_trait {
+    use super::*;
+
+    trait Trait {
+        type Assoc;
+
+        fn make_assoc(self) -> Self::Assoc;
+    }
+
+    /// `T::Assoc` can't be normalized any further here.
+    fn foo<T: Trait>(x: T) -> impl FooLike<Output = T::Assoc> {
+        Foo(x.make_assoc())
+    }
+
+    impl<'a> Trait for &'a () {
+        type Assoc = &'a ();
+
+        fn make_assoc(self) -> &'a () { &() }
+    }
+
+    fn usage() {
+        let x = {
+            let y = ();
+            foo(&y)
+            //~^ ERROR `y` does not live long enough
+        };
+        drop(x);
+    }
+}
+
+// Same with lifetimes in the trait
+
+mod lifetimes {
+    use super::*;
+
+    trait Trait<'a> {
+        type Assoc;
+
+        fn make_assoc(self) -> Self::Assoc;
+    }
+
+    /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further.
+    fn foo<'a, T: Trait<'a>>(x: T) -> impl FooLike<Output = T::Assoc> {
+        Foo(x.make_assoc())
+    }
+
+    impl<'a> Trait<'a> for &'a () {
+        type Assoc = &'a ();
+
+        fn make_assoc(self) -> &'a () { &() }
+    }
+
+    fn usage() {
+        let x = {
+            let y = ();
+            foo(&y)
+            //~^ ERROR `y` does not live long enough
+        };
+        drop(x);
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/feature-self-return-type.stderr b/src/test/ui/impl-trait/feature-self-return-type.stderr
new file mode 100644
index 00000000000..601e53b7694
--- /dev/null
+++ b/src/test/ui/impl-trait/feature-self-return-type.stderr
@@ -0,0 +1,39 @@
+error[E0597]: `bar` does not live long enough
+  --> $DIR/feature-self-return-type.rs:23:22
+   |
+LL |         let x = {
+   |             - borrow later stored here
+LL |             let bar = 22;
+LL |             Foo::new(&bar).into()
+   |                      ^^^^ borrowed value does not live long enough
+LL |
+LL |         };
+   |         - `bar` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/feature-self-return-type.rs:63:17
+   |
+LL |         let x = {
+   |             - borrow later stored here
+LL |             let y = ();
+LL |             foo(&y)
+   |                 ^^ borrowed value does not live long enough
+LL |
+LL |         };
+   |         - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/feature-self-return-type.rs:95:17
+   |
+LL |         let x = {
+   |             - borrow later stored here
+LL |             let y = ();
+LL |             foo(&y)
+   |                 ^^ borrowed value does not live long enough
+LL |
+LL |         };
+   |         - `y` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
index 7747319c153..c19420bbb0c 100644
--- a/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
+++ b/src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
@@ -14,10 +14,7 @@ error[E0720]: cannot resolve opaque type
   --> $DIR/impl-fn-predefined-lifetimes.rs:4:35
    |
 LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
-   |                                   ^^^^^^^^^^^^^^^ recursive opaque type
-...
-LL |     |x| x
-   |     ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]`
+   |                                   ^^^^^^^^^^^^^^^ cannot resolve opaque type
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 737cb35841c..7b9ed171d2d 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs
index 428194058c3..01d1f5db132 100644
--- a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs
+++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs
@@ -2,6 +2,6 @@
 
 type Opaque<'a, T> = impl Sized;
 fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
-//~^ ERROR: non-defining opaque type use in defining scope
+//~^ ERROR: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
index df2b3ed1911..65a0af0d22f 100644
--- a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
+++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
@@ -1,8 +1,11 @@
-error: non-defining opaque type use in defining scope
+error[E0700]: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds
   --> $DIR/missing_lifetime_bound.rs:4:47
    |
 LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
-   |                                               ^ lifetime `'a` is part of concrete type but not used in parameter list of the `impl Trait` type alias
+   |             --                                ^
+   |             |
+   |             hidden type `&'a i32` captures the lifetime `'a` as defined here
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0700`.