From 4187560bdf513e959e3dc3d720128c0a87ab9c61 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 22 Mar 2019 17:20:25 +0100 Subject: [PATCH 01/25] Add comments for new `AdtDef` functions. --- src/librustc/ty/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f0045136f41bf..fe3b13d707690 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2146,6 +2146,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { debug!("found non-exhaustive variant list for {:?}", did); flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; } + flags |= match kind { AdtKind::Enum => AdtFlags::IS_ENUM, AdtKind::Union => AdtFlags::IS_UNION, @@ -2299,21 +2300,25 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().all(|v| v.fields.is_empty()) } + /// Return a `VariantDef` given a variant id. pub fn variant_with_id(&self, vid: DefId) -> &VariantDef { self.variants.iter().find(|v| v.def_id == vid) .expect("variant_with_id: unknown variant") } + /// Return a `VariantDef` given a constructor id. pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef { self.variants.iter().find(|v| v.ctor_def_id == Some(cid)) .expect("variant_with_ctor_id: unknown variant") } + /// Return the index of `VariantDef` given a variant id. pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx { self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid) .expect("variant_index_with_id: unknown variant").0 } + /// Return the index of `VariantDef` given a constructor id. pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx { self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid)) .expect("variant_index_with_ctor_id: unknown variant").0 From 4e7ec07bb910aef258a848d5fcfa96b3bab7b3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 19:04:25 -0700 Subject: [PATCH 02/25] Account for short-hand field syntax when suggesting borrow --- src/librustc_typeck/check/demand.rs | 48 ++++++++++++++++++++++++----- src/test/ui/deref-suggestion.rs | 14 +++++++++ src/test/ui/deref-suggestion.stderr | 32 ++++++++++++++++--- 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index b1a249d821bec..5939f965269be 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -277,6 +277,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } + let parent_id = self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id); + let mut is_struct_pat_shorthand_field = false; + if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { + // Account for fields + if let Node::Expr(hir::Expr { + node: hir::ExprKind::Struct(_, fields, ..), .. + }) = parent { + if let Ok(src) = cm.span_to_snippet(sp) { + for field in fields { + if field.ident.as_str() == src.as_str() && field.is_shorthand { + is_struct_pat_shorthand_field = true; + break; + } + } + } + } + }; + match (&expected.sty, &checked_ty.sty) { (&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { (&ty::Str, &ty::Array(arr, _)) | @@ -341,14 +359,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); } - return Some(match mutability { - hir::Mutability::MutMutable => { - (sp, "consider mutably borrowing here", format!("&mut {}", - sugg_expr)) + return Some(match (mutability, is_struct_pat_shorthand_field) { + (hir::Mutability::MutMutable, false) => { + (sp, "consider mutably borrowing here", + format!("&mut {}", sugg_expr)) } - hir::Mutability::MutImmutable => { + (hir::Mutability::MutImmutable, false) => { (sp, "consider borrowing here", format!("&{}", sugg_expr)) } + (hir::Mutability::MutMutable, true) => { + (sp, "consider mutably borrowing here", + format!("{}: &mut {}", sugg_expr, sugg_expr)) + } + (hir::Mutability::MutImmutable, true) => { + (sp, "consider borrowing here", + format!("{}: &{}", sugg_expr, sugg_expr)) + } }); } } @@ -389,12 +415,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { checked, sp) { // do not suggest if the span comes from a macro (#52783) - if let (Ok(code), - true) = (cm.span_to_snippet(sp), sp == expr.span) { + if let (Ok(code), true) = ( + cm.span_to_snippet(sp), + sp == expr.span, + ) { return Some(( sp, "consider dereferencing the borrow", - format!("*{}", code), + if is_struct_pat_shorthand_field { + format!("{}: *{}", code, code) + } else { + format!("*{}", code) + }, )); } } diff --git a/src/test/ui/deref-suggestion.rs b/src/test/ui/deref-suggestion.rs index 83e54b64f47c9..f156766f52881 100644 --- a/src/test/ui/deref-suggestion.rs +++ b/src/test/ui/deref-suggestion.rs @@ -15,6 +15,14 @@ fn foo4(u: &u32) { //~^ ERROR mismatched types } +struct S<'a> { + u: &'a u32, +} + +struct R { + i: u32, +} + fn main() { let s = String::new(); let r_s = &s; @@ -27,4 +35,10 @@ fn main() { foo4(&0); assert_eq!(3i32, &3i32); //~^ ERROR mismatched types + let u = 3; + let s = S { u }; + //~^ ERROR mismatched types + let i = &4; + let r = R { i }; + //~^ ERROR mismatched types } diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index 8f061b3416e13..bd0ebfac5319d 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -23,7 +23,7 @@ LL | foo3(u); found type `&u32` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:22:9 + --> $DIR/deref-suggestion.rs:30:9 | LL | foo(&"aaa".to_owned()); | ^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | foo(&"aaa".to_owned()); found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:24:9 + --> $DIR/deref-suggestion.rs:32:9 | LL | foo(&mut "aaa".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | foo3(borrow!(0)); found type `&{integer}` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:28:5 + --> $DIR/deref-suggestion.rs:36:5 | LL | assert_eq!(3i32, &3i32); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32 @@ -68,6 +68,30 @@ LL | assert_eq!(3i32, &3i32); found type `&i32` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:39:17 + | +LL | let s = S { u }; + | ^ + | | + | expected &u32, found integer + | help: consider borrowing here: `u: &u` + | + = note: expected type `&u32` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:42:17 + | +LL | let r = R { i }; + | ^ + | | + | expected u32, found &{integer} + | help: consider dereferencing the borrow: `i: *i` + | + = note: expected type `u32` + found type `&{integer}` + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. From a51ca0268d0b130cbe3ef4a2dd0024d6d136e3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 19:07:15 -0700 Subject: [PATCH 03/25] Expand test --- src/test/ui/deref-suggestion.rs | 4 ++++ src/test/ui/deref-suggestion.stderr | 28 ++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/test/ui/deref-suggestion.rs b/src/test/ui/deref-suggestion.rs index f156766f52881..580410aecf4f8 100644 --- a/src/test/ui/deref-suggestion.rs +++ b/src/test/ui/deref-suggestion.rs @@ -38,7 +38,11 @@ fn main() { let u = 3; let s = S { u }; //~^ ERROR mismatched types + let s = S { u: u }; + //~^ ERROR mismatched types let i = &4; let r = R { i }; //~^ ERROR mismatched types + let r = R { i: i }; + //~^ ERROR mismatched types } diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index bd0ebfac5319d..9c49f541c9309 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -81,7 +81,19 @@ LL | let s = S { u }; found type `{integer}` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:42:17 + --> $DIR/deref-suggestion.rs:41:20 + | +LL | let s = S { u: u }; + | ^ + | | + | expected &u32, found integer + | help: consider borrowing here: `&u` + | + = note: expected type `&u32` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:44:17 | LL | let r = R { i }; | ^ @@ -92,6 +104,18 @@ LL | let r = R { i }; = note: expected type `u32` found type `&{integer}` -error: aborting due to 8 previous errors +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:46:20 + | +LL | let r = R { i: i }; + | ^ + | | + | expected u32, found &{integer} + | help: consider dereferencing the borrow: `*i` + | + = note: expected type `u32` + found type `&{integer}` + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0308`. From e3918cf62138157ef4748c2193e0601aaa78f311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 17:36:07 -0700 Subject: [PATCH 04/25] Recover from parse error in tuple syntax --- src/libsyntax/parse/parser.rs | 39 +++++++++++++---- src/test/ui/issues/issue-34334.rs | 8 +++- src/test/ui/issues/issue-34334.stderr | 43 +++++++++++++++++-- src/test/ui/parser/pat-tuple-1.rs | 5 ++- src/test/ui/parser/pat-tuple-5.rs | 2 +- .../ui/parser/recover-from-bad-variant.rs | 14 ++++++ .../ui/parser/recover-from-bad-variant.stderr | 15 +++++++ src/test/ui/parser/recover-tuple-pat.rs | 12 ++++++ src/test/ui/parser/recover-tuple-pat.stderr | 24 +++++++++++ src/test/ui/parser/recover-tuple.rs | 11 +++++ src/test/ui/parser/recover-tuple.stderr | 18 ++++++++ .../ui/parser/trait-object-lifetime-parens.rs | 5 ++- .../trait-object-lifetime-parens.stderr | 17 +++++++- 13 files changed, 196 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/parser/recover-from-bad-variant.rs create mode 100644 src/test/ui/parser/recover-from-bad-variant.stderr create mode 100644 src/test/ui/parser/recover-tuple-pat.rs create mode 100644 src/test/ui/parser/recover-tuple-pat.stderr create mode 100644 src/test/ui/parser/recover-tuple.rs create mode 100644 src/test/ui/parser/recover-tuple.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a0c3fe356083f..ea0c7e0e36662 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2637,7 +2637,15 @@ impl<'a> Parser<'a> { let mut trailing_comma = false; let mut recovered = false; while self.token != token::CloseDelim(token::Paren) { - es.push(self.parse_expr()?); + es.push(match self.parse_expr() { + Ok(es) => es, + Err(mut err) => { // recover from parse error in tuple list + err.emit(); + self.consume_block(token::Paren); + hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Err, ThinVec::new())); + } + }); recovered = self.expect_one_of( &[], &[token::Comma, token::CloseDelim(token::Paren)], @@ -3248,16 +3256,24 @@ impl<'a> Parser<'a> { match self.token { // expr(...) token::OpenDelim(token::Paren) => { - let es = self.parse_unspanned_seq( + match self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) - )?; - hi = self.prev_span; - - let nd = self.mk_call(e, es); - e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); + ) { + Ok(es) => { + let nd = self.mk_call(e, es); + hi = self.prev_span; + e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); + } + Err(mut err) => { // recover from parse error in argument list + err.emit(); + self.consume_block(token::Paren); + hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Err, ThinVec::new()); + } + } } // expr[...] @@ -4262,7 +4278,14 @@ impl<'a> Parser<'a> { // Trailing commas are significant because (p) and (p,) are different patterns. fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec>, Option, bool)> { self.expect(&token::OpenDelim(token::Paren))?; - let result = self.parse_pat_list()?; + let result = match self.parse_pat_list() { + Ok(result) => result, + Err(mut err) => { // recover from parse error in tuple pattern list + err.emit(); + self.consume_block(token::Paren); + return Ok((vec![], Some(0), false)); + } + }; self.expect(&token::CloseDelim(token::Paren))?; Ok(result) } diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 5c4f5c86a7fde..928d217441ef2 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -1,4 +1,10 @@ fn main () { - let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` + let sr: Vec<(u32, _, _) = vec![]; + //~^ ERROR expected one of `,` or `>`, found `=` + //~| ERROR expected value, found struct `Vec` + //~| ERROR mismatched types + //~| ERROR invalid left-hand side expression + //~| ERROR expected expression, found reserved identifier `_` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); + //~^ ERROR no method named `iter` found for type `()` in the current scope } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 1b0babf939044..51ea0c6a90894 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -1,10 +1,47 @@ +error: expected expression, found reserved identifier `_` + --> $DIR/issue-34334.rs:2:23 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^ expected expression + error: expected one of `,` or `>`, found `=` --> $DIR/issue-34334.rs:2:29 | LL | let sr: Vec<(u32, _, _) = vec![]; - | -- ^ expected one of `,` or `>` here - | | + | --- ^ expected one of `,` or `>` here + | | | + | | help: use `=` if you meant to assign | while parsing the type for `sr` -error: aborting due to previous error +error[E0423]: expected value, found struct `Vec` + --> $DIR/issue-34334.rs:2:13 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^ did you mean `Vec { /* fields */ }`? + +error[E0308]: mismatched types + --> $DIR/issue-34334.rs:2:31 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^^^^ expected bool, found struct `std::vec::Vec` + | + = note: expected type `bool` + found type `std::vec::Vec<_>` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0070]: invalid left-hand side expression + --> $DIR/issue-34334.rs:2:13 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid + +error[E0599]: no method named `iter` found for type `()` in the current scope + --> $DIR/issue-34334.rs:8:36 + | +LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); + | ^^^^ + +error: aborting due to 6 previous errors +Some errors occurred: E0070, E0308, E0423, E0599. +For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/parser/pat-tuple-1.rs b/src/test/ui/parser/pat-tuple-1.rs index 213fbe371d435..d76096c25988d 100644 --- a/src/test/ui/parser/pat-tuple-1.rs +++ b/src/test/ui/parser/pat-tuple-1.rs @@ -1,5 +1,6 @@ fn main() { - match 0 { - (, ..) => {} //~ ERROR expected pattern, found `,` + match (0, 1) { + (, ..) => {} + //~^ ERROR expected pattern, found `,` } } diff --git a/src/test/ui/parser/pat-tuple-5.rs b/src/test/ui/parser/pat-tuple-5.rs index 03176abaf49a8..d4f05a5eb523e 100644 --- a/src/test/ui/parser/pat-tuple-5.rs +++ b/src/test/ui/parser/pat-tuple-5.rs @@ -1,5 +1,5 @@ fn main() { - match 0 { + match (0, 1) { (pat ..) => {} //~ ERROR unexpected token: `)` } } diff --git a/src/test/ui/parser/recover-from-bad-variant.rs b/src/test/ui/parser/recover-from-bad-variant.rs new file mode 100644 index 0000000000000..35088fb306882 --- /dev/null +++ b/src/test/ui/parser/recover-from-bad-variant.rs @@ -0,0 +1,14 @@ +enum Enum { + Foo { a: usize, b: usize }, + Bar(usize, usize), +} + +fn main() { + let x = Enum::Foo(a: 3, b: 4); + //~^ ERROR expected type, found `3` + match x { + Enum::Foo(a, b) => {} + //~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo` + Enum::Bar(a, b) => {} + } +} diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr new file mode 100644 index 0000000000000..bd4a562d72d19 --- /dev/null +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -0,0 +1,15 @@ +error: expected type, found `3` + --> $DIR/recover-from-bad-variant.rs:7:26 + | +LL | let x = Enum::Foo(a: 3, b: 4); + | ^ expecting a type here because of type ascription + +error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo` + --> $DIR/recover-from-bad-variant.rs:10:9 + | +LL | Enum::Foo(a, b) => {} + | ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`? + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/parser/recover-tuple-pat.rs b/src/test/ui/parser/recover-tuple-pat.rs new file mode 100644 index 0000000000000..488e8db6b8789 --- /dev/null +++ b/src/test/ui/parser/recover-tuple-pat.rs @@ -0,0 +1,12 @@ +fn main() { + let x = (1, 2, 3, 4); + match x { + (1, .., 4) => {} + (1, .=., 4) => { let _: usize = ""; } + //~^ ERROR expected pattern, found `.` + //~| ERROR mismatched types + (.=., 4) => {} + //~^ ERROR expected pattern, found `.` + (1, 2, 3, 4) => {} + } +} diff --git a/src/test/ui/parser/recover-tuple-pat.stderr b/src/test/ui/parser/recover-tuple-pat.stderr new file mode 100644 index 0000000000000..5919aa72355ac --- /dev/null +++ b/src/test/ui/parser/recover-tuple-pat.stderr @@ -0,0 +1,24 @@ +error: expected pattern, found `.` + --> $DIR/recover-tuple-pat.rs:5:13 + | +LL | (1, .=., 4) => { let _: usize = ""; } + | ^ expected pattern + +error: expected pattern, found `.` + --> $DIR/recover-tuple-pat.rs:8:10 + | +LL | (.=., 4) => {} + | ^ expected pattern + +error[E0308]: mismatched types + --> $DIR/recover-tuple-pat.rs:5:41 + | +LL | (1, .=., 4) => { let _: usize = ""; } + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/recover-tuple.rs b/src/test/ui/parser/recover-tuple.rs new file mode 100644 index 0000000000000..59e2695dec6dc --- /dev/null +++ b/src/test/ui/parser/recover-tuple.rs @@ -0,0 +1,11 @@ +fn main() { + // no complaints about the tuple not matching the expected type + let x: (usize, usize, usize) = (3, .=.); + //~^ ERROR expected expression, found `.` + // verify that the parser recovers: + let y: usize = ""; //~ ERROR mismatched types + // no complaints about the type + foo(x); +} + +fn foo(_: (usize, usize, usize)) {} diff --git a/src/test/ui/parser/recover-tuple.stderr b/src/test/ui/parser/recover-tuple.stderr new file mode 100644 index 0000000000000..4252fc1fd1e1b --- /dev/null +++ b/src/test/ui/parser/recover-tuple.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `.` + --> $DIR/recover-tuple.rs:3:40 + | +LL | let x: (usize, usize, usize) = (3, .=.); + | ^ expected expression + +error[E0308]: mismatched types + --> $DIR/recover-tuple.rs:6:20 + | +LL | let y: usize = ""; + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs index b188e14778be5..43f6497f7e71c 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.rs +++ b/src/test/ui/parser/trait-object-lifetime-parens.rs @@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a` + let _: Box<('a) + Trait>; + //~^ ERROR expected type, found `'a` + //~| ERROR expected `:`, found `)` + //~| ERROR chained comparison operators require parentheses } fn main() {} diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index 084e6d5b11fcd..a31b7aea8fee6 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -10,6 +10,21 @@ error: parenthesized lifetime bounds are not supported LL | let _: Box; | ^^^^ help: remove the parentheses +error: expected `:`, found `)` + --> $DIR/trait-object-lifetime-parens.rs:9:19 + | +LL | let _: Box<('a) + Trait>; + | ^ expected `:` + +error: chained comparison operators require parentheses + --> $DIR/trait-object-lifetime-parens.rs:9:15 + | +LL | let _: Box<('a) + Trait>; + | ^^^^^^^^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments + error: expected type, found `'a` --> $DIR/trait-object-lifetime-parens.rs:9:17 | @@ -18,5 +33,5 @@ LL | let _: Box<('a) + Trait>; | | | while parsing the type for `_` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors From 8fd3be596f1bbe4caf3f4a14a564480cf02320b3 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 28 Mar 2019 19:51:05 +0100 Subject: [PATCH 05/25] fix broken download link in the armhf-gnu image --- src/ci/docker/armhf-gnu/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 2b7624d53ee05..e4c2097f970a9 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -71,7 +71,8 @@ COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static # TODO: What is this?! -RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb +# Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb +RUN curl -O https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh From 3a88cd77781965118f9860b76341b7fe249df061 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 22 Mar 2019 17:19:12 +0100 Subject: [PATCH 06/25] Implement `#[non_exhaustive]` on variants. This commit removes the check that disallows the `#[non_exhaustive]` attribute from being placed on enum variants and removes the associated tests. Further, this commit lowers the visibility of enum variant constructors when the variant is marked as non-exhaustive. --- src/librustc/ty/mod.rs | 9 +++- src/librustc_metadata/encoder.rs | 9 +++- src/librustc_passes/ast_validation.rs | 9 ---- src/librustc_privacy/lib.rs | 21 +++++++- src/librustc_resolve/build_reduced_graph.rs | 10 +++- .../auxiliary/enums.rs | 10 ---- .../auxiliary/structs.rs | 14 ----- .../auxiliary/variants.rs | 9 ---- .../rfcs/rfc-2008-non-exhaustive/enums.rs | 53 ------------------- .../rfcs/rfc-2008-non-exhaustive/structs.rs | 20 ------- .../rfcs/rfc-2008-non-exhaustive/variants.rs | 22 -------- src/test/ui/rfc-2008-non-exhaustive/enum.rs | 44 +++++++++++++++ .../enum_same_crate.rs} | 1 + .../{structs.rs => struct.rs} | 12 +++++ .../{structs.stderr => struct.stderr} | 18 +++---- .../structs_same_crate.rs | 1 + .../{variants.rs => variant.rs} | 25 +++++---- .../ui/rfc-2008-non-exhaustive/variant.stderr | 52 ++++++++++++++++++ .../variants_create.rs | 17 ------ .../variants_create.stderr | 20 ------- .../variants_same_crate.rs | 7 +-- 21 files changed, 179 insertions(+), 204 deletions(-) delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs delete mode 100644 src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs rename src/test/{run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs => ui/rfc-2008-non-exhaustive/enum_same_crate.rs} (99%) rename src/test/ui/rfc-2008-non-exhaustive/{structs.rs => struct.rs} (73%) rename src/test/ui/rfc-2008-non-exhaustive/{structs.stderr => struct.stderr} (88%) rename src/test/{run-pass/rfcs => ui}/rfc-2008-non-exhaustive/structs_same_crate.rs (99%) rename src/test/ui/rfc-2008-non-exhaustive/{variants.rs => variant.rs} (50%) create mode 100644 src/test/ui/rfc-2008-non-exhaustive/variant.stderr delete mode 100644 src/test/ui/rfc-2008-non-exhaustive/variants_create.rs delete mode 100644 src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr rename src/test/{run-pass/rfcs => ui}/rfc-2008-non-exhaustive/variants_same_crate.rs (76%) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index fe3b13d707690..102057c1380ac 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef { if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") { debug!("found non-exhaustive field list for {:?}", parent_did); flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; + } else if let Some(variant_did) = variant_did { + if tcx.has_attr(variant_did, "non_exhaustive") { + debug!("found non-exhaustive field list for {:?}", variant_did); + flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; + } } VariantDef { @@ -2935,8 +2940,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - // Returns `ty::VariantDef` if `def` refers to a struct, - // or variant or their constructors, panics otherwise. + /// Returns `ty::VariantDef` if `def` refers to a struct, + /// or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { match def { Def::Variant(did) => { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 78a186fbb714a..84237cc1e7133 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -642,13 +642,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } }; - // Variant constructors have the same visibility as the parent enums. + // Variant constructors have the same visibility as the parent enums, unless marked as + // non-exhaustive, in which case they are lowered to `pub(crate)`. let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis; + let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx); + if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } Entry { kind: EntryKind::Variant(self.lazy(&data)), - visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)), + visibility: self.lazy(&ctor_vis), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), children: LazySeq::empty(), diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 4e2aefe623167..741264d1dbe18 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> { } } - fn invalid_non_exhaustive_attribute(&self, variant: &Variant) { - let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive"); - if has_non_exhaustive { - self.err_handler().span_err(variant.span, - "#[non_exhaustive] is not yet supported on variants"); - } - } - fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { if let VisibilityKind::Inherited = vis.node { return @@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Enum(ref def, _) => { for variant in &def.variants { - self.invalid_non_exhaustive_attribute(variant); for field in variant.node.data.fields() { self.invalid_visibility(&field.vis, None); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index bbd03e82a3730..8c3d80b323ffd 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) match tcx.hir().get_by_hir_id(parent_hir_id) { Node::Variant(..) => { let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id); - return def_id_visibility(tcx, parent_did); + let (mut ctor_vis, mut span, mut descr) = def_id_visibility( + tcx, parent_did, + ); + + let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id)); + let ctor_did = tcx.hir().local_def_id_from_hir_id( + vdata.ctor_hir_id().unwrap()); + let variant = adt_def.variant_with_ctor_id(ctor_did); + + if variant.is_field_list_non_exhaustive() && + ctor_vis == ty::Visibility::Public + { + ctor_vis = ty::Visibility::Restricted( + DefId::local(CRATE_DEF_INDEX)); + let attrs = tcx.get_attrs(variant.def_id); + span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span; + descr = "crate-visible"; + } + + return (ctor_vis, span, descr); } Node::Item(..) => { let item = match tcx.hir().get_by_hir_id(parent_hir_id) { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f55425c3168ec..7ce264db755db 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -588,6 +588,14 @@ impl<'a> Resolver<'a> { let def = Def::Variant(def_id); self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion)); + // If the variant is marked as non_exhaustive then lower the visibility to within the + // crate. + let mut ctor_vis = vis; + let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive"); + if has_non_exhaustive && vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } + // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. @@ -597,7 +605,7 @@ impl<'a> Resolver<'a> { let ctor_def_id = self.definitions.local_def_id(ctor_node_id); let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind); - self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); + self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion)); } /// Constructs the reduced graph for one foreign item. diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs deleted file mode 100644 index b3e2fa2c6208e..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass -#![crate_type = "rlib"] -#![feature(non_exhaustive)] - -#[non_exhaustive] -pub enum NonExhaustiveEnum { - Unit, - Tuple(u32), - Struct { field: u32 } -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs deleted file mode 100644 index 08b14d0df9408..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass -#![feature(non_exhaustive)] - -#[non_exhaustive] -pub struct NormalStruct { - pub first_field: u16, - pub second_field: u16, -} - -#[non_exhaustive] -pub struct UnitStruct; - -#[non_exhaustive] -pub struct TupleStruct (pub u16, pub u16); diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs deleted file mode 100644 index 56a73d8ab6088..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass -#![crate_type = "rlib"] -#![feature(non_exhaustive)] - -pub enum NonExhaustiveVariants { - #[non_exhaustive] Unit, - #[non_exhaustive] Tuple(u32), - #[non_exhaustive] Struct { field: u32 } -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs deleted file mode 100644 index f7e9c53849612..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass -// aux-build:enums.rs -extern crate enums; - -// ignore-pretty issue #37199 - -use enums::NonExhaustiveEnum; - -fn main() { - let enum_unit = NonExhaustiveEnum::Unit; - - match enum_unit { - NonExhaustiveEnum::Unit => 1, - NonExhaustiveEnum::Tuple(_) => 2, - // This particular arm tests that a enum marked as non-exhaustive - // will not error if its variants are matched exhaustively. - NonExhaustiveEnum::Struct { field } => field, - _ => 0 // no error with wildcard - }; - - match enum_unit { - _ => "no error with only wildcard" - }; - - - // issue #53549 - check that variant constructors can still be called normally. - - match NonExhaustiveEnum::Unit { - NonExhaustiveEnum::Unit => {}, - _ => {} - }; - - match NonExhaustiveEnum::Tuple(2) { - NonExhaustiveEnum::Tuple(2) => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Unit {}) { - NonExhaustiveEnum::Unit {} => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Tuple { 0: 2 }) { - NonExhaustiveEnum::Tuple { 0: 2 } => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Struct { field: 2 }) { - NonExhaustiveEnum::Struct { field: 2 } => {}, - _ => {} - }; - -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs deleted file mode 100644 index 3cd7234269e1d..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs +++ /dev/null @@ -1,20 +0,0 @@ -// run-pass -#![allow(dead_code)] -#![allow(unused_variables)] -// aux-build:structs.rs -extern crate structs; - -use structs::{NormalStruct, UnitStruct, TupleStruct}; - -// We only test matching here as we cannot create non-exhaustive -// structs from another crate. ie. they'll never pass in run-pass tests. - -fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { - let NormalStruct { first_field, second_field, .. } = ns; - - let TupleStruct { 0: first, 1: second, .. } = ts; - - let UnitStruct { .. } = us; -} - -fn main() { } diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs deleted file mode 100644 index 90b8219e2a3c0..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs +++ /dev/null @@ -1,22 +0,0 @@ -// run-pass -// aux-build:variants.rs -extern crate variants; - -use variants::NonExhaustiveVariants; - -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test - -fn main() { - let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 }; - let variant_struct = NonExhaustiveVariants::Struct { field: 340 }; - - match variant_struct { - NonExhaustiveVariants::Unit => "", - NonExhaustiveVariants::Struct { field, .. } => "", - NonExhaustiveVariants::Tuple(fe_tpl, ..) => "" - }; -} diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs index d9b1a9895104c..7423a970e2e3b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs @@ -12,4 +12,48 @@ fn main() { NonExhaustiveEnum::Tuple(_) => "second", NonExhaustiveEnum::Struct { .. } => "third" }; + + // Everything below this is expected to compile successfully. + + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => 1, + NonExhaustiveEnum::Tuple(_) => 2, + // This particular arm tests that a enum marked as non-exhaustive + // will not error if its variants are matched exhaustively. + NonExhaustiveEnum::Struct { field } => field, + _ => 0 // no error with wildcard + }; + + match enum_unit { + _ => "no error with only wildcard" + }; + + // #53549: Check that variant constructors can still be called normally. + match NonExhaustiveEnum::Unit { + NonExhaustiveEnum::Unit => {}, + _ => {} + }; + + match NonExhaustiveEnum::Tuple(2) { + NonExhaustiveEnum::Tuple(2) => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Unit {}) { + NonExhaustiveEnum::Unit {} => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Tuple { 0: 2 }) { + NonExhaustiveEnum::Tuple { 0: 2 } => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Struct { field: 2 }) { + NonExhaustiveEnum::Struct { field: 2 } => {}, + _ => {} + }; + } diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs similarity index 99% rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs rename to src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs index 384e099275e9b..a3626bf60b260 100644 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs @@ -1,4 +1,5 @@ // run-pass + #![feature(non_exhaustive)] #[non_exhaustive] diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs similarity index 73% rename from src/test/ui/rfc-2008-non-exhaustive/structs.rs rename to src/test/ui/rfc-2008-non-exhaustive/struct.rs index 303d71d12df33..94ac588d24083 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/structs.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs @@ -35,3 +35,15 @@ fn main() { let UnitStruct { } = us; //~^ ERROR `..` required with struct marked as non-exhaustive } + +// Everything below this is expected to compile successfully. + +// We only test matching here as we cannot create non-exhaustive +// structs from another crate. ie. they'll never pass in run-pass tests. +fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { + let NormalStruct { first_field, second_field, .. } = ns; + + let TupleStruct { 0: first, 1: second, .. } = ts; + + let UnitStruct { .. } = us; +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr similarity index 88% rename from src/test/ui/rfc-2008-non-exhaustive/structs.stderr rename to src/test/ui/rfc-2008-non-exhaustive/struct.stderr index 6213c392a9b47..ecfad88a82552 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -1,29 +1,29 @@ error[E0423]: expected function, found struct `TupleStruct` - --> $DIR/structs.rs:20:14 + --> $DIR/struct.rs:20:14 | LL | let ts = TupleStruct(640, 480); | ^^^^^^^^^^^ constructor is not visible here due to private fields error[E0423]: expected value, found struct `UnitStruct` - --> $DIR/structs.rs:29:14 + --> $DIR/struct.rs:29:14 | LL | let us = UnitStruct; | ^^^^^^^^^^ constructor is not visible here due to private fields error[E0603]: tuple struct `TupleStruct` is private - --> $DIR/structs.rs:23:32 + --> $DIR/struct.rs:23:32 | LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ error[E0603]: unit struct `UnitStruct` is private - --> $DIR/structs.rs:32:32 + --> $DIR/struct.rs:32:32 | LL | let us_explicit = structs::UnitStruct; | ^^^^^^^^^^ error[E0639]: cannot create non-exhaustive struct using struct expression - --> $DIR/structs.rs:7:14 + --> $DIR/struct.rs:7:14 | LL | let fr = FunctionalRecord { | ______________^ @@ -35,25 +35,25 @@ LL | | }; | |_____^ error[E0639]: cannot create non-exhaustive struct using struct expression - --> $DIR/structs.rs:14:14 + --> $DIR/struct.rs:14:14 | LL | let ns = NormalStruct { first_field: 640, second_field: 480 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:17:9 + --> $DIR/struct.rs:17:9 | LL | let NormalStruct { first_field, second_field } = ns; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:26:9 + --> $DIR/struct.rs:26:9 | LL | let TupleStruct { 0: first_field, 1: second_field } = ts; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:35:9 + --> $DIR/struct.rs:35:9 | LL | let UnitStruct { } = us; | ^^^^^^^^^^^^^^ diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs similarity index 99% rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs rename to src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs index 5e71cce1297cb..2b1d7d9ac5030 100644 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs @@ -1,4 +1,5 @@ // run-pass + #![allow(unused_variables)] #![feature(non_exhaustive)] diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants.rs b/src/test/ui/rfc-2008-non-exhaustive/variant.rs similarity index 50% rename from src/test/ui/rfc-2008-non-exhaustive/variants.rs rename to src/test/ui/rfc-2008-non-exhaustive/variant.rs index 373bbc3547f38..bc346aea51cfc 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/variants.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/variant.rs @@ -1,26 +1,33 @@ // aux-build:variants.rs + extern crate variants; use variants::NonExhaustiveVariants; -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test - fn main() { let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; //~^ ERROR cannot create non-exhaustive variant - let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 }; - //~^ ERROR cannot create non-exhaustive variant + let variant_tuple = NonExhaustiveVariants::Tuple(640); + //~^ ERROR tuple variant `Tuple` is private [E0603] + + let variant_unit = NonExhaustiveVariants::Unit; + //~^ ERROR unit variant `Unit` is private [E0603] match variant_struct { NonExhaustiveVariants::Unit => "", + //~^ ERROR unit variant `Unit` is private [E0603] NonExhaustiveVariants::Tuple(fe_tpl) => "", - //~^ ERROR `..` required with variant marked as non-exhaustive + //~^ ERROR tuple variant `Tuple` is private [E0603] NonExhaustiveVariants::Struct { field } => "" //~^ ERROR `..` required with variant marked as non-exhaustive }; + + if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + //~^ ERROR tuple variant `Tuple` is private [E0603] + } + + if let NonExhaustiveVariants::Struct { field } = variant_struct { + //~^ ERROR `..` required with variant marked as non-exhaustive + } } diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr new file mode 100644 index 0000000000000..edfca78915017 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr @@ -0,0 +1,52 @@ +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:11:48 + | +LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); + | ^^^^^ + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:14:47 + | +LL | let variant_unit = NonExhaustiveVariants::Unit; + | ^^^^ + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:18:32 + | +LL | NonExhaustiveVariants::Unit => "", + | ^^^^ + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:20:32 + | +LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", + | ^^^^^ + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:26:35 + | +LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + | ^^^^^ + +error[E0639]: cannot create non-exhaustive variant using struct expression + --> $DIR/variant.rs:8:26 + | +LL | let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:22:9 + | +LL | NonExhaustiveVariants::Struct { field } => "" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:30:12 + | +LL | if let NonExhaustiveVariants::Struct { field } = variant_struct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +Some errors occurred: E0603, E0638, E0639. +For more information about an error, try `rustc --explain E0603`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs deleted file mode 100644 index 9ed244144dff9..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(non_exhaustive)] - -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ - -pub enum NonExhaustiveVariants { - #[non_exhaustive] Unit, - //~^ ERROR #[non_exhaustive] is not yet supported on variants - #[non_exhaustive] Tuple(u32), - //~^ ERROR #[non_exhaustive] is not yet supported on variants - #[non_exhaustive] Struct { field: u32 } - //~^ ERROR #[non_exhaustive] is not yet supported on variants -} - -fn main() { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr b/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr deleted file mode 100644 index 5b099d58ec467..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:9:23 - | -LL | #[non_exhaustive] Unit, - | ^^^^ - -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:11:23 - | -LL | #[non_exhaustive] Tuple(u32), - | ^^^^^^^^^^ - -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:13:23 - | -LL | #[non_exhaustive] Struct { field: u32 } - | ^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs similarity index 76% rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs rename to src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs index 603e69b9ff9b0..470a5ea9833ad 100644 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs @@ -1,11 +1,6 @@ // run-pass -#![feature(non_exhaustive)] -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test +#![feature(non_exhaustive)] pub enum NonExhaustiveVariants { #[non_exhaustive] Unit, From b7dc8e71ccb15ff54b9cdf0f67776cc3cf4bea33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Mar 2019 19:58:00 -0700 Subject: [PATCH 07/25] fix text after rebase --- src/test/ui/parser/recover-from-bad-variant.stderr | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr index bd4a562d72d19..1eba6d7d52877 100644 --- a/src/test/ui/parser/recover-from-bad-variant.stderr +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -3,6 +3,14 @@ error: expected type, found `3` | LL | let x = Enum::Foo(a: 3, b: 4); | ^ expecting a type here because of type ascription + | + = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/recover-from-bad-variant.rs:7:23 + | +LL | let x = Enum::Foo(a: 3, b: 4); + | ^ + = help: this might be indicative of a syntax error elsewhere error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo` --> $DIR/recover-from-bad-variant.rs:10:9 From 9ea6790a6444fbf65d0cba9c9518abf70077f3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Mar 2019 19:58:45 -0700 Subject: [PATCH 08/25] Deduplicate parse recovery code --- src/libsyntax/parse/parser.rs | 78 +++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ea0c7e0e36662..d4b8c7ce15941 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2639,11 +2639,9 @@ impl<'a> Parser<'a> { while self.token != token::CloseDelim(token::Paren) { es.push(match self.parse_expr() { Ok(es) => es, - Err(mut err) => { // recover from parse error in tuple list - err.emit(); - self.consume_block(token::Paren); - hi = self.prev_span; - return Ok(self.mk_expr(lo.to(hi), ExprKind::Err, ThinVec::new())); + Err(err) => { + // recover from parse error in tuple list + return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err))); } }); recovered = self.expect_one_of( @@ -3254,44 +3252,54 @@ impl<'a> Parser<'a> { } if self.expr_is_complete(&e) { break; } match self.token { - // expr(...) - token::OpenDelim(token::Paren) => { - match self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - ) { - Ok(es) => { + // expr(...) + token::OpenDelim(token::Paren) => { + let seq = self.parse_unspanned_seq( + &token::OpenDelim(token::Paren), + &token::CloseDelim(token::Paren), + SeqSep::trailing_allowed(token::Comma), + |p| Ok(p.parse_expr()?) + ).map(|es| { let nd = self.mk_call(e, es); - hi = self.prev_span; - e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); - } - Err(mut err) => { // recover from parse error in argument list - err.emit(); - self.consume_block(token::Paren); - hi = self.prev_span; - e = self.mk_expr(lo.to(hi), ExprKind::Err, ThinVec::new()); - } + let hi = self.prev_span; + self.mk_expr(lo.to(hi), nd, ThinVec::new()) + }); + e = self.recover_seq_parse_error(token::Paren, lo, seq); } - } - // expr[...] - // Could be either an index expression or a slicing expression. - token::OpenDelim(token::Bracket) => { - self.bump(); - let ix = self.parse_expr()?; - hi = self.span; - self.expect(&token::CloseDelim(token::Bracket))?; - let index = self.mk_index(e, ix); - e = self.mk_expr(lo.to(hi), index, ThinVec::new()) - } - _ => return Ok(e) + // expr[...] + // Could be either an index expression or a slicing expression. + token::OpenDelim(token::Bracket) => { + self.bump(); + let ix = self.parse_expr()?; + hi = self.span; + self.expect(&token::CloseDelim(token::Bracket))?; + let index = self.mk_index(e, ix); + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) + } + _ => return Ok(e) } } return Ok(e); } + fn recover_seq_parse_error( + &mut self, + delim: token::DelimToken, + lo: Span, + result: PResult<'a, P>, + ) -> P { + match result { + Ok(x) => x, + Err(mut err) => { + err.emit(); + // recover from parse error + self.consume_block(delim); + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + } + } + } + crate fn process_potential_macro_variable(&mut self) { let (token, span) = match self.token { token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() && From 07857f74065c567a46549cb88d6a0aba3cef484c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Mar 2019 04:47:09 -0700 Subject: [PATCH 09/25] review comments --- src/librustc_typeck/check/demand.rs | 83 +++++++++++++++-------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 5939f965269be..7886af0c97393 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -249,6 +249,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } + fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId) -> bool { + let parent_id = self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id); + let mut is_struct_pat_shorthand_field = false; + if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { + // Account for fields + if let Node::Expr(hir::Expr { + node: hir::ExprKind::Struct(_, fields, ..), .. + }) = parent { + if let Ok(src) = cm.span_to_snippet(sp) { + for field in fields { + if field.ident.as_str() == src.as_str() && field.is_shorthand { + is_struct_pat_shorthand_field = true; + break; + } + } + } + } + }; + } + /// This function is used to determine potential "simple" improvements or users' errors and /// provide them useful help. For example: /// @@ -277,23 +297,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let parent_id = self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id); - let mut is_struct_pat_shorthand_field = false; - if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { - // Account for fields - if let Node::Expr(hir::Expr { - node: hir::ExprKind::Struct(_, fields, ..), .. - }) = parent { - if let Ok(src) = cm.span_to_snippet(sp) { - for field in fields { - if field.ident.as_str() == src.as_str() && field.is_shorthand { - is_struct_pat_shorthand_field = true; - break; - } - } - } - } - }; + let mut is_struct_pat_shorthand_field = + self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id); match (&expected.sty, &checked_ty.sty) { (&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { @@ -333,12 +338,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // bar(&x); // error, expected &mut // ``` let ref_ty = match mutability { - hir::Mutability::MutMutable => self.tcx.mk_mut_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), - hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), + hir::Mutability::MutMutable => { + self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty) + } + hir::Mutability::MutImmutable => { + self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty) + } }; if self.can_coerce(ref_ty, expected) { if let Ok(src) = cm.span_to_snippet(sp) { @@ -359,22 +364,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); } - return Some(match (mutability, is_struct_pat_shorthand_field) { - (hir::Mutability::MutMutable, false) => { - (sp, "consider mutably borrowing here", - format!("&mut {}", sugg_expr)) - } - (hir::Mutability::MutImmutable, false) => { - (sp, "consider borrowing here", format!("&{}", sugg_expr)) - } - (hir::Mutability::MutMutable, true) => { - (sp, "consider mutably borrowing here", - format!("{}: &mut {}", sugg_expr, sugg_expr)) - } - (hir::Mutability::MutImmutable, true) => { - (sp, "consider borrowing here", - format!("{}: &{}", sugg_expr, sugg_expr)) - } + let field_name = if is_struct_pat_shorthand_field { + format!("{}: ", sugg_expr) + } else { + String::new() + }; + return Some(match mutability { + hir::Mutability::MutMutable => ( + sp, + "consider mutably borrowing here", + format!("{}&mut {}", field_name, sugg_expr), + ), + hir::Mutability::MutImmutable => ( + sp, + "consider borrowing here", + format!("{}&{}", field_name, sugg_expr), + ), }); } } From e995fa8aeaa4bfe92d270ddb9e1dd8b5516eaa25 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 28 Mar 2019 20:45:40 -0400 Subject: [PATCH 10/25] implement `AsRawFd` for stdio locks --- src/libstd/sys/redox/ext/io.rs | 15 +++++++++++++++ src/libstd/sys/unix/ext/io.rs | 15 +++++++++++++++ src/libstd/sys/windows/ext/io.rs | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs index f431f96c541f7..c21d216478fb7 100644 --- a/src/libstd/sys/redox/ext/io.rs +++ b/src/libstd/sys/redox/ext/io.rs @@ -115,6 +115,21 @@ impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { 2 } } +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { 0 } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { 1 } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { 2 } +} + #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::TcpStream { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 1a0b3b8962bd1..6bcc59495e363 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -95,3 +95,18 @@ impl AsRawFd for io::Stdout { impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } } + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } +} diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index 1a7d734b89e4b..ec47c2e9d5afd 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -83,6 +83,27 @@ impl AsRawHandle for io::Stderr { } } +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdinLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle } + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdoutLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle } + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StderrLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle } + } +} + #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawHandle for fs::File { unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { From 18938416e4d34d7f7d64d11decd87ce47036bb75 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 23 Mar 2019 02:35:22 +0100 Subject: [PATCH 11/25] Update documentation. This commit updates the unstable book and diagnostics to reflect that the `#[non_exhaustive]` attribute is now available for enum variants. --- .../src/language-features/non-exhaustive.md | 11 ++++++----- src/librustc_typeck/diagnostics.rs | 13 +++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md index f9840e1b83f2b..907147c17ef8e 100644 --- a/src/doc/unstable-book/src/language-features/non-exhaustive.md +++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md @@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109] ------------------------ The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute -on structs and enums. When applied within a crate, users of the crate will need -to use the `_` pattern when matching enums and use the `..` pattern when -matching structs. Structs marked as `non_exhaustive` will not be able to be -created normally outside of the defining crate. This is demonstrated below: +on structs, enums and enum variants. When applied within a crate, users of the +crate will need to use the `_` pattern when matching enums and use the `..` +pattern when matching structs. Enum variants cannot be matched against. +Structs and enum variants marked as `non_exhaustive` will not be able to +be created normally outside of the defining crate. This is demonstrated +below: ```rust,ignore (pseudo-Rust) use std::error::Error as StdError; @@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 }; // when marked non_exhaustive. let &Config { window_width, window_height, .. } = config; ``` - diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index cde37fb23c320..22f24df450f46 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4341,11 +4341,12 @@ foo.method(); // Ok! "##, E0638: r##" -This error indicates that the struct or enum must be matched non-exhaustively -as it has been marked as `non_exhaustive`. +This error indicates that the struct, enum or enum variant must be matched +non-exhaustively as it has been marked as `non_exhaustive`. When applied within a crate, downstream users of the crate will need to use the `_` pattern when matching enums and use the `..` pattern when matching structs. +Downstream crates cannot match against non-exhaustive enum variants. For example, in the below example, since the enum is marked as `non_exhaustive`, it is required that downstream crates match non-exhaustively @@ -4390,10 +4391,10 @@ Similarly, for structs, match with `..` to avoid this error. "##, E0639: r##" -This error indicates that the struct or enum cannot be instantiated from -outside of the defining crate as it has been marked as `non_exhaustive` and as -such more fields/variants may be added in future that could cause adverse side -effects for this code. +This error indicates that the struct, enum or enum variant cannot be +instantiated from outside of the defining crate as it has been marked +as `non_exhaustive` and as such more fields/variants may be added in +future that could cause adverse side effects for this code. It is recommended that you look for a `new` function or equivalent in the crate's documentation. From 49a6da2cda1a208838911e296fc72a6791e68406 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 23 Mar 2019 02:36:30 +0100 Subject: [PATCH 12/25] Support non-exhaustive enum variants in rustdoc. This commit adds support for non-exhaustive enum variants in rustdoc, extending the existing support for non-exhaustive enums and structs. --- src/librustdoc/clean/mod.rs | 3 +++ src/librustdoc/html/render.rs | 15 ++++++++++++++- src/librustdoc/html/static/main.js | 5 +++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 61dbf00a1f536..114294cde4ee2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -421,6 +421,9 @@ impl Item { pub fn is_enum(&self) -> bool { self.type_() == ItemType::Enum } + pub fn is_variant(&self) -> bool { + self.type_() == ItemType::Variant + } pub fn is_associated_type(&self) -> bool { self.type_() == ItemType::AssociatedType } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 445ce0637662d..982c033be99fd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2596,7 +2596,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result { if item.is_non_exhaustive() { write!(w, "
", { - if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" } + if item.is_struct() { + "struct" + } else if item.is_enum() { + "enum" + } else if item.is_variant() { + "variant" + } else { + "type" + } })?; if item.is_struct() { @@ -2609,6 +2617,10 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm write!(w, "Non-exhaustive enums could have additional variants added in future. \ Therefore, when matching against variants of non-exhaustive enums, an \ extra wildcard arm must be added to account for any future variants.")?; + } else if item.is_variant() { + write!(w, "Non-exhaustive enum variants could have additional fields added in future. \ + Therefore, non-exhaustive enum variants cannot be constructed in external \ + crates and cannot be matched against.")?; } else { write!(w, "This type will require a wildcard arm in any match statements or \ constructors.")?; @@ -3671,6 +3683,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, } write!(w, "")?; document(w, cx, variant)?; + document_non_exhaustive(w, variant)?; use crate::clean::{Variant, VariantKind}; if let clean::VariantItem(Variant { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index fef6910f40a57..85dc4d57337c8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2247,6 +2247,8 @@ if (!DOMTokenList.prototype.remove) { otherMessage += "struct"; } else if (hasClass(e, "non-exhaustive-enum")) { otherMessage += "enum"; + } else if (hasClass(e, "non-exhaustive-variant")) { + otherMessage += "enum variant"; } else if (hasClass(e, "non-exhaustive-type")) { otherMessage += "type"; } @@ -2264,6 +2266,9 @@ if (!DOMTokenList.prototype.remove) { if (hasClass(e, "type-decl") === true && showItemDeclarations === true) { collapseDocs(e.previousSibling.childNodes[0], "toggle"); } + if (hasClass(e, "non-exhaustive") === true) { + collapseDocs(e.previousSibling.childNodes[0], "toggle"); + } } } From ff33b2733ad23d105160c4f1946d606f4ef31870 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 Mar 2019 14:24:14 +0100 Subject: [PATCH 13/25] Whitelist `rustc_on_unimplemented` to avoid erroneous flagging as an unused attribute. --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 96c89d3176ab6..3a1f6736ebd33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -906,7 +906,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu not currently handle destructors.", cfg_fn!(thread_local))), - ("rustc_on_unimplemented", Normal, template!(List: + ("rustc_on_unimplemented", Whitelisted, template!(List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, NameValueStr: "message"), Gated(Stability::Unstable, From 3592079765d4d76f19b3a9501de5f8cc47f11a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Mar 2019 20:10:00 -0700 Subject: [PATCH 14/25] revert change to test file as per review request --- src/test/ui/parser/pat-tuple-1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/parser/pat-tuple-1.rs b/src/test/ui/parser/pat-tuple-1.rs index d76096c25988d..0e49b547f7d0f 100644 --- a/src/test/ui/parser/pat-tuple-1.rs +++ b/src/test/ui/parser/pat-tuple-1.rs @@ -1,6 +1,5 @@ fn main() { match (0, 1) { - (, ..) => {} - //~^ ERROR expected pattern, found `,` + (, ..) => {} //~ ERROR expected pattern, found `,` } } From 0b9669729953a94602d74887efe488f918a1ba13 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 Mar 2019 15:03:31 +0100 Subject: [PATCH 15/25] Regression test for incremental treatment of rustc_on_unimplemented. --- ...ssue-59523-on-implemented-is-not-unused.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/incremental/issue-59523-on-implemented-is-not-unused.rs diff --git a/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs new file mode 100644 index 0000000000000..3d16a1543f43a --- /dev/null +++ b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs @@ -0,0 +1,27 @@ +// We should not see the unused_attributes lint fire for +// rustc_on_unimplemented, but with this bug we are seeing it fire (on +// subsequent runs) if incremental compilation is enabled. + +// revisions: rpass1 rpass2 +// compile-pass + +#![feature(on_unimplemented)] +#![deny(unused_attributes)] + +#[rustc_on_unimplemented = "invalid"] +trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +#[rustc_on_unimplemented = "a usize is required to index into a slice"] +impl Index for [i32] { + type Output = i32; + fn index(&self, index: usize) -> &i32 { + &self[index] + } +} + +fn main() { + Index::::index(&[1, 2, 3] as &[i32], 2); +} From 7642f108e246d955252bb8225bc1847c627f046d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 Mar 2019 15:04:09 +0100 Subject: [PATCH 16/25] Whitelist rustc_layout_scalar_valid_range_{start,end} so incr comp does not flag them as unused. --- src/libsyntax/feature_gate.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3a1f6736ebd33..dcb55fb572f33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -962,6 +962,20 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_layout_scalar_valid_range_start", Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + "rustc_attrs", + "the `#[rustc_layout_scalar_valid_range_start]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ("rustc_layout_scalar_valid_range_end", Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + "rustc_attrs", + "the `#[rustc_layout_scalar_valid_range_end]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable, "rustc_attrs", "the `#[rustc_regions]` attribute \ From cbbd4d5f98da0c218958766355ea58d28d92f68d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 Mar 2019 15:05:03 +0100 Subject: [PATCH 17/25] Regression test for incremental treatment of rustc_scalar_valid_range_{start,end}. --- ...layout-scalar-valid-range-is-not-unused.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs diff --git a/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs new file mode 100644 index 0000000000000..e4802cba9b6d7 --- /dev/null +++ b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs @@ -0,0 +1,19 @@ +// We should not see the unused_attributes lint fire for +// rustc_layout_scalar_valid_range_start, but with this bug we are +// seeing it fire (on subsequent runs) if incremental compilation is +// enabled. + +// revisions: rpass1 rpass2 +// compile-pass + +#![feature(rustc_attrs)] +#![deny(unused_attributes)] + +#[rustc_layout_scalar_valid_range_start(10)] +#[rustc_layout_scalar_valid_range_end(30)] +struct RestrictedRange(u32); +const OKAY_RANGE: RestrictedRange = unsafe { RestrictedRange(20) }; + +fn main() { + OKAY_RANGE.0; +} From f10e44420a072881cce6d7819d2b2bfb99df90df Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 29 Mar 2019 15:56:22 +0100 Subject: [PATCH 18/25] Edited the dbg! docs stating that dbg! works the same way in release builds. --- src/libstd/macros.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9d0eb2e6b1cef..ee5a8e6631ec7 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -231,10 +231,13 @@ macro_rules! eprintln { /// to give up ownership, you can instead borrow with `dbg!(&expr)` /// for some expression `expr`. /// +/// The `dbg!` macro works exactly the same in release builds. This is useful when debugging issues +/// that only occur in release builds or when debugging in release mode is significantly faster. +/// /// Note that the macro is intended as a debugging tool and therefore you /// should avoid having uses of it in version control for longer periods. /// Use cases involving debug output that should be added to version control -/// may be better served by macros such as `debug!` from the `log` crate. +/// are better served by macros such as [`debug!`][debug-log] from the [`log`][log] crate. /// /// # Stability /// @@ -306,6 +309,8 @@ macro_rules! eprintln { /// ``` /// /// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) +/// [debug-log]: https://docs.rs/log/*/log/macro.debug.html +/// [log]: https://docs.rs/log/ #[macro_export] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { From 9240092fe3bf32803ac9f9a247a098844d6f4780 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 29 Mar 2019 16:18:24 +0100 Subject: [PATCH 19/25] Adjusted the indentation. --- src/libstd/macros.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index ee5a8e6631ec7..03d2a3072167c 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -231,8 +231,9 @@ macro_rules! eprintln { /// to give up ownership, you can instead borrow with `dbg!(&expr)` /// for some expression `expr`. /// -/// The `dbg!` macro works exactly the same in release builds. This is useful when debugging issues -/// that only occur in release builds or when debugging in release mode is significantly faster. +/// The `dbg!` macro works exactly the same in release builds. +/// This is useful when debugging issues that only occur in release builds or when debugging in +/// release mode is significantly faster. /// /// Note that the macro is intended as a debugging tool and therefore you /// should avoid having uses of it in version control for longer periods. From fe210d0df17b16d3afa3ec5462767bd9f20a4c0c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 29 Mar 2019 16:24:13 +0100 Subject: [PATCH 20/25] Update src/libstd/macros.rs Wrapped lines earlier such that it is more coherent with the rest of the text. Co-Authored-By: DevQps <46896178+DevQps@users.noreply.github.com> --- src/libstd/macros.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 03d2a3072167c..37e88ee620993 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -232,7 +232,8 @@ macro_rules! eprintln { /// for some expression `expr`. /// /// The `dbg!` macro works exactly the same in release builds. -/// This is useful when debugging issues that only occur in release builds or when debugging in +/// This is useful when debugging issues that only occur in release +/// builds or when debugging in release mode is significantly faster. /// release mode is significantly faster. /// /// Note that the macro is intended as a debugging tool and therefore you From 8705de49e1de83f357fcd6224f9e0a5e266915da Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 29 Mar 2019 16:25:38 +0100 Subject: [PATCH 21/25] Update src/libstd/macros.rs Removed duplicate line. Co-Authored-By: DevQps <46896178+DevQps@users.noreply.github.com> --- src/libstd/macros.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 37e88ee620993..bc0a97939d881 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -234,7 +234,6 @@ macro_rules! eprintln { /// The `dbg!` macro works exactly the same in release builds. /// This is useful when debugging issues that only occur in release /// builds or when debugging in release mode is significantly faster. -/// release mode is significantly faster. /// /// Note that the macro is intended as a debugging tool and therefore you /// should avoid having uses of it in version control for longer periods. From ddfa47f4b4926d411d52afa0e29dead708c2a9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 Mar 2019 06:46:39 -0700 Subject: [PATCH 22/25] Fix incorrect code --- src/librustc_typeck/check/demand.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 7886af0c97393..cca6da4f82c32 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -249,9 +249,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId) -> bool { - let parent_id = self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id); - let mut is_struct_pat_shorthand_field = false; + fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp: Span) -> bool { + let cm = self.sess().source_map(); + let parent_id = self.tcx.hir().get_parent_node_by_hir_id(hir_id); if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { // Account for fields if let Node::Expr(hir::Expr { @@ -260,13 +260,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Ok(src) = cm.span_to_snippet(sp) { for field in fields { if field.ident.as_str() == src.as_str() && field.is_shorthand { - is_struct_pat_shorthand_field = true; - break; + return true; } } } } - }; + } + false } /// This function is used to determine potential "simple" improvements or users' errors and @@ -297,8 +297,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let mut is_struct_pat_shorthand_field = - self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id); + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field( + expr.hir_id, + sp, + ); match (&expected.sty, &checked_ty.sty) { (&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { From 9e4ec7a568e22485f55108dab10f41e0536b5160 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 29 Mar 2019 19:47:19 +0100 Subject: [PATCH 23/25] Collapse blanket impls in the same way as normal impls --- src/librustdoc/html/static/main.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index aad7eb627bfe2..a16e225f1c645 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2071,6 +2071,14 @@ if (!DOMTokenList.prototype.remove) { collapser(e, collapse); }); } + + var blanket_list = document.getElementById("blanket-implementations-list"); + + if (blanket_list !== null) { + onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) { + collapser(e, collapse); + }); + } } } From b6fb3e34117008f7f97094b0f1521116a4e66473 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 29 Mar 2019 09:30:08 -0700 Subject: [PATCH 24/25] In doc examples, don't ignore read/write results Calling `Read::read` or `Write::write` without checking the returned `usize` value is almost always an error. Example code in the documentation should demonstrate how to use the return value correctly. Otherwise, people might copy the example code thinking that it is okay to "fire and forget" these methods. --- src/libstd/io/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 14c850b6b0547..14a16f3fc0f04 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -24,9 +24,9 @@ //! let mut buffer = [0; 10]; //! //! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! let n = f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); +//! println!("The bytes: {:?}", &buffer[..n]); //! Ok(()) //! } //! ``` @@ -56,9 +56,9 @@ //! f.seek(SeekFrom::End(-10))?; //! //! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! let n = f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); +//! println!("The bytes: {:?}", &buffer[..n]); //! Ok(()) //! } //! ``` @@ -537,7 +537,9 @@ pub trait Read { /// let mut buffer = [0; 10]; /// /// // read up to 10 bytes - /// f.read(&mut buffer[..])?; + /// let n = f.read(&mut buffer[..])?; + /// + /// println!("The bytes: {:?}", &buffer[..n]); /// Ok(()) /// } /// ``` @@ -1062,12 +1064,23 @@ impl Initializer { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { +/// let data = b"some bytes"; +/// +/// let mut pos = 0; /// let mut buffer = File::create("foo.txt")?; /// -/// buffer.write(b"some bytes")?; +/// while pos < data.len() { +/// let bytes_written = buffer.write(&data[pos..])?; +/// pos += bytes_written; +/// } /// Ok(()) /// } /// ``` +/// +/// The trait also provides convenience methods like [`write_all`], which calls +/// `write` in a loop until its entire input has been written. +/// +/// [`write_all`]: #method.write_all #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] pub trait Write { From 7ce0b67272a760aff12505b5ca04357a3dc5c0ed Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Fri, 29 Mar 2019 15:03:14 -0700 Subject: [PATCH 25/25] Fix OnceWith docstring. This was incorrectly copypasta'd from RepeatWith. --- src/libcore/iter/sources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index ffc24df3ed42e..7934e5880d7d2 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -375,8 +375,8 @@ pub fn once(value: T) -> Once { Once { inner: Some(value).into_iter() } } -/// An iterator that repeats elements of type `A` endlessly by -/// applying the provided closure `F: FnMut() -> A`. +/// An iterator that yields a single element of type `A` by +/// applying the provided closure `F: FnOnce() -> A`. /// /// This `struct` is created by the [`once_with`] function. /// See its documentation for more.