diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f2061f3088a25..8e3e694a5a717 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1806,8 +1806,9 @@ pub enum ExprKind { /// A use expression (`x.use`). Span is of use keyword. Use(Box, Span), - /// A try block (`try { ... }`). - TryBlock(Box), + /// A try block (`try { ... }`), if the type is `None`, or + /// A try block (`try bikeshed Ty { ... }`) if the type is `Some`. + TryBlock(Box, Option>), /// An assignment (`a = foo()`). /// The `Span` argument is the span of the `=` token. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index dde773fd147da..7a0424d395750 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1048,8 +1048,8 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, kind), ExprKind::Try(subexpression) => visit_visitable!($($mut)? vis, subexpression), - ExprKind::TryBlock(body) => - visit_visitable!($($mut)? vis, body), + ExprKind::TryBlock(body, optional_type) => + visit_visitable!($($mut)? vis, body, optional_type), ExprKind::Lit(token) => visit_visitable!($($mut)? vis, token), ExprKind::IncludedBytes(bytes) => diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 524f8b054cb49..7230e1c424740 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,4 @@ +use std::mem; use std::ops::ControlFlow; use std::sync::Arc; @@ -27,7 +28,9 @@ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; -use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; +use crate::{ + AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope, fluent_generated, +}; struct WillCreateDefIdsVisitor {} @@ -199,7 +202,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }) } - ExprKind::TryBlock(body) => self.lower_expr_try_block(body), + ExprKind::TryBlock(body, opt_ty) => { + self.lower_expr_try_block(body, opt_ty.as_deref()) + } ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), @@ -562,9 +567,14 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `try { ; }` into `{ ; ::std::ops::Try::from_output() }`, /// `try { ; }` into `{ ; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. - fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { + fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> { let body_hir_id = self.lower_node_id(body.id); - self.with_catch_scope(body_hir_id, |this| { + let new_scope = if opt_ty.is_some() { + TryBlockScope::Heterogeneous(body_hir_id) + } else { + TryBlockScope::Homogeneous(body_hir_id) + }; + let whole_block = self.with_try_block_scope(new_scope, |this| { let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block @@ -598,8 +608,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ok_wrapped_span, )); - hir::ExprKind::Block(this.arena.alloc(block), None) - }) + this.arena.alloc(block) + }); + + if let Some(ty) = opt_ty { + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); + let block_expr = self.arena.alloc(self.expr_block(whole_block)); + hir::ExprKind::Type(block_expr, ty) + } else { + hir::ExprKind::Block(whole_block, None) + } } fn wrap_in_try_constructor( @@ -1617,10 +1635,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn with_catch_scope(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { - let old_scope = self.catch_scope.replace(catch_id); + fn with_try_block_scope( + &mut self, + scope: TryBlockScope, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let old_scope = mem::replace(&mut self.try_block_scope, scope); let result = f(self); - self.catch_scope = old_scope; + self.try_block_scope = old_scope; result } @@ -1978,18 +2000,25 @@ impl<'hir> LoweringContext<'_, 'hir> { let residual_ident = Ident::with_dummy_span(sym::residual); let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident); let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid); + + let (constructor_item, target_id) = match self.try_block_scope { + TryBlockScope::Function => { + (hir::LangItem::TryTraitFromResidual, Err(hir::LoopIdError::OutsideLoopScope)) + } + TryBlockScope::Homogeneous(block_id) => { + (hir::LangItem::ResidualIntoTryType, Ok(block_id)) + } + TryBlockScope::Heterogeneous(block_id) => { + (hir::LangItem::TryTraitFromResidual, Ok(block_id)) + } + }; let from_residual_expr = self.wrap_in_try_constructor( - if self.catch_scope.is_some() { - hir::LangItem::ResidualIntoTryType - } else { - hir::LangItem::TryTraitFromResidual - }, + constructor_item, try_span, self.arena.alloc(residual_expr), unstable_span, ); - let ret_expr = if let Some(catch_id) = self.catch_scope { - let target_id = Ok(catch_id); + let ret_expr = if target_id.is_ok() { self.arena.alloc(self.expr( try_span, hir::ExprKind::Break( @@ -2044,11 +2073,14 @@ impl<'hir> LoweringContext<'_, 'hir> { yeeted_span, ); - if let Some(catch_id) = self.catch_scope { - let target_id = Ok(catch_id); - hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) - } else { - self.checked_return(Some(from_yeet_expr)) + match self.try_block_scope { + TryBlockScope::Homogeneous(block_id) | TryBlockScope::Heterogeneous(block_id) => { + hir::ExprKind::Break( + hir::Destination { label: None, target_id: Ok(block_id) }, + Some(from_yeet_expr), + ) + } + TryBlockScope::Function => self.checked_return(Some(from_yeet_expr)), } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1f36454ec861a..a1d8c32473c7d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -35,6 +35,7 @@ #![feature(if_let_guard)] // tidy-alphabetical-end +use std::mem; use std::sync::Arc; use rustc_ast::node_id::NodeMap; @@ -117,7 +118,7 @@ struct LoweringContext<'a, 'hir> { /// outside of an `async fn`. current_item: Option, - catch_scope: Option, + try_block_scope: TryBlockScope, loop_scope: Option, is_in_loop_condition: bool, is_in_dyn_type: bool, @@ -173,7 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_map: Default::default(), // Lowering state. - catch_scope: None, + try_block_scope: TryBlockScope::Function, loop_scope: None, is_in_loop_condition: false, is_in_dyn_type: false, @@ -416,6 +417,14 @@ enum AstOwner<'a> { ForeignItem(&'a ast::ForeignItem), } +#[derive(Copy, Clone, Debug)] +enum TryBlockScope { + /// There isn't a `try` block, so the scope is the function or closure or ... + Function, + Homogeneous(HirId), + Heterogeneous(HirId), +} + fn index_crate<'a>( node_id_to_def_id: &NodeMap, krate: &'a Crate, @@ -936,10 +945,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let old_contract = self.contract_ensures.take(); - let catch_scope = self.catch_scope.take(); + let try_block_scope = mem::replace(&mut self.try_block_scope, TryBlockScope::Function); let loop_scope = self.loop_scope.take(); let ret = f(self); - self.catch_scope = catch_scope; + self.try_block_scope = try_block_scope; self.loop_scope = loop_scope; self.contract_ensures = old_contract; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2d87d8c84d7c9..9b746508b33e5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -339,9 +339,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { - ast::ExprKind::TryBlock(_) => { + ast::ExprKind::TryBlock(_, None) => { gate!(&self, try_blocks, e.span, "`try` expression is experimental"); } + ast::ExprKind::TryBlock(_, Some(_)) => { + gate!( + &self, + try_blocks_heterogeneous, + e.span, + "`try bikeshed` expression is experimental" + ); + } ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float | token::LitKind::Integer, suffix, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index bdf73ac32f0d8..7dce7f6d41954 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -818,10 +818,15 @@ impl<'a> State<'a> { ); self.word("?") } - ast::ExprKind::TryBlock(blk) => { + ast::ExprKind::TryBlock(blk, opt_ty) => { let cb = self.cbox(0); let ib = self.ibox(0); self.word_nbsp("try"); + if let Some(ty) = opt_ty { + self.word_nbsp("bikeshed"); + self.print_type(ty); + self.space(); + } self.print_block_with_attrs(blk, attrs, cb, ib) } ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => { diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 31855cbd4e6cc..21b20e2bb974f 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -315,7 +315,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Path(_, _) | ExprKind::Ret(_) | ExprKind::Try(_) - | ExprKind::TryBlock(_) + | ExprKind::TryBlock(_, _) | ExprKind::Type(_, _) | ExprKind::Underscore | ExprKind::While(_, _, _) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 26612fda5a7fb..48f5c6707c753 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -665,6 +665,8 @@ declare_features! ( (unstable, trivial_bounds, "1.28.0", Some(48214)), /// Allows using `try {...}` expressions. (unstable, try_blocks, "1.29.0", Some(31436)), + /// Allows using `try bikeshed TargetType {...}` expressions. + (unstable, try_blocks_heterogeneous, "CURRENT_RUSTC_VERSION", Some(149488)), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (unstable, type_alias_impl_trait, "1.38.0", Some(63063)), /// Allows creation of instances of a struct by moving fields that have diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9e7d4bca37d05..fa5e61d24d911 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3544,15 +3544,20 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound) } - /// Parses a `try {...}` expression (`try` token already eaten). + /// Parses a `try {...}` or `try bikeshed Ty {...}` expression (`try` token already eaten). fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box> { + let annotation = + if self.eat_keyword(exp!(Bikeshed)) { Some(self.parse_ty()?) } else { None }; + let (attrs, body) = self.parse_inner_attrs_and_block(None)?; if self.eat_keyword(exp!(Catch)) { Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span })) } else { let span = span_lo.to(body.span); - self.psess.gated_spans.gate(sym::try_blocks, span); - Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body), attrs)) + let gate_sym = + if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous }; + self.psess.gated_spans.gate(gate_sym, span); + Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs)) } } @@ -3569,7 +3574,11 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) - && self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block()) + && self.look_ahead(1, |t| { + *t == token::OpenBrace + || t.is_metavar_block() + || t.kind == TokenKind::Ident(sym::bikeshed, IdentIsRaw::No) + }) && self.token_uninterpolated_span().at_least_rust_2018() } @@ -4264,7 +4273,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Closure(_) | ExprKind::Block(_, _) | ExprKind::Gen(_, _, _, _) - | ExprKind::TryBlock(_) + | ExprKind::TryBlock(_, _) | ExprKind::Underscore | ExprKind::Path(_, _) | ExprKind::Break(_, _) diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 08c5b06575cd4..e5dda7cf91041 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -129,6 +129,7 @@ pub enum TokenType { // Keyword-like symbols. // tidy-alphabetical-start SymAttSyntax, + SymBikeshed, SymClobberAbi, SymInlateout, SymInout, @@ -556,6 +557,7 @@ macro_rules! exp { (Yield) => { exp!(@kw, Yield, KwYield) }; (AttSyntax) => { exp!(@sym, att_syntax, SymAttSyntax) }; + (Bikeshed) => { exp!(@sym, bikeshed, SymBikeshed) }; (ClobberAbi) => { exp!(@sym, clobber_abi, SymClobberAbi) }; (Inlateout) => { exp!(@sym, inlateout, SymInlateout) }; (Inout) => { exp!(@sym, inout, SymInout) }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index eca4259efa7d1..2c3cdd9fe61c4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -571,6 +571,7 @@ symbols! { begin_panic, bench, bevy_ecs, + bikeshed, bikeshed_guaranteed_no_drop, bin, binaryheap_iter, @@ -2277,6 +2278,7 @@ symbols! { truncf64, truncf128, try_blocks, + try_blocks_heterogeneous, try_capture, try_from, try_from_fn, diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 0d809c17989de..af5e3ccb674a4 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -545,7 +545,7 @@ fn ident_difference_expr_with_base_location( | (Field(_, _), Field(_, _)) | (AssignOp(_, _, _), AssignOp(_, _, _)) | (Assign(_, _, _), Assign(_, _, _)) - | (TryBlock(_), TryBlock(_)) + | (TryBlock(_, _), TryBlock(_, _)) | (Await(_, _), Await(_, _)) | (Gen(_, _, _, _), Gen(_, _, _, _)) | (Block(_, _), Block(_, _)) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 04a64e0fe9485..8502419ef8c55 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -199,7 +199,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { ) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), - (TryBlock(l), TryBlock(r)) => eq_block(l, r), + (TryBlock(lb, lt), TryBlock(rb, rt)) => eq_block(lb, rb) && both(lt.as_deref(), rt.as_deref(), eq_ty), (Yield(l), Yield(r)) => eq_expr_opt(l.expr().map(Box::as_ref), r.expr().map(Box::as_ref)) && l.same_kind(r), (Ret(l), Ret(r)) => eq_expr_opt(l.as_deref(), r.as_deref()), (Break(ll, le), Break(rl, re)) => { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 975f9be44e4d3..de96f004dc873 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -363,12 +363,13 @@ pub(crate) fn format_expr( // Style Guide RFC for InlineAsm variant pending // https://github.com/rust-dev-tools/fmt-rfcs/issues/152 ast::ExprKind::InlineAsm(..) => Ok(context.snippet(expr.span).to_owned()), - ast::ExprKind::TryBlock(ref block) => { + ast::ExprKind::TryBlock(ref block, None) => { if let rw @ Ok(_) = rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape) { rw } else { + // FIXME: 9 sounds like `"do catch ".len()`, so may predate the rename // 9 = `try ` let budget = shape.width.saturating_sub(9); Ok(format!( @@ -384,6 +385,8 @@ pub(crate) fn format_expr( )) } } + // FIXME: heterogeneous try blocks, which include a type so are harder to format + ast::ExprKind::TryBlock(_, Some(_)) => Err(RewriteError::Unknown), ast::ExprKind::Gen(capture_by, ref block, ref kind, _) => { let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) { "move " diff --git a/tests/pretty/try-blocks.rs b/tests/pretty/try-blocks.rs new file mode 100644 index 0000000000000..fc0af21147692 --- /dev/null +++ b/tests/pretty/try-blocks.rs @@ -0,0 +1,6 @@ +//@ pp-exact +//@ edition: 2024 + +#![feature(try_blocks, try_blocks_heterogeneous)] + +fn main() { try { Some(1)? }; try bikeshed Result { 3 }; } diff --git a/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.rs b/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.rs new file mode 100644 index 0000000000000..9f0073eac9adc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.rs @@ -0,0 +1,9 @@ +//@ edition: 2018 + +pub fn main() { + let try_result = try bikeshed Option<_> { //~ ERROR `try bikeshed` expression is experimental + let x = 5; + x + }; + assert_eq!(try_result, Some(5)); +} diff --git a/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.stderr b/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.stderr new file mode 100644 index 0000000000000..0d31dc507fdde --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.stderr @@ -0,0 +1,17 @@ +error[E0658]: `try bikeshed` expression is experimental + --> $DIR/feature-gate-try_blocks_heterogeneous.rs:4:22 + | +LL | let try_result = try bikeshed Option<_> { + | ______________________^ +LL | | let x = 5; +LL | | x +LL | | }; + | |_____^ + | + = note: see issue #149488 for more information + = help: add `#![feature(try_blocks_heterogeneous)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.rs b/tests/ui/try-block/try-block-bad-type-heterogeneous.rs new file mode 100644 index 0000000000000..b099651bf8a9e --- /dev/null +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.rs @@ -0,0 +1,21 @@ +//@ edition: 2018 + +#![feature(try_blocks_heterogeneous)] + +pub fn main() { + let res = try bikeshed Result { + Err("")?; //~ ERROR `?` couldn't convert the error + 5 + }; + + let res = try bikeshed Result { + "" //~ ERROR type mismatch + }; + + let res = try bikeshed Result { }; //~ ERROR type mismatch + + let res = try bikeshed () { }; + //~^ ERROR a `try` block must return `Result` or `Option` + + let res = try bikeshed i32 { 5 }; //~ ERROR a `try` block must return `Result` or `Option` +} diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr new file mode 100644 index 0000000000000..7c7cedd392e64 --- /dev/null +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr @@ -0,0 +1,46 @@ +error[E0277]: `?` couldn't convert the error to `TryFromSliceError` + --> $DIR/try-block-bad-type-heterogeneous.rs:7:16 + | +LL | Err("")?; + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | | + | this can't be annotated with `?` because it has type `Result<_, &str>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the trait `From<&str>` is not implemented for `TryFromSliceError` + but trait `From` is implemented for it + --> $SRC_DIR/core/src/array/mod.rs:LL:COL + = help: for that trait implementation, expected `Infallible`, found `&str` + +error[E0271]: type mismatch resolving ` as Try>::Output == &str` + --> $DIR/try-block-bad-type-heterogeneous.rs:12:9 + | +LL | "" + | ^^ expected `&str`, found `i32` + +error[E0271]: type mismatch resolving ` as Try>::Output == ()` + --> $DIR/try-block-bad-type-heterogeneous.rs:15:47 + | +LL | let res = try bikeshed Result { }; + | ^ expected `()`, found `i32` + +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type-heterogeneous.rs:17:33 + | +LL | let res = try bikeshed () { }; + | ^ could not wrap the final value of the block as `()` doesn't implement `Try` + | + = help: the trait `Try` is not implemented for `()` + +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type-heterogeneous.rs:20:34 + | +LL | let res = try bikeshed i32 { 5 }; + | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` + | + = help: the trait `Try` is not implemented for `i32` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/try-block/try-block-heterogeneous.rs b/tests/ui/try-block/try-block-heterogeneous.rs new file mode 100644 index 0000000000000..0b17b7c8655dc --- /dev/null +++ b/tests/ui/try-block/try-block-heterogeneous.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ edition: 2018 + +#![feature(try_blocks_heterogeneous)] + +fn foo() -> Result<(), u16> { Ok(()) } + +fn bar() -> Result<(), u32> { Ok(()) } + +fn whatever() -> Result<(), String> { + try bikeshed _ {} +} + +fn main() { + try bikeshed Result<(), u64> { + foo()?; + bar()?; + }; +} diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 9e6797c727f03..1fc9e6a726936 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -28,6 +28,7 @@ #![feature(trace_macros)] #![feature(trait_alias)] #![feature(try_blocks)] +#![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[macro_use] @@ -222,7 +223,12 @@ mod expressions { } /// ExprKind::TryBlock - fn expr_try_block() { try {} try { return; } } + fn expr_try_block() { + try {} + try { return; } + try bikeshed Option<_> {} + try bikeshed Option { None? } + } /// ExprKind::Assign fn expr_assign() { let expr; expr = true; } diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr index eb5c186bd2c05..f6800fc9c1e6f 100644 --- a/tests/ui/unpretty/exhaustive.hir.stderr +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -1,17 +1,17 @@ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:210:9 + --> $DIR/exhaustive.rs:211:9 | LL | static || value; | ^^^^^^^^^ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:211:9 + --> $DIR/exhaustive.rs:212:9 | LL | static move || value; | ^^^^^^^^^^^^^^ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/exhaustive.rs:240:13 + --> $DIR/exhaustive.rs:241:13 | LL | fn expr_await() { | --------------- this is not `async` @@ -20,19 +20,19 @@ LL | fut.await; | ^^^^^ only allowed inside `async` functions and blocks error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/exhaustive.rs:289:9 + --> $DIR/exhaustive.rs:292:9 | LL | _; | ^ `_` not allowed here error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:299:9 + --> $DIR/exhaustive.rs:302:9 | LL | x::(); | ^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:300:9 + --> $DIR/exhaustive.rs:303:9 | LL | x::(T, T) -> T; | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses @@ -44,31 +44,31 @@ LL + x:: -> T; | error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:301:9 + --> $DIR/exhaustive.rs:304:9 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:301:26 + --> $DIR/exhaustive.rs:304:26 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:304:9 + --> $DIR/exhaustive.rs:307:9 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:304:19 + --> $DIR/exhaustive.rs:307:19 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^^^ only `Fn` traits may use parentheses error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks - --> $DIR/exhaustive.rs:391:9 + --> $DIR/exhaustive.rs:394:9 | LL | yield; | ^^^^^ @@ -79,7 +79,7 @@ LL | #[coroutine] fn expr_yield() { | ++++++++++++ error[E0703]: invalid ABI: found `C++` - --> $DIR/exhaustive.rs:471:23 + --> $DIR/exhaustive.rs:474:23 | LL | unsafe extern "C++" {} | ^^^^^ invalid ABI @@ -87,7 +87,7 @@ LL | unsafe extern "C++" {} = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: `..` patterns are not allowed here - --> $DIR/exhaustive.rs:678:13 + --> $DIR/exhaustive.rs:681:13 | LL | let ..; | ^^ @@ -95,13 +95,13 @@ LL | let ..; = note: only allowed in tuple, tuple struct, and slice patterns error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:793:16 + --> $DIR/exhaustive.rs:796:16 | LL | let _: T() -> !; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:807:16 + --> $DIR/exhaustive.rs:810:16 | LL | let _: impl Send; | ^^^^^^^^^ @@ -112,7 +112,7 @@ LL | let _: impl Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:808:16 + --> $DIR/exhaustive.rs:811:16 | LL | let _: impl Send + 'static; | ^^^^^^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | let _: impl Send + 'static; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:809:16 + --> $DIR/exhaustive.rs:812:16 | LL | let _: impl 'static + Send; | ^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | let _: impl 'static + Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:810:16 + --> $DIR/exhaustive.rs:813:16 | LL | let _: impl ?Sized; | ^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | let _: impl ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:811:16 + --> $DIR/exhaustive.rs:814:16 | LL | let _: impl [const] Clone; | ^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL | let _: impl [const] Clone; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:812:16 + --> $DIR/exhaustive.rs:815:16 | LL | let _: impl for<'a> Send; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 873febbbd84d7..9396e937d8433 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -27,6 +27,7 @@ #![feature(trace_macros)] #![feature(trait_alias)] #![feature(try_blocks)] +#![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[attr = MacroUse {arguments: UseAll}] @@ -253,7 +254,19 @@ mod expressions { } /// ExprKind::TryBlock - fn expr_try_block() { { from_output(()) } { return; from_output(()) } } + fn expr_try_block() { + { from_output(()) } + { return; from_output(()) } + type_ascribe!({ from_output(()) }, Option<_>); + type_ascribe!({ + from_output(match branch(None) { + Break { 0: residual } => #[allow(unreachable_code)] + break from_residual(residual), + Continue { 0: val } => #[allow(unreachable_code)] + val, + }) + }, Option) + } /// ExprKind::Assign fn expr_assign() { let expr; expr = true; } diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index 0983a0a7e4372..0bbc87845695f 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -27,6 +27,7 @@ #![feature(trace_macros)] #![feature(trait_alias)] #![feature(try_blocks)] +#![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] #![allow(incomplete_features)] @@ -244,6 +245,8 @@ mod expressions { fn expr_try_block() { try {} try { return; } + try bikeshed Option<_> { } + try bikeshed Option { None? } } /// ExprKind::Assign