Skip to content

Commit bc82952

Browse files
committed
Auto merge of #14892 - HKalbasi:mir, r=HKalbasi
MIR episode 6 This PR separates monomorphization from interpreting, and add a monomorphization query to cache the results. Together with making layout queries returning `Arc<Layout>` instead of `Layout` (did you know that `Layout` is a 312 byte struct with a couple of vectors, so it is very costly to clone? I thought it should be very small and cheap) it makes mir interpreting an order of magnitude faster in warmed calls. It still can't evaluate no test in the r-a repo, but all tests that I tried are hitting #7434 so I hope after that it will become able to interpret some real world test.
2 parents 505fd09 + 5136879 commit bc82952

File tree

35 files changed

+1474
-556
lines changed

35 files changed

+1474
-556
lines changed

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

+130-27
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ use crate::{
3131
expander::Expander,
3232
hir::{
3333
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
34-
ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat,
35-
RecordLitField, Statement,
34+
ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, Pat, PatId,
35+
RecordFieldPat, RecordLitField, Statement,
3636
},
3737
item_scope::BuiltinShadowMode,
3838
lang_item::LangItem,
@@ -295,13 +295,7 @@ impl ExprCollector<'_> {
295295

296296
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
297297
}
298-
ast::Expr::ForExpr(e) => {
299-
let label = e.label().map(|label| self.collect_label(label));
300-
let iterable = self.collect_expr_opt(e.iterable());
301-
let pat = self.collect_pat_top(e.pat());
302-
let body = self.collect_labelled_block_opt(label, e.loop_body());
303-
self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
304-
}
298+
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
305299
ast::Expr::CallExpr(e) => {
306300
let is_rustc_box = {
307301
let attrs = e.attrs();
@@ -703,6 +697,91 @@ impl ExprCollector<'_> {
703697
expr_id
704698
}
705699

700+
/// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
701+
/// ```ignore (pseudo-rust)
702+
/// match IntoIterator::into_iter(<head>) {
703+
/// mut iter => {
704+
/// [opt_ident]: loop {
705+
/// match Iterator::next(&mut iter) {
706+
/// None => break,
707+
/// Some(<pat>) => <body>,
708+
/// };
709+
/// }
710+
/// }
711+
/// }
712+
/// ```
713+
fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {
714+
let (into_iter_fn, iter_next_fn, option_some, option_none) = 'if_chain: {
715+
if let Some(into_iter_fn) = LangItem::IntoIterIntoIter.path(self.db, self.krate) {
716+
if let Some(iter_next_fn) = LangItem::IteratorNext.path(self.db, self.krate) {
717+
if let Some(option_some) = LangItem::OptionSome.path(self.db, self.krate) {
718+
if let Some(option_none) = LangItem::OptionNone.path(self.db, self.krate) {
719+
break 'if_chain (into_iter_fn, iter_next_fn, option_some, option_none);
720+
}
721+
}
722+
}
723+
}
724+
// Some of the needed lang items are missing, so we can't desugar
725+
return self.alloc_expr(Expr::Missing, syntax_ptr);
726+
};
727+
let head = self.collect_expr_opt(e.iterable());
728+
let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr.clone());
729+
let iterator = self.alloc_expr(
730+
Expr::Call {
731+
callee: into_iter_fn_expr,
732+
args: Box::new([head]),
733+
is_assignee_expr: false,
734+
},
735+
syntax_ptr.clone(),
736+
);
737+
let none_arm = MatchArm {
738+
pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
739+
guard: None,
740+
expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone()),
741+
};
742+
let some_pat = Pat::TupleStruct {
743+
path: Some(Box::new(option_some)),
744+
args: Box::new([self.collect_pat_top(e.pat())]),
745+
ellipsis: None,
746+
};
747+
let some_arm = MatchArm {
748+
pat: self.alloc_pat_desugared(some_pat),
749+
guard: None,
750+
expr: self.collect_expr_opt(e.loop_body().map(|x| x.into())),
751+
};
752+
let iter_name = Name::generate_new_name();
753+
let iter_binding = self.alloc_binding(iter_name.clone(), BindingAnnotation::Mutable);
754+
let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name)), syntax_ptr.clone());
755+
let iter_expr_mut = self.alloc_expr(
756+
Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
757+
syntax_ptr.clone(),
758+
);
759+
let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr.clone());
760+
let iter_next_expr = self.alloc_expr(
761+
Expr::Call {
762+
callee: iter_next_fn_expr,
763+
args: Box::new([iter_expr_mut]),
764+
is_assignee_expr: false,
765+
},
766+
syntax_ptr.clone(),
767+
);
768+
let loop_inner = self.alloc_expr(
769+
Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) },
770+
syntax_ptr.clone(),
771+
);
772+
let label = e.label().map(|label| self.collect_label(label));
773+
let loop_outer =
774+
self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone());
775+
let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
776+
self.alloc_expr(
777+
Expr::Match {
778+
expr: iterator,
779+
arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]),
780+
},
781+
syntax_ptr.clone(),
782+
)
783+
}
784+
706785
/// Desugar `ast::TryExpr` from: `<expr>?` into:
707786
/// ```ignore (pseudo-rust)
708787
/// match Try::branch(<expr>) {
@@ -1159,22 +1238,12 @@ impl ExprCollector<'_> {
11591238
}
11601239
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676
11611240
ast::Pat::LiteralPat(lit) => 'b: {
1162-
if let Some(ast_lit) = lit.literal() {
1163-
let mut hir_lit: Literal = ast_lit.kind().into();
1164-
if lit.minus_token().is_some() {
1165-
let Some(h) = hir_lit.negate() else {
1166-
break 'b Pat::Missing;
1167-
};
1168-
hir_lit = h;
1169-
}
1170-
let expr = Expr::Literal(hir_lit);
1171-
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
1172-
let expr_id = self.alloc_expr(expr, expr_ptr);
1173-
Pat::Lit(expr_id)
1174-
} else {
1175-
Pat::Missing
1176-
}
1177-
},
1241+
let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { break 'b Pat::Missing };
1242+
let expr = Expr::Literal(hir_lit);
1243+
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
1244+
let expr_id = self.alloc_expr(expr, expr_ptr);
1245+
Pat::Lit(expr_id)
1246+
}
11781247
ast::Pat::RestPat(_) => {
11791248
// `RestPat` requires special handling and should not be mapped
11801249
// to a Pat. Here we are using `Pat::Missing` as a fallback for
@@ -1215,8 +1284,30 @@ impl ExprCollector<'_> {
12151284
}
12161285
None => Pat::Missing,
12171286
},
1218-
// FIXME: implement
1219-
ast::Pat::RangePat(_) => Pat::Missing,
1287+
// FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
1288+
ast::Pat::RangePat(p) => {
1289+
let mut range_part_lower = |p: Option<ast::Pat>| {
1290+
p.and_then(|x| match &x {
1291+
ast::Pat::LiteralPat(x) => {
1292+
Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0)))
1293+
}
1294+
ast::Pat::IdentPat(p) => {
1295+
let name =
1296+
p.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
1297+
Some(Box::new(LiteralOrConst::Const(name.into())))
1298+
}
1299+
ast::Pat::PathPat(p) => p
1300+
.path()
1301+
.and_then(|path| self.expander.parse_path(self.db, path))
1302+
.map(LiteralOrConst::Const)
1303+
.map(Box::new),
1304+
_ => None,
1305+
})
1306+
};
1307+
let start = range_part_lower(p.start());
1308+
let end = range_part_lower(p.end());
1309+
Pat::Range { start, end }
1310+
}
12201311
};
12211312
let ptr = AstPtr::new(&pat);
12221313
self.alloc_pat(pattern, Either::Left(ptr))
@@ -1338,6 +1429,18 @@ impl ExprCollector<'_> {
13381429
// endregion: labels
13391430
}
13401431

1432+
fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
1433+
let ast_lit = lit.literal()?;
1434+
let mut hir_lit: Literal = ast_lit.kind().into();
1435+
if lit.minus_token().is_some() {
1436+
let Some(h) = hir_lit.negate() else {
1437+
return None;
1438+
};
1439+
hir_lit = h;
1440+
}
1441+
Some((hir_lit, ast_lit))
1442+
}
1443+
13411444
impl ExprCollector<'_> {
13421445
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
13431446
let src = self.expander.to_source(ptr);

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

+16-14
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use syntax::ast::HasName;
77

88
use crate::{
99
hir::{
10-
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, Movability, Statement,
10+
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst,
11+
Movability, Statement,
1112
},
1213
pretty::{print_generic_args, print_path, print_type_ref},
1314
type_ref::TypeRef,
@@ -184,16 +185,6 @@ impl<'a> Printer<'a> {
184185
self.print_expr(*condition);
185186
self.print_expr(*body);
186187
}
187-
Expr::For { iterable, pat, body, label } => {
188-
if let Some(lbl) = label {
189-
w!(self, "{}: ", self.body[*lbl].name.display(self.db));
190-
}
191-
w!(self, "for ");
192-
self.print_pat(*pat);
193-
w!(self, " in ");
194-
self.print_expr(*iterable);
195-
self.print_expr(*body);
196-
}
197188
Expr::Call { callee, args, is_assignee_expr: _ } => {
198189
self.print_expr(*callee);
199190
w!(self, "(");
@@ -534,9 +525,13 @@ impl<'a> Printer<'a> {
534525
w!(self, "}}");
535526
}
536527
Pat::Range { start, end } => {
537-
self.print_expr(*start);
538-
w!(self, "...");
539-
self.print_expr(*end);
528+
if let Some(start) = start {
529+
self.print_literal_or_const(start);
530+
}
531+
w!(self, "..=");
532+
if let Some(end) = end {
533+
self.print_literal_or_const(end);
534+
}
540535
}
541536
Pat::Slice { prefix, slice, suffix } => {
542537
w!(self, "[");
@@ -627,6 +622,13 @@ impl<'a> Printer<'a> {
627622
}
628623
}
629624

625+
fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) {
626+
match literal_or_const {
627+
LiteralOrConst::Literal(l) => self.print_literal(l),
628+
LiteralOrConst::Const(c) => self.print_path(c),
629+
}
630+
}
631+
630632
fn print_literal(&mut self, literal: &Literal) {
631633
match literal {
632634
Literal::String(it) => w!(self, "{:?}", it),

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

-6
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
228228
scopes.set_scope(expr, scope);
229229
compute_block_scopes(statements, *tail, body, scopes, &mut scope);
230230
}
231-
Expr::For { iterable, pat, body: body_expr, label } => {
232-
compute_expr_scopes(*iterable, body, scopes, scope);
233-
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
234-
scopes.add_pat_bindings(body, scope, *pat);
235-
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
236-
}
237231
Expr::While { condition, body: body_expr, label } => {
238232
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
239233
compute_expr_scopes(*condition, body, scopes, &mut scope);

crates/hir-def/src/hir.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ pub enum Literal {
9696
Float(FloatTypeWrapper, Option<BuiltinFloat>),
9797
}
9898

99+
#[derive(Debug, Clone, Eq, PartialEq)]
100+
/// Used in range patterns.
101+
pub enum LiteralOrConst {
102+
Literal(Literal),
103+
Const(Path),
104+
}
105+
99106
impl Literal {
100107
pub fn negate(self) -> Option<Self> {
101108
if let Literal::Int(i, k) = self {
@@ -189,12 +196,6 @@ pub enum Expr {
189196
body: ExprId,
190197
label: Option<LabelId>,
191198
},
192-
For {
193-
iterable: ExprId,
194-
pat: PatId,
195-
body: ExprId,
196-
label: Option<LabelId>,
197-
},
198199
Call {
199200
callee: ExprId,
200201
args: Box<[ExprId]>,
@@ -382,10 +383,6 @@ impl Expr {
382383
f(*condition);
383384
f(*body);
384385
}
385-
Expr::For { iterable, body, .. } => {
386-
f(*iterable);
387-
f(*body);
388-
}
389386
Expr::Call { callee, args, .. } => {
390387
f(*callee);
391388
args.iter().copied().for_each(f);
@@ -526,7 +523,7 @@ pub enum Pat {
526523
Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
527524
Or(Box<[PatId]>),
528525
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
529-
Range { start: ExprId, end: ExprId },
526+
Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
530527
Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
531528
Path(Box<Path>),
532529
Lit(ExprId),

0 commit comments

Comments
 (0)