From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- .../borrowck-issue-49631.rs | 24 ++++++++++++ .../borrowck-issue-49631.stderr | 14 +++++++ .../ui/rfcs/rfc-2005-default-binding-mode/const.rs | 17 ++++++++ .../rfc-2005-default-binding-mode/const.stderr | 18 +++++++++ .../rfcs/rfc-2005-default-binding-mode/enum-ok.rs | 45 ++++++++++++++++++++++ .../ui/rfcs/rfc-2005-default-binding-mode/enum.rs | 29 ++------------ .../rfcs/rfc-2005-default-binding-mode/enum.stderr | 21 ++++++++++ .../rfc-2005-default-binding-mode/explicit-mut.rs | 28 ++++++++++++++ .../explicit-mut.stderr | 21 ++++++++++ .../rfcs/rfc-2005-default-binding-mode/for-ok.rs | 20 ++++++++++ tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs | 23 +++-------- .../rfcs/rfc-2005-default-binding-mode/for.stderr | 17 ++++++++ .../issue-44912-or.rs | 10 +++++ .../issue-44912-or.stderr | 9 +++++ .../rfcs/rfc-2005-default-binding-mode/lit-ok.rs | 34 ++++++++++++++++ tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs | 26 ++++--------- .../rfcs/rfc-2005-default-binding-mode/lit.stderr | 25 ++++++++++++ .../no-double-error.rs | 11 ++++++ .../no-double-error.stderr | 9 +++++ .../rfcs/rfc-2005-default-binding-mode/slice-ok.rs | 25 ++++++++++++ .../ui/rfcs/rfc-2005-default-binding-mode/slice.rs | 26 ++----------- .../rfc-2005-default-binding-mode/slice.stderr | 16 ++++++++ 22 files changed, 385 insertions(+), 83 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr (limited to 'tests/ui/rfcs/rfc-2005-default-binding-mode') diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs new file mode 100644 index 000000000..54ab9f0ad --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs @@ -0,0 +1,24 @@ +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Foo { +} + +impl Foo { + fn get(&self) -> Option<&Result> { + None + } + + fn mutate(&mut self) { } +} + +fn main() { + let mut foo = Foo { }; + + // foo.get() returns type Option<&Result>, so + // using `string` keeps borrow of `foo` alive. Hence calling + // `foo.mutate()` should be an error. + while let Some(Ok(string)) = foo.get() { + foo.mutate(); + //~^ ERROR cannot borrow `foo` as mutable + println!("foo={:?}", *string); + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr new file mode 100644 index 000000000..b7c0b0bb6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-issue-49631.rs:20:9 + | +LL | while let Some(Ok(string)) = foo.get() { + | --------- immutable borrow occurs here +LL | foo.mutate(); + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | println!("foo={:?}", *string); + | ------- immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs new file mode 100644 index 000000000..93df88040 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs @@ -0,0 +1,17 @@ +// FIXME(tschottdorf): this test should pass. + +#[derive(PartialEq, Eq)] +struct Foo { + bar: i32, +} + +const FOO: Foo = Foo{bar: 5}; + +fn main() { + let f = Foo{bar:6}; + + match &f { + FOO => {}, //~ ERROR mismatched types + _ => panic!(), + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr new file mode 100644 index 000000000..fc06de90a --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/const.rs:14:9 + | +LL | const FOO: Foo = Foo{bar: 5}; + | -------------- constant defined here +... +LL | match &f { + | -- this expression has type `&Foo` +LL | FOO => {}, + | ^^^ + | | + | expected `&Foo`, found `Foo` + | `FOO` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs new file mode 100644 index 000000000..52fbb90ed --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs @@ -0,0 +1,45 @@ +// run-pass +enum Wrapper { + Wrap(i32), +} + +use Wrapper::Wrap; + +pub fn main() { + let Wrap(x) = &Wrap(3); + println!("{}", *x); + + let Wrap(x) = &mut Wrap(3); + println!("{}", *x); + + if let Some(x) = &Some(3) { + println!("{}", *x); + } else { + panic!(); + } + + if let Some(x) = &mut Some(3) { + println!("{}", *x); + } else { + panic!(); + } + + if let Some(x) = &mut Some(3) { + *x += 1; + } else { + panic!(); + } + + while let Some(x) = &Some(3) { + println!("{}", *x); + break; + } + while let Some(x) = &mut Some(3) { + println!("{}", *x); + break; + } + while let Some(x) = &mut Some(3) { + *x += 1; + break; + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs index 52fbb90ed..4e57769d6 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs @@ -1,4 +1,3 @@ -// run-pass enum Wrapper { Wrap(i32), } @@ -7,39 +6,17 @@ use Wrapper::Wrap; pub fn main() { let Wrap(x) = &Wrap(3); - println!("{}", *x); + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference - let Wrap(x) = &mut Wrap(3); - println!("{}", *x); if let Some(x) = &Some(3) { - println!("{}", *x); - } else { - panic!(); - } - - if let Some(x) = &mut Some(3) { - println!("{}", *x); - } else { - panic!(); - } - - if let Some(x) = &mut Some(3) { - *x += 1; + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference } else { panic!(); } while let Some(x) = &Some(3) { - println!("{}", *x); - break; - } - while let Some(x) = &mut Some(3) { - println!("{}", *x); - break; - } - while let Some(x) = &mut Some(3) { - *x += 1; + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference break; } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr new file mode 100644 index 000000000..21e3d3d27 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:9:5 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:13:9 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:19:9 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs new file mode 100644 index 000000000..b8fde2208 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs @@ -0,0 +1,28 @@ +// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the +// final default binding mode mutable. + +fn main() { + match &&Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; + + match &mut &Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; + + match &&mut Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr new file mode 100644 index 000000000..c3f64f65a --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:7:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:15:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:23:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs new file mode 100644 index 000000000..a5a24a806 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs @@ -0,0 +1,20 @@ +// run-pass +pub fn main() { + let mut tups = vec![(0u8, 1u8)]; + + for (n, m) in &tups { + let _: &u8 = n; + let _: &u8 = m; + } + + for (n, m) in &mut tups { + *n += 1; + *m += 2; + } + + assert_eq!(tups, vec![(1u8, 3u8)]); + + for (n, m) in tups { + println!("{} {}", m, n); + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs index a5a24a806..d6c5a13b1 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs @@ -1,20 +1,9 @@ -// run-pass -pub fn main() { - let mut tups = vec![(0u8, 1u8)]; - - for (n, m) in &tups { - let _: &u8 = n; - let _: &u8 = m; - } +struct Foo {} - for (n, m) in &mut tups { - *n += 1; - *m += 2; - } - - assert_eq!(tups, vec![(1u8, 3u8)]); - - for (n, m) in tups { - println!("{} {}", m, n); +pub fn main() { + let mut tups = vec![(Foo {}, Foo {})]; + // The below desugars to &(ref n, mut m). + for (n, mut m) in &tups { + //~^ ERROR cannot move out of a shared reference } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr new file mode 100644 index 000000000..07991af6e --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/for.rs:6:23 + | +LL | for (n, mut m) in &tups { + | ----- ^^^^^ + | | + | data moved here + | move occurs because `m` has type `Foo`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | for (n, ref mut m) in &tups { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs new file mode 100644 index 000000000..b4a0d8145 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs @@ -0,0 +1,10 @@ +// FIXME(tschottdorf): This should compile. See #44912. + +pub fn main() { + let x = &Some((3, 3)); + let _: &i32 = match x { + Some((x, 3)) | &Some((ref x, 5)) => x, + //~^ ERROR is bound inconsistently + _ => &5i32, + }; +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr new file mode 100644 index 000000000..e1e1bf7f6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr @@ -0,0 +1,9 @@ +error[E0409]: variable `x` is bound inconsistently across alternatives separated by `|` + --> $DIR/issue-44912-or.rs:6:35 + | +LL | Some((x, 3)) | &Some((ref x, 5)) => x, + | - first binding ^ bound in different ways + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0409`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs new file mode 100644 index 000000000..937975359 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs @@ -0,0 +1,34 @@ +// run-pass +#![allow(dead_code)] +fn with_u8() { + let s = 5u8; + let r = match &s { + 4 => false, + 5 => true, + _ => false, + }; + assert!(r); +} + +// A string literal isn't mistaken for a non-ref pattern (in which case we'd +// deref `s` and mess things up). +fn with_str() { + let s: &'static str = "abc"; + match s { + "abc" => true, + _ => panic!(), + }; +} + +// Ditto with byte strings. +fn with_bytes() { + let s: &'static [u8] = b"abc"; + match s { + b"abc" => true, + _ => panic!(), + }; +} + +pub fn main() { + with_str(); +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs index 937975359..ce79cfbdc 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs @@ -1,34 +1,24 @@ -// run-pass -#![allow(dead_code)] -fn with_u8() { - let s = 5u8; - let r = match &s { - 4 => false, - 5 => true, - _ => false, - }; - assert!(r); -} +// FIXME(tschottdorf): we want these to compile, but they don't. -// A string literal isn't mistaken for a non-ref pattern (in which case we'd -// deref `s` and mess things up). fn with_str() { let s: &'static str = "abc"; - match s { - "abc" => true, + + match &s { + "abc" => true, //~ ERROR mismatched types _ => panic!(), }; } -// Ditto with byte strings. fn with_bytes() { let s: &'static [u8] = b"abc"; - match s { - b"abc" => true, + + match &s { + b"abc" => true, //~ ERROR mismatched types _ => panic!(), }; } pub fn main() { with_str(); + with_bytes(); } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr new file mode 100644 index 000000000..181f57899 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/lit.rs:7:13 + | +LL | match &s { + | -- this expression has type `&&str` +LL | "abc" => true, + | ^^^^^ expected `&&str`, found `&str` + | + = note: expected reference `&&str` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/lit.rs:16:9 + | +LL | match &s { + | -- this expression has type `&&[u8]` +LL | b"abc" => true, + | ^^^^^^ expected `&&[u8]`, found `&[u8; 3]` + | + = note: expected reference `&&[u8]` + found reference `&'static [u8; 3]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs new file mode 100644 index 000000000..46fdfd678 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs @@ -0,0 +1,11 @@ +// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs +// the error below would be reported twice (once when checking +// for a non-ref pattern, once when processing the pattern). + +fn main() { + let foo = 22; + match foo { + u32::XXX => { } //~ ERROR no associated item named + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr new file mode 100644 index 000000000..c672acee0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr @@ -0,0 +1,9 @@ +error[E0599]: no associated item named `XXX` found for type `u32` in the current scope + --> $DIR/no-double-error.rs:8:14 + | +LL | u32::XXX => { } + | ^^^ associated item not found in `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs new file mode 100644 index 000000000..33229a205 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs @@ -0,0 +1,25 @@ +// run-pass + +fn slice_pat() { + let sl: &[u8] = b"foo"; + + match sl { + [first, remainder @ ..] => { + let _: &u8 = first; + assert_eq!(first, &b'f'); + assert_eq!(remainder, b"oo"); + } + [] => panic!(), + } +} + +fn slice_pat_omission() { + match &[0, 1, 2] { + [..] => {} + }; +} + +fn main() { + slice_pat(); + slice_pat_omission(); +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs index 33229a205..363a0e3e6 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs @@ -1,25 +1,7 @@ -// run-pass - -fn slice_pat() { +pub fn main() { let sl: &[u8] = b"foo"; - match sl { - [first, remainder @ ..] => { - let _: &u8 = first; - assert_eq!(first, &b'f'); - assert_eq!(remainder, b"oo"); - } - [] => panic!(), - } -} - -fn slice_pat_omission() { - match &[0, 1, 2] { - [..] => {} - }; -} - -fn main() { - slice_pat(); - slice_pat_omission(); + match sl { //~ ERROR non-exhaustive patterns + [first, remainder @ ..] => {}, + }; } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr new file mode 100644 index 000000000..5b51dc5ac --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `&[]` not covered + --> $DIR/slice.rs:4:11 + | +LL | match sl { + | ^^ pattern `&[]` not covered + | + = note: the matched value is of type `&[u8]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [first, remainder @ ..] => {}, +LL ~ &[] => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. -- cgit v1.2.3