Skip to content

Commit

Permalink
MIR episode 6
Browse files Browse the repository at this point in the history
  • Loading branch information
HKalbasi committed May 28, 2023
1 parent 505fd09 commit 5136879
Show file tree
Hide file tree
Showing 35 changed files with 1,474 additions and 556 deletions.
157 changes: 130 additions & 27 deletions crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use crate::{
expander::Expander,
hir::{
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat,
RecordLitField, Statement,
ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, Pat, PatId,
RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
Expand Down Expand Up @@ -295,13 +295,7 @@ impl ExprCollector<'_> {

self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
}
ast::Expr::ForExpr(e) => {
let label = e.label().map(|label| self.collect_label(label));
let iterable = self.collect_expr_opt(e.iterable());
let pat = self.collect_pat_top(e.pat());
let body = self.collect_labelled_block_opt(label, e.loop_body());
self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
}
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
ast::Expr::CallExpr(e) => {
let is_rustc_box = {
let attrs = e.attrs();
Expand Down Expand Up @@ -703,6 +697,91 @@ impl ExprCollector<'_> {
expr_id
}

/// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
/// ```ignore (pseudo-rust)
/// match IntoIterator::into_iter(<head>) {
/// mut iter => {
/// [opt_ident]: loop {
/// match Iterator::next(&mut iter) {
/// None => break,
/// Some(<pat>) => <body>,
/// };
/// }
/// }
/// }
/// ```
fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {
let (into_iter_fn, iter_next_fn, option_some, option_none) = 'if_chain: {
if let Some(into_iter_fn) = LangItem::IntoIterIntoIter.path(self.db, self.krate) {
if let Some(iter_next_fn) = LangItem::IteratorNext.path(self.db, self.krate) {
if let Some(option_some) = LangItem::OptionSome.path(self.db, self.krate) {
if let Some(option_none) = LangItem::OptionNone.path(self.db, self.krate) {
break 'if_chain (into_iter_fn, iter_next_fn, option_some, option_none);
}
}
}
}
// Some of the needed lang items are missing, so we can't desugar
return self.alloc_expr(Expr::Missing, syntax_ptr);
};
let head = self.collect_expr_opt(e.iterable());
let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr.clone());
let iterator = self.alloc_expr(
Expr::Call {
callee: into_iter_fn_expr,
args: Box::new([head]),
is_assignee_expr: false,
},
syntax_ptr.clone(),
);
let none_arm = MatchArm {
pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
guard: None,
expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone()),
};
let some_pat = Pat::TupleStruct {
path: Some(Box::new(option_some)),
args: Box::new([self.collect_pat_top(e.pat())]),
ellipsis: None,
};
let some_arm = MatchArm {
pat: self.alloc_pat_desugared(some_pat),
guard: None,
expr: self.collect_expr_opt(e.loop_body().map(|x| x.into())),
};
let iter_name = Name::generate_new_name();
let iter_binding = self.alloc_binding(iter_name.clone(), BindingAnnotation::Mutable);
let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name)), syntax_ptr.clone());
let iter_expr_mut = self.alloc_expr(
Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
syntax_ptr.clone(),
);
let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr.clone());
let iter_next_expr = self.alloc_expr(
Expr::Call {
callee: iter_next_fn_expr,
args: Box::new([iter_expr_mut]),
is_assignee_expr: false,
},
syntax_ptr.clone(),
);
let loop_inner = self.alloc_expr(
Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) },
syntax_ptr.clone(),
);
let label = e.label().map(|label| self.collect_label(label));
let loop_outer =
self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone());
let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
self.alloc_expr(
Expr::Match {
expr: iterator,
arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]),
},
syntax_ptr.clone(),
)
}

/// Desugar `ast::TryExpr` from: `<expr>?` into:
/// ```ignore (pseudo-rust)
/// match Try::branch(<expr>) {
Expand Down Expand Up @@ -1159,22 +1238,12 @@ impl ExprCollector<'_> {
}
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676
ast::Pat::LiteralPat(lit) => 'b: {
if let Some(ast_lit) = lit.literal() {
let mut hir_lit: Literal = ast_lit.kind().into();
if lit.minus_token().is_some() {
let Some(h) = hir_lit.negate() else {
break 'b Pat::Missing;
};
hir_lit = h;
}
let expr = Expr::Literal(hir_lit);
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
let expr_id = self.alloc_expr(expr, expr_ptr);
Pat::Lit(expr_id)
} else {
Pat::Missing
}
},
let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { break 'b Pat::Missing };
let expr = Expr::Literal(hir_lit);
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
let expr_id = self.alloc_expr(expr, expr_ptr);
Pat::Lit(expr_id)
}
ast::Pat::RestPat(_) => {
// `RestPat` requires special handling and should not be mapped
// to a Pat. Here we are using `Pat::Missing` as a fallback for
Expand Down Expand Up @@ -1215,8 +1284,30 @@ impl ExprCollector<'_> {
}
None => Pat::Missing,
},
// FIXME: implement
ast::Pat::RangePat(_) => Pat::Missing,
// FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
ast::Pat::RangePat(p) => {
let mut range_part_lower = |p: Option<ast::Pat>| {
p.and_then(|x| match &x {
ast::Pat::LiteralPat(x) => {
Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0)))
}
ast::Pat::IdentPat(p) => {
let name =
p.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
Some(Box::new(LiteralOrConst::Const(name.into())))
}
ast::Pat::PathPat(p) => p
.path()
.and_then(|path| self.expander.parse_path(self.db, path))
.map(LiteralOrConst::Const)
.map(Box::new),
_ => None,
})
};
let start = range_part_lower(p.start());
let end = range_part_lower(p.end());
Pat::Range { start, end }
}
};
let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, Either::Left(ptr))
Expand Down Expand Up @@ -1338,6 +1429,18 @@ impl ExprCollector<'_> {
// endregion: labels
}

fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
let ast_lit = lit.literal()?;
let mut hir_lit: Literal = ast_lit.kind().into();
if lit.minus_token().is_some() {
let Some(h) = hir_lit.negate() else {
return None;
};
hir_lit = h;
}
Some((hir_lit, ast_lit))
}

impl ExprCollector<'_> {
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.to_source(ptr);
Expand Down
30 changes: 16 additions & 14 deletions crates/hir-def/src/body/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use syntax::ast::HasName;

use crate::{
hir::{
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, Movability, Statement,
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst,
Movability, Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
Expand Down Expand Up @@ -184,16 +185,6 @@ impl<'a> Printer<'a> {
self.print_expr(*condition);
self.print_expr(*body);
}
Expr::For { iterable, pat, body, label } => {
if let Some(lbl) = label {
w!(self, "{}: ", self.body[*lbl].name.display(self.db));
}
w!(self, "for ");
self.print_pat(*pat);
w!(self, " in ");
self.print_expr(*iterable);
self.print_expr(*body);
}
Expr::Call { callee, args, is_assignee_expr: _ } => {
self.print_expr(*callee);
w!(self, "(");
Expand Down Expand Up @@ -534,9 +525,13 @@ impl<'a> Printer<'a> {
w!(self, "}}");
}
Pat::Range { start, end } => {
self.print_expr(*start);
w!(self, "...");
self.print_expr(*end);
if let Some(start) = start {
self.print_literal_or_const(start);
}
w!(self, "..=");
if let Some(end) = end {
self.print_literal_or_const(end);
}
}
Pat::Slice { prefix, slice, suffix } => {
w!(self, "[");
Expand Down Expand Up @@ -627,6 +622,13 @@ impl<'a> Printer<'a> {
}
}

fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) {
match literal_or_const {
LiteralOrConst::Literal(l) => self.print_literal(l),
LiteralOrConst::Const(c) => self.print_path(c),
}
}

fn print_literal(&mut self, literal: &Literal) {
match literal {
Literal::String(it) => w!(self, "{:?}", it),
Expand Down
6 changes: 0 additions & 6 deletions crates/hir-def/src/body/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
scopes.set_scope(expr, scope);
compute_block_scopes(statements, *tail, body, scopes, &mut scope);
}
Expr::For { iterable, pat, body: body_expr, label } => {
compute_expr_scopes(*iterable, body, scopes, scope);
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
scopes.add_pat_bindings(body, scope, *pat);
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
}
Expr::While { condition, body: body_expr, label } => {
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
compute_expr_scopes(*condition, body, scopes, &mut scope);
Expand Down
19 changes: 8 additions & 11 deletions crates/hir-def/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ pub enum Literal {
Float(FloatTypeWrapper, Option<BuiltinFloat>),
}

#[derive(Debug, Clone, Eq, PartialEq)]
/// Used in range patterns.
pub enum LiteralOrConst {
Literal(Literal),
Const(Path),
}

impl Literal {
pub fn negate(self) -> Option<Self> {
if let Literal::Int(i, k) = self {
Expand Down Expand Up @@ -189,12 +196,6 @@ pub enum Expr {
body: ExprId,
label: Option<LabelId>,
},
For {
iterable: ExprId,
pat: PatId,
body: ExprId,
label: Option<LabelId>,
},
Call {
callee: ExprId,
args: Box<[ExprId]>,
Expand Down Expand Up @@ -382,10 +383,6 @@ impl Expr {
f(*condition);
f(*body);
}
Expr::For { iterable, body, .. } => {
f(*iterable);
f(*body);
}
Expr::Call { callee, args, .. } => {
f(*callee);
args.iter().copied().for_each(f);
Expand Down Expand Up @@ -526,7 +523,7 @@ pub enum Pat {
Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
Or(Box<[PatId]>),
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
Range { start: ExprId, end: ExprId },
Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
Path(Box<Path>),
Lit(ExprId),
Expand Down
Loading

0 comments on commit 5136879

Please sign in to comment.