Skip to content

Commit 3321799

Browse files
committed
Auto merge of rust-lang#14368 - HKalbasi:mir, r=HKalbasi
MIR episode 3 This PR adds lowering for try operator and overloaded dereference, and adds evaluating support for function pointers and trait objects. It also adds a flag to `analysis-stats` to show percentage of functions that it fails to emit mir for them, which is currently `20%` (which is somehow lying, as most of the supported `80%` are tests). The most offenders are closure (1975 items) and overloaded index (415 items). I will try to add overloaded index before monday to have it in this PR, and tackle the closure in the next episode.
2 parents 6d75119 + 8a3ad7c commit 3321799

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+3098
-935
lines changed

crates/hir-def/src/body.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ impl Body {
391391
}
392392
};
393393
let expander = Expander::new(db, file_id, module);
394-
let (mut body, source_map) = Body::new(db, expander, params, body);
394+
let (mut body, source_map) = Body::new(db, expander, params, body, module.krate);
395395
body.shrink_to_fit();
396396

397397
(Arc::new(body), Arc::new(source_map))
@@ -420,8 +420,9 @@ impl Body {
420420
expander: Expander,
421421
params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
422422
body: Option<ast::Expr>,
423+
krate: CrateId,
423424
) -> (Body, BodySourceMap) {
424-
lower::lower(db, expander, params, body)
425+
lower::lower(db, expander, params, body, krate)
425426
}
426427

427428
fn shrink_to_fit(&mut self) {

crates/hir-def/src/body/lower.rs

Lines changed: 156 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use std::{mem, sync::Arc};
55

6+
use base_db::CrateId;
67
use either::Either;
78
use hir_expand::{
89
ast_id_map::AstIdMap,
@@ -18,7 +19,7 @@ use rustc_hash::FxHashMap;
1819
use smallvec::SmallVec;
1920
use syntax::{
2021
ast::{
21-
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
22+
self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasLoopBody, HasName, LiteralKind,
2223
SlicePatComponents,
2324
},
2425
AstNode, AstPtr, SyntaxNodePtr,
@@ -36,6 +37,7 @@ use crate::{
3637
RecordFieldPat, RecordLitField, Statement,
3738
},
3839
item_scope::BuiltinShadowMode,
40+
lang_item::LangItem,
3941
path::{GenericArgs, Path},
4042
type_ref::{Mutability, Rawness, TypeRef},
4143
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
@@ -80,9 +82,11 @@ pub(super) fn lower(
8082
expander: Expander,
8183
params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
8284
body: Option<ast::Expr>,
85+
krate: CrateId,
8386
) -> (Body, BodySourceMap) {
8487
ExprCollector {
8588
db,
89+
krate,
8690
source_map: BodySourceMap::default(),
8791
ast_id_map: db.ast_id_map(expander.current_file_id),
8892
body: Body {
@@ -96,6 +100,7 @@ pub(super) fn lower(
96100
_c: Count::new(),
97101
},
98102
expander,
103+
current_try_block: None,
99104
is_lowering_assignee_expr: false,
100105
is_lowering_generator: false,
101106
}
@@ -107,7 +112,9 @@ struct ExprCollector<'a> {
107112
expander: Expander,
108113
ast_id_map: Arc<AstIdMap>,
109114
body: Body,
115+
krate: CrateId,
110116
source_map: BodySourceMap,
117+
current_try_block: Option<LabelId>,
111118
is_lowering_assignee_expr: bool,
112119
is_lowering_generator: bool,
113120
}
@@ -176,8 +183,7 @@ impl ExprCollector<'_> {
176183
self.source_map.expr_map.insert(src, id);
177184
id
178185
}
179-
// desugared exprs don't have ptr, that's wrong and should be fixed
180-
// somehow.
186+
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow.
181187
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
182188
self.body.exprs.alloc(expr)
183189
}
@@ -199,6 +205,10 @@ impl ExprCollector<'_> {
199205
self.source_map.pat_map.insert(src, id);
200206
id
201207
}
208+
// FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
209+
fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
210+
self.body.pats.alloc(pat)
211+
}
202212
fn missing_pat(&mut self) -> PatId {
203213
self.body.pats.alloc(Pat::Missing)
204214
}
@@ -214,6 +224,10 @@ impl ExprCollector<'_> {
214224
self.source_map.label_map.insert(src, id);
215225
id
216226
}
227+
// FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
228+
fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
229+
self.body.labels.alloc(label)
230+
}
217231
fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
218232
let id = self.body.labels.alloc(label);
219233
self.source_map.label_map_back.insert(id, src);
@@ -251,13 +265,7 @@ impl ExprCollector<'_> {
251265
self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
252266
}
253267
ast::Expr::BlockExpr(e) => match e.modifier() {
254-
Some(ast::BlockModifier::Try(_)) => {
255-
self.collect_block_(e, |id, statements, tail| Expr::TryBlock {
256-
id,
257-
statements,
258-
tail,
259-
})
260-
}
268+
Some(ast::BlockModifier::Try(_)) => self.collect_try_block(e),
261269
Some(ast::BlockModifier::Unsafe(_)) => {
262270
self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
263271
id,
@@ -437,10 +445,7 @@ impl ExprCollector<'_> {
437445
let expr = self.collect_expr_opt(e.expr());
438446
self.alloc_expr(Expr::Await { expr }, syntax_ptr)
439447
}
440-
ast::Expr::TryExpr(e) => {
441-
let expr = self.collect_expr_opt(e.expr());
442-
self.alloc_expr(Expr::Try { expr }, syntax_ptr)
443-
}
448+
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
444449
ast::Expr::CastExpr(e) => {
445450
let expr = self.collect_expr_opt(e.expr());
446451
let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
@@ -601,6 +606,126 @@ impl ExprCollector<'_> {
601606
})
602607
}
603608

609+
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
610+
/// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
611+
/// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
612+
fn collect_try_block(&mut self, e: BlockExpr) -> ExprId {
613+
let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else {
614+
return self.alloc_expr_desugared(Expr::Missing);
615+
};
616+
let prev_try_block = self.current_try_block.take();
617+
self.current_try_block =
618+
Some(self.alloc_label_desugared(Label { name: Name::generate_new_name() }));
619+
let expr_id = self.collect_block(e);
620+
let callee = self.alloc_expr_desugared(Expr::Path(try_from_output));
621+
let Expr::Block { label, tail, .. } = &mut self.body.exprs[expr_id] else {
622+
unreachable!("It is the output of collect block");
623+
};
624+
*label = self.current_try_block;
625+
let next_tail = match *tail {
626+
Some(tail) => self.alloc_expr_desugared(Expr::Call {
627+
callee,
628+
args: Box::new([tail]),
629+
is_assignee_expr: false,
630+
}),
631+
None => {
632+
let unit = self.alloc_expr_desugared(Expr::Tuple {
633+
exprs: Box::new([]),
634+
is_assignee_expr: false,
635+
});
636+
self.alloc_expr_desugared(Expr::Call {
637+
callee,
638+
args: Box::new([unit]),
639+
is_assignee_expr: false,
640+
})
641+
}
642+
};
643+
let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else {
644+
unreachable!("It is the output of collect block");
645+
};
646+
*tail = Some(next_tail);
647+
self.current_try_block = prev_try_block;
648+
expr_id
649+
}
650+
651+
/// Desugar `ast::TryExpr` from: `<expr>?` into:
652+
/// ```ignore (pseudo-rust)
653+
/// match Try::branch(<expr>) {
654+
/// ControlFlow::Continue(val) => val,
655+
/// ControlFlow::Break(residual) =>
656+
/// // If there is an enclosing `try {...}`:
657+
/// break 'catch_target Try::from_residual(residual),
658+
/// // Otherwise:
659+
/// return Try::from_residual(residual),
660+
/// }
661+
/// ```
662+
fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
663+
let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: {
664+
if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) {
665+
if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) {
666+
if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) {
667+
if let Some(try_from_residual) =
668+
LangItem::TryTraitFromResidual.path(self.db, self.krate)
669+
{
670+
break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual);
671+
}
672+
}
673+
}
674+
}
675+
// Some of the needed lang items are missing, so we can't desugar
676+
return self.alloc_expr(Expr::Missing, syntax_ptr);
677+
};
678+
let operand = self.collect_expr_opt(e.expr());
679+
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone());
680+
let expr = self.alloc_expr(
681+
Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
682+
syntax_ptr.clone(),
683+
);
684+
let continue_name = Name::generate_new_name();
685+
let continue_binding =
686+
self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
687+
let continue_bpat =
688+
self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
689+
self.add_definition_to_binding(continue_binding, continue_bpat);
690+
let continue_arm = MatchArm {
691+
pat: self.alloc_pat_desugared(Pat::TupleStruct {
692+
path: Some(Box::new(cf_continue)),
693+
args: Box::new([continue_bpat]),
694+
ellipsis: None,
695+
}),
696+
guard: None,
697+
expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr.clone()),
698+
};
699+
let break_name = Name::generate_new_name();
700+
let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated);
701+
let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
702+
self.add_definition_to_binding(break_binding, break_bpat);
703+
let break_arm = MatchArm {
704+
pat: self.alloc_pat_desugared(Pat::TupleStruct {
705+
path: Some(Box::new(cf_break)),
706+
args: Box::new([break_bpat]),
707+
ellipsis: None,
708+
}),
709+
guard: None,
710+
expr: {
711+
let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone());
712+
let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
713+
let result = self.alloc_expr(
714+
Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false },
715+
syntax_ptr.clone(),
716+
);
717+
if let Some(label) = self.current_try_block {
718+
let label = Some(self.body.labels[label].name.clone());
719+
self.alloc_expr(Expr::Break { expr: Some(result), label }, syntax_ptr.clone())
720+
} else {
721+
self.alloc_expr(Expr::Return { expr: Some(result) }, syntax_ptr.clone())
722+
}
723+
},
724+
};
725+
let arms = Box::new([continue_arm, break_arm]);
726+
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
727+
}
728+
604729
fn collect_macro_call<F, T, U>(
605730
&mut self,
606731
mcall: ast::MacroCall,
@@ -949,16 +1074,24 @@ impl ExprCollector<'_> {
9491074
.collect(),
9501075
}
9511076
}
952-
ast::Pat::LiteralPat(lit) => {
953-
if let Some(ast_lit) = lit.literal() {
954-
let expr = Expr::Literal(ast_lit.kind().into());
1077+
// FIXME: rustfmt removes this label if it is a block and not a loop
1078+
ast::Pat::LiteralPat(lit) => 'b: loop {
1079+
break if let Some(ast_lit) = lit.literal() {
1080+
let mut hir_lit: Literal = ast_lit.kind().into();
1081+
if lit.minus_token().is_some() {
1082+
let Some(h) = hir_lit.negate() else {
1083+
break 'b Pat::Missing;
1084+
};
1085+
hir_lit = h;
1086+
}
1087+
let expr = Expr::Literal(hir_lit);
9551088
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
9561089
let expr_id = self.alloc_expr(expr, expr_ptr);
9571090
Pat::Lit(expr_id)
9581091
} else {
9591092
Pat::Missing
960-
}
961-
}
1093+
};
1094+
},
9621095
ast::Pat::RestPat(_) => {
9631096
// `RestPat` requires special handling and should not be mapped
9641097
// to a Pat. Here we are using `Pat::Missing` as a fallback for
@@ -1063,11 +1196,11 @@ impl From<ast::LiteralKind> for Literal {
10631196
FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
10641197
builtin,
10651198
)
1066-
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
1067-
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1068-
} else {
1069-
let builtin = lit.suffix().and_then(BuiltinUint::from_suffix);
1199+
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) {
10701200
Literal::Uint(lit.value().unwrap_or(0), builtin)
1201+
} else {
1202+
let builtin = lit.suffix().and_then(BuiltinInt::from_suffix);
1203+
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
10711204
}
10721205
}
10731206
LiteralKind::FloatNumber(lit) => {

crates/hir-def/src/body/pretty.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,6 @@ impl<'a> Printer<'a> {
288288
self.print_expr(*expr);
289289
w!(self, ".await");
290290
}
291-
Expr::Try { expr } => {
292-
self.print_expr(*expr);
293-
w!(self, "?");
294-
}
295291
Expr::Cast { expr, type_ref } => {
296292
self.print_expr(*expr);
297293
w!(self, " as ");
@@ -424,9 +420,6 @@ impl<'a> Printer<'a> {
424420
Expr::Unsafe { id: _, statements, tail } => {
425421
self.print_block(Some("unsafe "), statements, tail);
426422
}
427-
Expr::TryBlock { id: _, statements, tail } => {
428-
self.print_block(Some("try "), statements, tail);
429-
}
430423
Expr::Async { id: _, statements, tail } => {
431424
self.print_block(Some("async "), statements, tail);
432425
}

crates/hir-def/src/body/scope.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
202202
}
203203
Expr::Unsafe { id, statements, tail }
204204
| Expr::Async { id, statements, tail }
205-
| Expr::Const { id, statements, tail }
206-
| Expr::TryBlock { id, statements, tail } => {
205+
| Expr::Const { id, statements, tail } => {
207206
let mut scope = scopes.new_block_scope(*scope, *id, None);
208207
// Overwrite the old scope for the block expr, so that every block scope can be found
209208
// via the block itself (important for blocks that only contain items, no expressions).

crates/hir-def/src/expr.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ pub enum Literal {
9292
Float(FloatTypeWrapper, Option<BuiltinFloat>),
9393
}
9494

95+
impl Literal {
96+
pub fn negate(self) -> Option<Self> {
97+
if let Literal::Int(i, k) = self {
98+
Some(Literal::Int(-i, k))
99+
} else {
100+
None
101+
}
102+
}
103+
}
104+
95105
#[derive(Debug, Clone, Eq, PartialEq)]
96106
pub enum Expr {
97107
/// This is produced if the syntax tree does not have a required expression piece.
@@ -112,11 +122,6 @@ pub enum Expr {
112122
tail: Option<ExprId>,
113123
label: Option<LabelId>,
114124
},
115-
TryBlock {
116-
id: BlockId,
117-
statements: Box<[Statement]>,
118-
tail: Option<ExprId>,
119-
},
120125
Async {
121126
id: BlockId,
122127
statements: Box<[Statement]>,
@@ -192,9 +197,6 @@ pub enum Expr {
192197
Await {
193198
expr: ExprId,
194199
},
195-
Try {
196-
expr: ExprId,
197-
},
198200
Cast {
199201
expr: ExprId,
200202
type_ref: Interned<TypeRef>,
@@ -303,7 +305,6 @@ impl Expr {
303305
f(*expr);
304306
}
305307
Expr::Block { statements, tail, .. }
306-
| Expr::TryBlock { statements, tail, .. }
307308
| Expr::Unsafe { statements, tail, .. }
308309
| Expr::Async { statements, tail, .. }
309310
| Expr::Const { statements, tail, .. } => {
@@ -383,7 +384,6 @@ impl Expr {
383384
}
384385
Expr::Field { expr, .. }
385386
| Expr::Await { expr }
386-
| Expr::Try { expr }
387387
| Expr::Cast { expr, .. }
388388
| Expr::Ref { expr, .. }
389389
| Expr::UnaryOp { expr, .. }

0 commit comments

Comments
 (0)