mirror of https://github.com/rust-lang/rust.git
Auto merge of #96376 - scottmcm:do-yeet, r=oli-obk
Add `do yeet` expressions to allow experimentation in nightly Two main goals for this: - Ensure that trait restructuring in https://github.com/rust-lang/rust/issues/84277#issuecomment-1066120333 doesn't accidentally close us off from the possibility of doing this in future, as sketched in https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#possibilities-for-yeet - Experiment with the *existence* of syntax for this, to be able to weight the syntax-vs-library tradeoffs better than we can right now. Notably the syntax (with `do`) and name in this PR are not intended as candidates for stabilization, but they make a good v0 PR for adding this with minimal impact to compiler maintenance or priming one possible name choice over another. r? `@oli-obk` The lang `second` for doing this: https://github.com/rust-lang/lang-team/issues/160#issuecomment-1107896716 Tracking issues - Lang, https://github.com/rust-lang/rust/issues/96373 - Libs-api, https://github.com/rust-lang/rust/issues/96374
This commit is contained in:
commit
508e0584e3
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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.
|
||||
// =========================================================================
|
||||
|
|
|
@ -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()),
|
||||
};
|
||||
|
|
|
@ -783,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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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`",
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -330,6 +330,22 @@ pub trait FromResidual<R = <Self as Try>::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<T, Y>(yeeted: Y) -> T
|
||||
where
|
||||
T: FromResidual<Yeet<Y>>,
|
||||
{
|
||||
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<T> FromResidual for NeverShortCircuit<T> {
|
|||
impl<T> Residual<T> for NeverShortCircuitResidual {
|
||||
type TryType = NeverShortCircuit<T>;
|
||||
}
|
||||
|
||||
/// Implement `FromResidual<Yeet<T>>` 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<T>(pub T);
|
||||
|
|
|
@ -2287,6 +2287,14 @@ impl<T> const ops::FromResidual for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
|
||||
impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
|
||||
#[inline]
|
||||
fn from_residual(ops::Yeet(()): ops::Yeet<()>) -> Self {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
|
||||
impl<T> ops::Residual<T> for Option<convert::Infallible> {
|
||||
type TryType = Option<T>;
|
||||
|
|
|
@ -2107,6 +2107,14 @@ impl<T, E, F: ~const From<E>> const ops::FromResidual<Result<convert::Infallible
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
|
||||
impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
|
||||
#[inline]
|
||||
fn from_residual(ops::Yeet(e): ops::Yeet<E>) -> Self {
|
||||
Err(From::from(e))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
|
||||
impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
|
||||
type TryType = Result<T, E>;
|
||||
|
|
|
@ -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<String, i32> {
|
||||
do yeet 4;
|
||||
}
|
||||
assert_eq!(foo(), Err(4));
|
||||
|
||||
fn bar() -> Option<String> {
|
||||
do yeet;
|
||||
}
|
||||
assert_eq!(bar(), None);
|
||||
```
|
|
@ -0,0 +1,12 @@
|
|||
// pp-exact
|
||||
#![feature(yeet_expr)]
|
||||
|
||||
fn yeet_no_expr() -> Option<String> { do yeet }
|
||||
|
||||
fn yeet_no_expr_with_semicolon() -> Option<String> { do yeet; }
|
||||
|
||||
fn yeet_with_expr() -> Result<String, i32> { do yeet 1 + 2 }
|
||||
|
||||
fn yeet_with_expr_with_semicolon() -> Result<String, i32> { do yeet 1 + 2; }
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,19 @@
|
|||
// compile-flags: --edition 2021
|
||||
|
||||
pub fn demo() -> Option<i32> {
|
||||
#[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();
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -0,0 +1,9 @@
|
|||
// compile-flags: --edition 2018
|
||||
|
||||
pub fn demo() -> Option<i32> {
|
||||
do yeet //~ ERROR `do yeet` expression is experimental
|
||||
}
|
||||
|
||||
pub fn main() -> Result<(), String> {
|
||||
do yeet "hello"; //~ ERROR `do yeet` expression is experimental
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -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::<B>()?
|
||||
| +++++
|
||||
| ^ 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`.
|
||||
|
|
|
@ -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<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Result<T, F> as FromResidual<Result<Infallible, E>>>
|
||||
<Result<T, F> as FromResidual<Yeet<E>>>
|
||||
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
|
@ -31,7 +31,9 @@ LL | | }
|
|||
| |_- this function returns a `Result`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Result<T, F> as FromResidual<Result<Infallible, E>>>
|
||||
<Result<T, F> as FromResidual<Yeet<E>>>
|
||||
|
||||
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<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Result<T, F> as FromResidual<Result<Infallible, E>>>
|
||||
<Result<T, F> as FromResidual<Yeet<E>>>
|
||||
|
||||
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<Result<Infallible, &str>>` is not implemented for `Option<u16>`
|
||||
= help: the trait `FromResidual` is implemented for `Option<T>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Option<T> as FromResidual<Yeet<()>>>
|
||||
<Option<T> 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<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
|
||||
= help: the trait `FromResidual` is implemented for `Option<T>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Option<T> as FromResidual<Yeet<()>>>
|
||||
<Option<T> 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
|
||||
|
|
|
@ -10,7 +10,9 @@ LL | | }
|
|||
| |_- this function returns a `Result`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Result<T, F> as FromResidual<Result<Infallible, E>>>
|
||||
<Result<T, F> as FromResidual<Yeet<E>>>
|
||||
|
||||
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<Result<Infallible, i32>>` is not implemented for `Option<i32>`
|
||||
= help: the trait `FromResidual` is implemented for `Option<T>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Option<T> as FromResidual<Yeet<()>>>
|
||||
<Option<T> as FromResidual>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ LL | | }
|
|||
| |_- this function returns a `Result`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
= help: the following other types implement trait `FromResidual<R>`:
|
||||
<Result<T, F> as FromResidual<Result<Infallible, E>>>
|
||||
<Result<T, F> as FromResidual<Yeet<E>>>
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(yeet_expr)]
|
||||
|
||||
fn always_yeet() -> Option<String> {
|
||||
do yeet;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(always_yeet(), None);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(yeet_expr)]
|
||||
|
||||
fn always_yeet() -> Result<i32, String> {
|
||||
do yeet "hello";
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(always_yeet(), Err("hello".to_string()));
|
||||
}
|
|
@ -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(..)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue