Skip to content

Commit 2812814

Browse files
committed
MIR episode 6
1 parent fcd3a6b commit 2812814

File tree

31 files changed

+1392
-415
lines changed

31 files changed

+1392
-415
lines changed

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

Lines changed: 115 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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::TryExpr` 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,17 @@ impl ExprCollector<'_> {
12151284
}
12161285
None => Pat::Missing,
12171286
},
1218-
// FIXME: implement
1219-
ast::Pat::RangePat(_) => Pat::Missing,
1287+
ast::Pat::RangePat(p) => {
1288+
let start = p.start().and_then(|x| match &x {
1289+
ast::Pat::LiteralPat(x) => Some(pat_literal_to_hir(x)?.0),
1290+
_ => None,
1291+
});
1292+
let end = p.end().and_then(|x| match &x {
1293+
ast::Pat::LiteralPat(x) => Some(pat_literal_to_hir(x)?.0),
1294+
_ => None,
1295+
});
1296+
Pat::Range { start, end }
1297+
}
12201298
};
12211299
let ptr = AstPtr::new(&pat);
12221300
self.alloc_pat(pattern, Either::Left(ptr))
@@ -1338,6 +1416,18 @@ impl ExprCollector<'_> {
13381416
// endregion: labels
13391417
}
13401418

1419+
fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
1420+
let ast_lit = lit.literal()?;
1421+
let mut hir_lit: Literal = ast_lit.kind().into();
1422+
if lit.minus_token().is_some() {
1423+
let Some(h) = hir_lit.negate() else {
1424+
return None;
1425+
};
1426+
hir_lit = h;
1427+
}
1428+
Some((hir_lit, ast_lit))
1429+
}
1430+
13411431
impl ExprCollector<'_> {
13421432
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
13431433
let src = self.expander.to_source(ptr);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,13 @@ impl<'a> Printer<'a> {
534534
w!(self, "}}");
535535
}
536536
Pat::Range { start, end } => {
537-
self.print_expr(*start);
537+
if let Some(start) = start {
538+
self.print_literal(start);
539+
}
538540
w!(self, "...");
539-
self.print_expr(*end);
541+
if let Some(end) = end {
542+
self.print_literal(end);
543+
}
540544
}
541545
Pat::Slice { prefix, slice, suffix } => {
542546
w!(self, "[");

crates/hir-def/src/hir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ pub enum Pat {
526526
Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
527527
Or(Box<[PatId]>),
528528
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
529-
Range { start: ExprId, end: ExprId },
529+
Range { start: Option<Literal>, end: Option<Literal> },
530530
Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
531531
Path(Box<Path>),
532532
Lit(ExprId),

crates/hir-ty/src/consteval.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use stdx::never;
1414
use triomphe::Arc;
1515

1616
use crate::{
17-
db::HirDatabase, infer::InferenceContext, layout::layout_of_ty, lower::ParamLoweringMode,
18-
to_placeholder_idx, utils::Generics, Const, ConstData, ConstScalar, ConstValue, GenericArg,
19-
Interner, MemoryMap, Substitution, Ty, TyBuilder,
17+
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
18+
mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
19+
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder,
2020
};
2121

2222
use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -130,14 +130,15 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const {
130130

131131
/// Interns a constant scalar with the given type
132132
pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const {
133+
let layout = db.layout_of_ty(ty.clone(), krate);
133134
let bytes = match value {
134135
ConstRef::Int(i) => {
135136
// FIXME: We should handle failure of layout better.
136-
let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16);
137+
let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16);
137138
ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default())
138139
}
139140
ConstRef::UInt(i) => {
140-
let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16);
141+
let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16);
141142
ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default())
142143
}
143144
ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()),
@@ -206,24 +207,35 @@ pub(crate) fn const_eval_query(
206207
subst: Substitution,
207208
) -> Result<Const, ConstEvalError> {
208209
let body = match def {
209-
GeneralConstId::ConstId(c) => db.mir_body(c.into())?,
210+
GeneralConstId::ConstId(c) => {
211+
db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))?
212+
}
210213
GeneralConstId::AnonymousConstId(c) => {
211214
let (def, root) = db.lookup_intern_anonymous_const(c);
212215
let body = db.body(def);
213216
let infer = db.infer(def);
214-
Arc::new(lower_to_mir(db, def, &body, &infer, root)?)
217+
Arc::new(monomorphize_mir_body_bad(
218+
db,
219+
lower_to_mir(db, def, &body, &infer, root)?,
220+
subst,
221+
db.trait_environment_for_body(def),
222+
)?)
215223
}
216224
};
217-
let c = interpret_mir(db, &body, subst, false).0?;
225+
let c = interpret_mir(db, &body, false).0?;
218226
Ok(c)
219227
}
220228

221229
pub(crate) fn const_eval_static_query(
222230
db: &dyn HirDatabase,
223231
def: StaticId,
224232
) -> Result<Const, ConstEvalError> {
225-
let body = db.mir_body(def.into())?;
226-
let c = interpret_mir(db, &body, Substitution::empty(Interner), false).0?;
233+
let body = db.monomorphized_mir_body(
234+
def.into(),
235+
Substitution::empty(Interner),
236+
db.trait_environment_for_body(def.into()),
237+
)?;
238+
let c = interpret_mir(db, &body, false).0?;
227239
Ok(c)
228240
}
229241

@@ -245,8 +257,12 @@ pub(crate) fn const_eval_discriminant_variant(
245257
};
246258
return Ok(value);
247259
}
248-
let mir_body = db.mir_body(def)?;
249-
let c = interpret_mir(db, &mir_body, Substitution::empty(Interner), false).0?;
260+
let mir_body = db.monomorphized_mir_body(
261+
def,
262+
Substitution::empty(Interner),
263+
db.trait_environment_for_body(def),
264+
)?;
265+
let c = interpret_mir(db, &mir_body, false).0?;
250266
let c = try_const_usize(db, &c).unwrap() as i128;
251267
Ok(c)
252268
}
@@ -271,7 +287,7 @@ pub(crate) fn eval_to_const(
271287
}
272288
let infer = ctx.clone().resolve_all();
273289
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
274-
if let Ok(result) = interpret_mir(db, &mir_body, Substitution::empty(Interner), true).0 {
290+
if let Ok(result) = interpret_mir(db, &mir_body, true).0 {
275291
return result;
276292
}
277293
}

0 commit comments

Comments
 (0)