From e094ee5f102dfea8e99137d3818510cd178e8817 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 25 Mar 2022 23:43:54 -0700 Subject: [PATCH 1/5] Add `do yeet` expressions to allow experimentation in nightly Using an obviously-placeholder syntax. An RFC would still be needed before this could have any chance at stabilization, and it might be removed at any point. But I'd really like to have it in nightly at least to ensure it works well with try_trait_v2, especially as we refactor the traits. --- compiler/rustc_ast/src/ast.rs | 5 +++ compiler/rustc_ast/src/mut_visit.rs | 3 ++ compiler/rustc_ast/src/util/parser.rs | 4 +- compiler/rustc_ast/src/visit.rs | 3 ++ compiler/rustc_ast_lowering/src/expr.rs | 39 +++++++++++++++++++ compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_passes/src/feature_gate.rs | 8 ++++ .../rustc_ast_pretty/src/pprust/state/expr.rs | 14 ++++++- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_parse/src/parser/expr.rs | 21 ++++++++++ compiler/rustc_span/src/hygiene.rs | 2 + compiler/rustc_span/src/symbol.rs | 4 ++ library/core/src/ops/mod.rs | 3 ++ library/core/src/ops/try_trait.rs | 22 +++++++++++ library/core/src/option.rs | 8 ++++ library/core/src/result.rs | 8 ++++ .../src/language-features/yeet-expr.md | 26 +++++++++++++ src/test/pretty/yeet-expr.rs | 12 ++++++ .../feature-gates/feature-gate-yeet_expr.rs | 9 +++++ .../feature-gate-yeet_expr.stderr | 21 ++++++++++ src/test/ui/try-trait/yeet-for-option.rs | 11 ++++++ src/test/ui/try-trait/yeet-for-result.rs | 11 ++++++ 23 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/yeet-expr.md create mode 100644 src/test/pretty/yeet-expr.rs create mode 100644 src/test/ui/feature-gates/feature-gate-yeet_expr.rs create mode 100644 src/test/ui/feature-gates/feature-gate-yeet_expr.stderr create mode 100644 src/test/ui/try-trait/yeet-for-option.rs create mode 100644 src/test/ui/try-trait/yeet-for-result.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cdcd221e811a7..1a18d1964c978 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1275,6 +1275,7 @@ impl Expr { ExprKind::Paren(..) => ExprPrecedence::Paren, ExprKind::Try(..) => ExprPrecedence::Try, ExprKind::Yield(..) => ExprPrecedence::Yield, + ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::Err => ExprPrecedence::Err, } } @@ -1462,6 +1463,10 @@ pub enum ExprKind { /// A `yield`, with an optional value to be yielded. Yield(Option>), + /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever), + /// with an optional value to be returned. + Yeet(Option>), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d7b1bc6a7f580..4bf3d483f7358 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1394,6 +1394,9 @@ pub fn noop_visit_expr( ExprKind::Ret(expr) => { visit_opt(expr, |expr| vis.visit_expr(expr)); } + ExprKind::Yeet(expr) => { + visit_opt(expr, |expr| vis.visit_expr(expr)); + } ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 742a7d1d2df70..74b7fe9e24955 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -247,6 +247,7 @@ pub enum ExprPrecedence { Continue, Ret, Yield, + Yeet, Range, @@ -299,7 +300,8 @@ impl ExprPrecedence { ExprPrecedence::Break | ExprPrecedence::Continue | ExprPrecedence::Ret | - ExprPrecedence::Yield => PREC_JUMP, + ExprPrecedence::Yield | + ExprPrecedence::Yeet => PREC_JUMP, // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e08ba73e0ae31..fa26716083f86 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -893,6 +893,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } + ExprKind::Yeet(ref optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac), ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 37ae41fabf987..5c3e3be21167a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -221,6 +221,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let e = e.as_ref().map(|x| self.lower_expr(x)); hir::ExprKind::Ret(e) } + ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), ExprKind::InlineAsm(ref asm) => { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } @@ -1543,6 +1544,44 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + /// Desugar `ExprKind::Yeet` from: `do yeet ` into: + /// ```rust + /// // If there is an enclosing `try {...}`: + /// break 'catch_target FromResidual::from_residual(Yeet(residual)), + /// // Otherwise: + /// return FromResidual::from_residual(Yeet(residual)), + /// ``` + /// But to simplify this, there's a `from_yeet` lang item function which + /// handles the combined `FromResidual::from_residual(Yeet(residual))`. + fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> { + // The expression (if present) or `()` otherwise. + let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr { + (sub_expr.span, self.lower_expr(sub_expr)) + } else { + (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span)) + }; + + let unstable_span = self.mark_span_with_reason( + DesugaringKind::YeetExpr, + span, + self.allow_try_trait.clone(), + ); + + let from_yeet_expr = self.wrap_in_try_constructor( + hir::LangItem::TryTraitFromYeet, + unstable_span, + yeeted_expr, + yeeted_span, + ); + + if let Some(catch_node) = self.catch_scope { + let target_id = Ok(self.lower_node_id(catch_node)); + hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) + } else { + hir::ExprKind::Ret(Some(from_yeet_expr)) + } + } + // ========================================================================= // Helper methods for building HIR. // ========================================================================= diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 125acdcc27d97..5a95e5b084ad4 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -85,7 +85,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { task_context: None, current_item: None, captured_lifetimes: None, - allow_try_trait: Some([sym::try_trait_v2][..].into()), + allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), }; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 649af48e48adf..add9955b18444 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -619,6 +619,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } + ast::ExprKind::Yeet(_) => { + gate_feature_post!( + &self, + yeet_expr, + e.span, + "`do yeet` expression is experimental" + ); + } ast::ExprKind::Block(_, Some(label)) => { gate_feature_post!( &self, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9de4cbbee13f0..9f44f1b6cc205 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -64,7 +64,10 @@ impl<'a> State<'a> { // parses as the erroneous construct `if (return {})`, not `if (return) {}`. pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool { match expr.kind { - ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true, + ast::ExprKind::Break(..) + | ast::ExprKind::Closure(..) + | ast::ExprKind::Ret(..) + | ast::ExprKind::Yeet(..) => true, _ => parser::contains_exterior_struct_lit(expr), } } @@ -502,6 +505,15 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } } + ast::ExprKind::Yeet(ref result) => { + self.word("do"); + self.word(" "); + self.word("yeet"); + if let Some(ref expr) = *result { + self.word(" "); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); + } + } ast::ExprKind::InlineAsm(ref a) => { self.word("asm!"); self.print_inline_asm(a); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f3d4c8ab43843..9159d60463c4c 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -544,6 +544,8 @@ declare_features! ( (active, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` (active, wasm_abi, "1.53.0", Some(83788), None), + /// Allows `do yeet` expressions + (active, yeet_expr, "1.62.0", Some(96373), None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9318ebb40b09b..b3c22d4ec213d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -293,6 +293,7 @@ language_item_table! { TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None; PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 13e9a5e660fe6..6114e7aaa7bd7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1374,6 +1374,8 @@ impl<'a> Parser<'a> { self.parse_break_expr(attrs) } else if self.eat_keyword(kw::Yield) { self.parse_yield_expr(attrs) + } else if self.is_do_yeet() { + self.parse_yeet_expr(attrs) } else if self.eat_keyword(kw::Let) { self.parse_let_expr(attrs) } else if self.eat_keyword(kw::Underscore) { @@ -1605,6 +1607,21 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Parse `"do" "yeet" expr?`. + fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + let lo = self.token.span; + + self.bump(); // `do` + self.bump(); // `yeet` + + let kind = ExprKind::Yeet(self.parse_expr_opt()?); + + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::yeet_expr, span); + let expr = self.mk_expr(span, kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten. /// If the label is followed immediately by a `:` token, the label and `:` are /// parsed as part of the expression (i.e. a labeled loop). The language team has @@ -2676,6 +2693,10 @@ impl<'a> Parser<'a> { && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } + fn is_do_yeet(&self) -> bool { + self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet]) + } + fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 3889639b50f45..447b73fa3c3ce 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1132,6 +1132,7 @@ pub enum DesugaringKind { CondTemporary, QuestionMark, TryBlock, + YeetExpr, /// Desugaring of an `impl Trait` in return type position /// to an `type Foo = impl Trait;` and replacing the /// `impl Trait` with `Foo`. @@ -1152,6 +1153,7 @@ impl DesugaringKind { DesugaringKind::Await => "`await` expression", DesugaringKind::QuestionMark => "operator `?`", DesugaringKind::TryBlock => "`try` block", + DesugaringKind::YeetExpr => "`do yeet` expression", DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", DesugaringKind::LetElse => "`let...else`", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e3ce8105a8b47..c1299c94c4bb3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -101,6 +101,7 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Union: "union", + Yeet: "yeet", } // Pre-interned symbols that can be referred to with `rustc_span::sym::*`. @@ -714,6 +715,7 @@ symbols! { from_residual, from_size_align_unchecked, from_usize, + from_yeet, fsub_fast, fundamental, future, @@ -1534,6 +1536,8 @@ symbols! { x87_reg, xer, xmm_reg, + yeet_desugar_details, + yeet_expr, ymm_reg, zmm_reg, } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 9d1e7e81b0e7e..31c1a1d099dc6 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -187,6 +187,9 @@ pub use self::range::OneSidedRange; #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::{FromResidual, Try}; +#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] +pub use self::try_trait::Yeet; + #[unstable(feature = "try_trait_v2_residual", issue = "91285")] pub use self::try_trait::Residual; diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index ba369e7f3aaa0..3eaee958b69bd 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -330,6 +330,22 @@ pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; } +#[cfg(not(bootstrap))] +#[unstable( + feature = "yeet_desugar_details", + issue = "none", + reason = "just here to simplify the desugaring; will never be stabilized" +)] +#[inline] +#[track_caller] // because `Result::from_residual` has it +#[lang = "from_yeet"] +pub fn from_yeet(yeeted: Y) -> T +where + T: FromResidual>, +{ + FromResidual::from_residual(Yeet(yeeted)) +} + /// Allows retrieving the canonical type implementing [`Try`] that has this type /// as its residual and allows it to hold an `O` as its output. /// @@ -395,3 +411,9 @@ impl FromResidual for NeverShortCircuit { impl Residual for NeverShortCircuitResidual { type TryType = NeverShortCircuit; } + +/// Implement `FromResidual>` on your type to enable +/// `do yeet expr` syntax in functions returning your type. +#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] +#[derive(Debug)] +pub struct Yeet(pub T); diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 91e4708f6a609..f339b076dd7d0 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2287,6 +2287,14 @@ impl const ops::FromResidual for Option { } } +#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] +impl ops::FromResidual> for Option { + #[inline] + fn from_residual(ops::Yeet(()): ops::Yeet<()>) -> Self { + None + } +} + #[unstable(feature = "try_trait_v2_residual", issue = "91285")] impl ops::Residual for Option { type TryType = Option; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index b2b132300a299..5e5f8a5ab9543 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -2107,6 +2107,14 @@ impl> const ops::FromResidual> ops::FromResidual> for Result { + #[inline] + fn from_residual(ops::Yeet(e): ops::Yeet) -> Self { + Err(From::from(e)) + } +} + #[unstable(feature = "try_trait_v2_residual", issue = "91285")] impl ops::Residual for Result { type TryType = Result; diff --git a/src/doc/unstable-book/src/language-features/yeet-expr.md b/src/doc/unstable-book/src/language-features/yeet-expr.md new file mode 100644 index 0000000000000..bc1ba4c916b64 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/yeet-expr.md @@ -0,0 +1,26 @@ +# `yeet_expr` + +The tracking issue for this feature is: [#96373] + +[#96373]: https://github.com/rust-lang/rust/issues/96373 + +------------------------ + +The `yeet_expr` feature adds support for `do yeet` expressions, +which can be used to early-exit from a function or `try` block. + +These are highly experimental, thus the placeholder syntax. + +```rust,edition2021 +#![feature(yeet_expr)] + +fn foo() -> Result { + do yeet 4; +} +assert_eq!(foo(), Err(4)); + +fn bar() -> Option { + do yeet; +} +assert_eq!(bar(), None); +``` diff --git a/src/test/pretty/yeet-expr.rs b/src/test/pretty/yeet-expr.rs new file mode 100644 index 0000000000000..c899f11b7240e --- /dev/null +++ b/src/test/pretty/yeet-expr.rs @@ -0,0 +1,12 @@ +// pp-exact +#![feature(yeet_expr)] + +fn yeet_no_expr() -> Option { do yeet } + +fn yeet_no_expr_with_semicolon() -> Option { do yeet; } + +fn yeet_with_expr() -> Result { do yeet 1 + 2 } + +fn yeet_with_expr_with_semicolon() -> Result { do yeet 1 + 2; } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr.rs new file mode 100644 index 0000000000000..978a84cf6e5f0 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-yeet_expr.rs @@ -0,0 +1,9 @@ +// compile-flags: --edition 2018 + +pub fn demo() -> Option { + do yeet //~ ERROR `do yeet` expression is experimental +} + +pub fn main() -> Result<(), String> { + do yeet "hello"; //~ ERROR `do yeet` expression is experimental +} diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr new file mode 100644 index 0000000000000..8d1b92370fbe2 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr @@ -0,0 +1,21 @@ +error[E0658]: `do yeet` expression is experimental + --> $DIR/feature-gate-yeet_expr.rs:4:5 + | +LL | do yeet + | ^^^^^^^ + | + = note: see issue #96373 for more information + = help: add `#![feature(yeet_expr)]` to the crate attributes to enable + +error[E0658]: `do yeet` expression is experimental + --> $DIR/feature-gate-yeet_expr.rs:8:5 + | +LL | do yeet "hello"; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #96373 for more information + = help: add `#![feature(yeet_expr)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/try-trait/yeet-for-option.rs b/src/test/ui/try-trait/yeet-for-option.rs new file mode 100644 index 0000000000000..753fbc1dee7d7 --- /dev/null +++ b/src/test/ui/try-trait/yeet-for-option.rs @@ -0,0 +1,11 @@ +// run-pass + +#![feature(yeet_expr)] + +fn always_yeet() -> Option { + do yeet; +} + +fn main() { + assert_eq!(always_yeet(), None); +} diff --git a/src/test/ui/try-trait/yeet-for-result.rs b/src/test/ui/try-trait/yeet-for-result.rs new file mode 100644 index 0000000000000..b7b113797cde4 --- /dev/null +++ b/src/test/ui/try-trait/yeet-for-result.rs @@ -0,0 +1,11 @@ +// run-pass + +#![feature(yeet_expr)] + +fn always_yeet() -> Result { + do yeet "hello"; +} + +fn main() { + assert_eq!(always_yeet(), Err("hello".to_string())); +} From a15c3a36d712c869b91e5b3e75e368d019253523 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 24 Apr 2022 19:08:23 -0700 Subject: [PATCH 2/5] Fix the clippy build --- src/tools/clippy/clippy_utils/src/sugg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 1fc9979f3dd7d..794d2e1026f8c 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -214,6 +214,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Path(..) | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) + | ast::ExprKind::Yeet(..) | ast::ExprKind::Struct(..) | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) From 944ba8c8a7b54d2bc02bc041747bc120304a831c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 24 Apr 2022 19:25:30 -0700 Subject: [PATCH 3/5] Fix the rustfmt build --- src/tools/rustfmt/src/expr.rs | 4 ++++ src/tools/rustfmt/src/utils.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 741f3350801db..e4cc93026f10b 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -225,6 +225,10 @@ pub(crate) fn format_expr( ast::ExprKind::Ret(Some(ref expr)) => { rewrite_unary_prefix(context, "return ", &**expr, shape) } + ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()), + ast::ExprKind::Yeet(Some(ref expr)) => { + rewrite_unary_prefix(context, "do yeet ", &**expr, shape) + } ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape), ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => { rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape) diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 35512e78fa6e2..ed418fb1fece6 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -512,6 +512,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Range(..) | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) + | ast::ExprKind::Yeet(..) | ast::ExprKind::Tup(..) | ast::ExprKind::Type(..) | ast::ExprKind::Yield(None) From 9b5766cd24554427c2f5fb283c1f09718804cfd0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 24 Apr 2022 19:59:23 -0700 Subject: [PATCH 4/5] Bless the UI tests --- .../ui/inference/question-mark-type-infer.stderr | 14 ++++---------- src/test/ui/issues/issue-32709.stderr | 4 +++- src/test/ui/try-trait/bad-interconversion.stderr | 16 ++++++++++++---- src/test/ui/try-trait/option-to-result.stderr | 8 ++++++-- src/test/ui/try-trait/try-on-option.stderr | 4 +++- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/test/ui/inference/question-mark-type-infer.stderr b/src/test/ui/inference/question-mark-type-infer.stderr index e7d5fee18127f..9b822714f828a 100644 --- a/src/test/ui/inference/question-mark-type-infer.stderr +++ b/src/test/ui/inference/question-mark-type-infer.stderr @@ -1,15 +1,9 @@ -error[E0284]: type annotations needed - --> $DIR/question-mark-type-infer.rs:10:21 +error[E0282]: type annotations needed + --> $DIR/question-mark-type-infer.rs:10:30 | LL | l.iter().map(f).collect()? - | ^^^^^^^ cannot infer type - | - = note: cannot satisfy `<_ as Try>::Residual == _` -help: consider specifying the type argument in the method call - | -LL | l.iter().map(f).collect::()? - | +++++ + | ^ cannot infer type error: aborting due to previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index ed5addcbec517..112cb33593223 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -7,7 +7,9 @@ LL | Err(5)?; | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the trait `FromResidual>` is implemented for `Result` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> = note: required because of the requirements on the impl of `FromResidual>` for `Result` error: aborting due to previous error diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 1a4105231dc75..1dbf3ebdf827c 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -31,7 +31,9 @@ LL | | } | |_- this function returns a `Result` | = help: the trait `FromResidual>` is not implemented for `Result` - = help: the trait `FromResidual>` is implemented for `Result` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -44,7 +46,9 @@ LL | | } | |_- this function returns a `Result` | = help: the trait `FromResidual>` is not implemented for `Result` - = help: the trait `FromResidual>` is implemented for `Result` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 @@ -57,7 +61,9 @@ LL | | } | |_- this function returns an `Option` | = help: the trait `FromResidual>` is not implemented for `Option` - = help: the trait `FromResidual` is implemented for `Option` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual> error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:27:33 @@ -70,7 +76,9 @@ LL | | } | |_- this function returns an `Option` | = help: the trait `FromResidual>` is not implemented for `Option` - = help: the trait `FromResidual` is implemented for `Option` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual> error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:32:39 diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr index b0e4de8cb4bf5..ae5c3ad628281 100644 --- a/src/test/ui/try-trait/option-to-result.stderr +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -10,7 +10,9 @@ LL | | } | |_- this function returns a `Result` | = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` - = help: the trait `FromResidual>` is implemented for `Result` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 @@ -24,7 +26,9 @@ LL | | } | |_- this function returns an `Option` | = help: the trait `FromResidual>` is not implemented for `Option` - = help: the trait `FromResidual` is implemented for `Option` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual> error: aborting due to 2 previous errors diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr index 7b2a9a16f900b..ba85a7cada232 100644 --- a/src/test/ui/try-trait/try-on-option.stderr +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -10,7 +10,9 @@ LL | | } | |_- this function returns a `Result` | = help: the trait `FromResidual>` is not implemented for `Result` - = help: the trait `FromResidual>` is implemented for `Result` + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 From b317ec1697fa3d8d095ea99b7180ae6eab9f77af Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 26 Apr 2022 19:49:00 -0700 Subject: [PATCH 5/5] Feature-gate `do yeet` inside `cfg`s too --- compiler/rustc_ast_passes/src/feature_gate.rs | 9 +------- .../feature-gate-yeet_expr-in-cfg.rs | 19 +++++++++++++++++ .../feature-gate-yeet_expr-in-cfg.stderr | 21 +++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs create mode 100644 src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index add9955b18444..0e8af549692fc 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -619,14 +619,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } - ast::ExprKind::Yeet(_) => { - gate_feature_post!( - &self, - yeet_expr, - e.span, - "`do yeet` expression is experimental" - ); - } ast::ExprKind::Block(_, Some(label)) => { gate_feature_post!( &self, @@ -791,6 +783,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(inline_const, "inline-const is experimental"); gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); gate_all!(associated_const_equality, "associated const equality is incomplete"); + gate_all!(yeet_expr, "`do yeet` expression is experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs new file mode 100644 index 0000000000000..a33bd34508c5f --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs @@ -0,0 +1,19 @@ +// compile-flags: --edition 2021 + +pub fn demo() -> Option { + #[cfg(nope)] + { + do yeet //~ ERROR `do yeet` expression is experimental + } + + Some(1) +} + +#[cfg(nope)] +pub fn alternative() -> Result<(), String> { + do yeet "hello"; //~ ERROR `do yeet` expression is experimental +} + +fn main() { + demo(); +} diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr new file mode 100644 index 0000000000000..f90c379bdafe3 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr @@ -0,0 +1,21 @@ +error[E0658]: `do yeet` expression is experimental + --> $DIR/feature-gate-yeet_expr-in-cfg.rs:6:9 + | +LL | do yeet + | ^^^^^^^ + | + = note: see issue #96373 for more information + = help: add `#![feature(yeet_expr)]` to the crate attributes to enable + +error[E0658]: `do yeet` expression is experimental + --> $DIR/feature-gate-yeet_expr-in-cfg.rs:14:5 + | +LL | do yeet "hello"; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #96373 for more information + = help: add `#![feature(yeet_expr)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`.