about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2022-03-25 23:43:54 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2022-04-30 17:40:27 -0700
commite094ee5f102dfea8e99137d3818510cd178e8817 (patch)
tree1355dfd0fa0c410199d17a4ea5f8889703a661db /compiler
parent2c858a7c3f189eb11ad89d9bf9f2e87cac9d2b76 (diff)
downloadrust-e094ee5f102dfea8e99137d3818510cd178e8817.tar.gz
rust-e094ee5f102dfea8e99137d3818510cd178e8817.zip
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.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/util/parser.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs39
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs14
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs21
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs4
13 files changed, 105 insertions, 3 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index cdcd221e811..1a18d1964c9 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<P<Expr>>),
 
+    /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
+    /// with an optional value to be returned.
+    Yeet(Option<P<Expr>>),
+
     /// 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 d7b1bc6a7f5..4bf3d483f73 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<T: MutVisitor>(
         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 742a7d1d2df..74b7fe9e249 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 e08ba73e0ae..fa26716083f 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 37ae41fabf9..5c3e3be2116 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 <expr>` 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 125acdcc27d..5a95e5b084a 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 649af48e48a..add9955b184 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 9de4cbbee13..9f44f1b6cc2 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 f3d4c8ab438..9159d60463c 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 9318ebb40b0..b3c22d4ec21 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 13e9a5e660f..6114e7aaa7b 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<Expr>> {
+        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 3889639b50f..447b73fa3c3 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 e3ce8105a8b..c1299c94c4b 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,
     }