Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store/lower.rs82
-rw-r--r--crates/hir-ty/src/tests/simple.rs10
-rw-r--r--crates/hir-ty/src/tests/traits.rs8
-rw-r--r--crates/ide-assists/src/handlers/convert_closure_to_fn.rs2
-rw-r--r--crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--crates/ide-db/src/syntax_helpers/node_ext.rs6
-rw-r--r--crates/ide/src/goto_definition.rs6
-rw-r--r--crates/ide/src/highlight_related.rs2
-rw-r--r--crates/ide/src/hover/render.rs2
-rw-r--r--crates/intern/src/symbol/symbols.rs1
-rw-r--r--crates/syntax/src/ast/expr_ext.rs14
11 files changed, 105 insertions, 30 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 4fbf6d9517..701586c258 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -426,7 +426,7 @@ pub struct ExprCollector<'db> {
/// and we need to find the current definition. So we track the number of definitions we saw.
current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
- current_try_block_label: Option<LabelId>,
+ current_try_block: Option<TryBlock>,
label_ribs: Vec<LabelRib>,
unowned_bindings: Vec<BindingId>,
@@ -472,6 +472,13 @@ enum Awaitable {
No(&'static str),
}
+enum TryBlock {
+ // `try { ... }`
+ Homogeneous { label: LabelId },
+ // `try bikeshed Ty { ... }`
+ Heterogeneous { label: LabelId },
+}
+
#[derive(Debug, Default)]
struct BindingList {
map: FxHashMap<(Name, HygieneId), BindingId>,
@@ -532,7 +539,7 @@ impl<'db> ExprCollector<'db> {
lang_items: OnceCell::new(),
store: ExpressionStoreBuilder::default(),
expander,
- current_try_block_label: None,
+ current_try_block: None,
is_lowering_coroutine: false,
label_ribs: Vec::new(),
unowned_bindings: Vec::new(),
@@ -1069,7 +1076,9 @@ impl<'db> ExprCollector<'db> {
self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
}
ast::Expr::BlockExpr(e) => match e.modifier() {
- Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
+ Some(ast::BlockModifier::Try { try_token: _, bikeshed_token: _, result_type }) => {
+ self.desugar_try_block(e, result_type)
+ }
Some(ast::BlockModifier::Unsafe(_)) => {
self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
id,
@@ -1344,7 +1353,7 @@ impl<'db> ExprCollector<'db> {
.map(|it| this.lower_type_ref_disallow_impl_trait(it));
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
- let prev_try_block_label = this.current_try_block_label.take();
+ let prev_try_block = this.current_try_block.take();
let awaitable = if e.async_token().is_some() {
Awaitable::Yes
@@ -1369,7 +1378,7 @@ impl<'db> ExprCollector<'db> {
let capture_by =
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
this.is_lowering_coroutine = prev_is_lowering_coroutine;
- this.current_try_block_label = prev_try_block_label;
+ this.current_try_block = prev_try_block;
this.alloc_expr(
Expr::Closure {
args: args.into(),
@@ -1686,11 +1695,15 @@ impl<'db> ExprCollector<'db> {
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
/// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
/// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
- fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
+ fn desugar_try_block(&mut self, e: BlockExpr, result_type: Option<ast::Type>) -> ExprId {
let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
let label = self.generate_new_name();
let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right());
- let old_label = self.current_try_block_label.replace(label);
+ let try_block_info = match result_type {
+ Some(_) => TryBlock::Heterogeneous { label },
+ None => TryBlock::Homogeneous { label },
+ };
+ let old_try_block = self.current_try_block.replace(try_block_info);
let ptr = AstPtr::new(&e).upcast();
let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
@@ -1720,8 +1733,38 @@ impl<'db> ExprCollector<'db> {
unreachable!("block was lowered to non-block");
};
*tail = Some(next_tail);
- self.current_try_block_label = old_label;
- expr_id
+ self.current_try_block = old_try_block;
+ match result_type {
+ Some(ty) => {
+ // `{ let <name>: <ty> = <expr>; <name> }`
+ let name = self.generate_new_name();
+ let type_ref = self.lower_type_ref_disallow_impl_trait(ty);
+ let binding = self.alloc_binding(
+ name.clone(),
+ BindingAnnotation::Unannotated,
+ HygieneId::ROOT,
+ );
+ let pat = self.alloc_pat_desugared(Pat::Bind { id: binding, subpat: None });
+ self.add_definition_to_binding(binding, pat);
+ let tail_expr =
+ self.alloc_expr_desugared_with_ptr(Expr::Path(Path::from(name)), ptr);
+ self.alloc_expr_desugared_with_ptr(
+ Expr::Block {
+ id: None,
+ statements: Box::new([Statement::Let {
+ pat,
+ type_ref: Some(type_ref),
+ initializer: Some(expr_id),
+ else_branch: None,
+ }]),
+ tail: Some(tail_expr),
+ label: None,
+ },
+ ptr,
+ )
+ }
+ None => expr_id,
+ }
}
/// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:
@@ -1863,6 +1906,8 @@ impl<'db> ExprCollector<'db> {
/// ControlFlow::Continue(val) => val,
/// ControlFlow::Break(residual) =>
/// // If there is an enclosing `try {...}`:
+ /// break 'catch_target Residual::into_try_type(residual),
+ /// // If there is an enclosing `try bikeshed Ty {...}`:
/// break 'catch_target Try::from_residual(residual),
/// // Otherwise:
/// return Try::from_residual(residual),
@@ -1873,7 +1918,6 @@ impl<'db> ExprCollector<'db> {
let try_branch = self.lang_path(lang_items.TryTraitBranch);
let cf_continue = self.lang_path(lang_items.ControlFlowContinue);
let cf_break = self.lang_path(lang_items.ControlFlowBreak);
- let try_from_residual = self.lang_path(lang_items.TryTraitFromResidual);
let operand = self.collect_expr_opt(e.expr());
let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr);
let expr = self
@@ -1910,13 +1954,23 @@ impl<'db> ExprCollector<'db> {
guard: None,
expr: {
let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
- let callee = self
- .alloc_expr(try_from_residual.map_or(Expr::Missing, Expr::Path), syntax_ptr);
+ let convert_fn = match self.current_try_block {
+ Some(TryBlock::Homogeneous { .. }) => {
+ self.lang_path(lang_items.ResidualIntoTryType)
+ }
+ Some(TryBlock::Heterogeneous { .. }) | None => {
+ self.lang_path(lang_items.TryTraitFromResidual)
+ }
+ };
+ let callee =
+ self.alloc_expr(convert_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);
let result =
self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
self.alloc_expr(
- match self.current_try_block_label {
- Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
+ match self.current_try_block {
+ Some(
+ TryBlock::Heterogeneous { label } | TryBlock::Homogeneous { label },
+ ) => Expr::Break { expr: Some(result), label: Some(label) },
None => Expr::Return { expr: Some(result) },
},
syntax_ptr,
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 98503452d3..e91c7d7566 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -2152,10 +2152,11 @@ async fn main() {
let z: core::ops::ControlFlow<(), _> = try { () };
let w = const { 92 };
let t = 'a: { 92 };
+ let u = try bikeshed core::ops::ControlFlow<(), _> { () };
}
"#,
expect![[r#"
- 16..193 '{ ...2 }; }': ()
+ 16..256 '{ ...) }; }': ()
26..27 'x': i32
30..43 'unsafe { 92 }': i32
39..41 '92': i32
@@ -2176,6 +2177,13 @@ async fn main() {
176..177 't': i32
180..190 ''a: { 92 }': i32
186..188 '92': i32
+ 200..201 'u': ControlFlow<(), ()>
+ 204..253 'try bi...{ () }': ControlFlow<(), ()>
+ 204..253 'try bi...{ () }': fn from_output<ControlFlow<(), ()>>(<ControlFlow<(), ()> as Try>::Output) -> ControlFlow<(), ()>
+ 204..253 'try bi...{ () }': ControlFlow<(), ()>
+ 204..253 'try bi...{ () }': ControlFlow<(), ()>
+ 204..253 'try bi...{ () }': ControlFlow<(), ()>
+ 249..251 '()': ()
"#]],
)
}
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 390553c0d7..9c65305712 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -219,14 +219,16 @@ fn test() {
#[test]
fn infer_try_block() {
- // FIXME: We should test more cases, but it currently doesn't work, since
- // our labeled block type inference is broken.
check_types(
r#"
-//- minicore: try, option
+//- minicore: try, option, result, from
fn test() {
let x: Option<_> = try { Some(2)?; };
//^ Option<()>
+ let homogeneous = try { Ok::<(), u32>(())?; "hi" };
+ //^^^^^^^^^^^ Result<&'? str, u32>
+ let heterogeneous = try bikeshed Result<_, u64> { 1 };
+ //^^^^^^^^^^^^^ Result<i32, u64>
}
"#,
);
diff --git a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index ca142332d9..5a223e1130 100644
--- a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -132,7 +132,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
);
}
- if block.try_token().is_none()
+ if block.try_block_modifier().is_none()
&& block.unsafe_token().is_none()
&& block.label().is_none()
&& block.const_token().is_none()
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index f2363c6f7b..124ef509fb 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -859,7 +859,7 @@ impl FunctionBody {
ast::BlockExpr(block_expr) => {
let (constness, block) = match block_expr.modifier() {
Some(ast::BlockModifier::Const(_)) => (true, block_expr),
- Some(ast::BlockModifier::Try(_)) => (false, block_expr),
+ Some(ast::BlockModifier::Try { .. }) => (false, block_expr),
Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr),
_ => continue,
};
diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs
index 94ecf6a02d..e30b21c139 100644
--- a/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -49,7 +49,7 @@ pub fn is_closure_or_blk_with_modif(expr: &ast::Expr) -> bool {
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
- | ast::BlockModifier::Try(_)
+ | ast::BlockModifier::Try { .. }
| ast::BlockModifier::Const(_)
)
)
@@ -148,7 +148,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
- | ast::BlockModifier::Try(_)
+ | ast::BlockModifier::Try { .. }
| ast::BlockModifier::Const(_)
)
)
@@ -291,7 +291,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
match b.modifier() {
Some(
ast::BlockModifier::Async(_)
- | ast::BlockModifier::Try(_)
+ | ast::BlockModifier::Try { .. }
| ast::BlockModifier::Const(_),
) => return cb(expr),
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index c0a7438081..3c3ac9d3bb 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -332,7 +332,7 @@ pub(crate) fn find_fn_or_blocks(
ast::BlockExpr(blk) => {
match blk.modifier() {
Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),
- Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => blk.syntax().clone(),
+ Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),
_ => continue,
}
},
@@ -404,8 +404,8 @@ fn nav_for_exit_points(
let blk_in_file = InFile::new(file_id, blk.into());
Some(expr_to_nav(db, blk_in_file, Some(async_tok)))
},
- Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => {
- let try_tok = blk.try_token()?.text_range();
+ Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => {
+ let try_tok = blk.try_block_modifier()?.try_token()?.text_range();
let blk_in_file = InFile::new(file_id, blk.into());
Some(expr_to_nav(db, blk_in_file, Some(try_tok)))
},
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index fce033382b..c8e01e21ec 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -473,7 +473,7 @@ pub(crate) fn highlight_exit_points(
},
ast::BlockExpr(blk) => match blk.modifier() {
Some(ast::BlockModifier::Async(t)) => hl_exit_points(sema, Some(t), blk.into()),
- Some(ast::BlockModifier::Try(t)) if token.kind() != T![return] => {
+ Some(ast::BlockModifier::Try { try_token: t, .. }) if token.kind() != T![return] => {
hl_exit_points(sema, Some(t), blk.into())
},
_ => continue,
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 15ea92d1c6..cf5f137cdd 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -74,7 +74,7 @@ pub(super) fn try_expr(
ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
ast::Item(__) => return None,
ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
- ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
+ ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try { .. } | ast::BlockModifier::Const(_))) {
sema.type_of_expr(&block_expr.into())?.original
} else {
continue;
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 2be4e41f4f..2eccc16c6a 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -285,6 +285,7 @@ define_symbols! {
Into,
into_future,
into_iter,
+ into_try_type,
IntoFuture,
IntoIter,
IntoIterator,
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index db66995381..b44150f868 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -375,7 +375,11 @@ impl ast::Literal {
pub enum BlockModifier {
Async(SyntaxToken),
Unsafe(SyntaxToken),
- Try(SyntaxToken),
+ Try {
+ try_token: SyntaxToken,
+ bikeshed_token: Option<SyntaxToken>,
+ result_type: Option<ast::Type>,
+ },
Const(SyntaxToken),
AsyncGen(SyntaxToken),
Gen(SyntaxToken),
@@ -394,7 +398,13 @@ impl ast::BlockExpr {
})
.or_else(|| self.async_token().map(BlockModifier::Async))
.or_else(|| self.unsafe_token().map(BlockModifier::Unsafe))
- .or_else(|| self.try_token().map(BlockModifier::Try))
+ .or_else(|| {
+ let modifier = self.try_block_modifier()?;
+ let try_token = modifier.try_token()?;
+ let bikeshed_token = modifier.bikeshed_token();
+ let result_type = modifier.ty();
+ Some(BlockModifier::Try { try_token, bikeshed_token, result_type })
+ })
.or_else(|| self.const_token().map(BlockModifier::Const))
.or_else(|| self.label().map(BlockModifier::Label))
}