Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement gen block and function parsing #16173

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/hir-def/src/body.rs
Expand Up @@ -126,6 +126,7 @@ impl Body {
let mut params = None;

let mut is_async_fn = false;
let mut is_gen_fn = false;
let InFile { file_id, value: body } = {
match def {
DefWithBodyId::FunctionId(f) => {
Expand All @@ -146,7 +147,9 @@ impl Body {
}),
)
});
// FIXME from here we know this only happens for functions, so maybe we can get the blockexpr directly and also onlive provide the keyword values then
is_async_fn = data.has_async_kw();
is_gen_fn = data.has_gen_kw();
src.map(|it| it.body().map(ast::Expr::from))
}
DefWithBodyId::ConstId(c) => {
Expand All @@ -170,7 +173,7 @@ impl Body {
let module = def.module(db);
let expander = Expander::new(db, file_id, module);
let (mut body, mut source_map) =
Body::new(db, def, expander, params, body, module.krate, is_async_fn);
Body::new(db, def, expander, params, body, module.krate, is_async_fn, is_gen_fn);
body.shrink_to_fit();
source_map.shrink_to_fit();

Expand Down Expand Up @@ -210,8 +213,9 @@ impl Body {
body: Option<ast::Expr>,
krate: CrateId,
is_async_fn: bool,
is_gen_fn: bool,
) -> (Body, BodySourceMap) {
lower::lower(db, owner, expander, params, body, krate, is_async_fn)
lower::lower(db, owner, expander, params, body, krate, is_async_fn, is_gen_fn)
}

fn shrink_to_fit(&mut self) {
Expand Down
187 changes: 167 additions & 20 deletions crates/hir-def/src/body/lower.rs
Expand Up @@ -59,6 +59,7 @@ pub(super) fn lower(
body: Option<ast::Expr>,
krate: CrateId,
is_async_fn: bool,
is_gen_fn: bool,
) -> (Body, BodySourceMap) {
ExprCollector {
db,
Expand All @@ -85,7 +86,7 @@ pub(super) fn lower(
label_ribs: Vec::new(),
current_binding_owner: None,
}
.collect(params, body, is_async_fn)
.collect(params, body, is_async_fn, is_gen_fn)
}

struct ExprCollector<'a> {
Expand Down Expand Up @@ -191,6 +192,7 @@ impl ExprCollector<'_> {
param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
is_async_fn: bool,
is_gen_fn: bool,
) -> (Body, BodySourceMap) {
if let Some((param_list, mut attr_enabled)) = param_list {
if let Some(self_param) =
Expand All @@ -212,23 +214,73 @@ impl ExprCollector<'_> {
self.body.params.push(param_pat);
}
};
self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
if is_async_fn {
match body {
self.body.body_expr =
self.with_label_rib(RibKind::Closure, |this| match (is_async_fn, is_gen_fn) {
(false, false) => this.collect_expr_opt(body),
(false, true) => match body {
Some(e) => {
let expr = this.collect_expr(e);
this.alloc_expr_desugared(Expr::Async {
id: None,
statements: Box::new([]),
tail: Some(expr),

this.alloc_expr_desugared(Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body: expr,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::Gen,
crate::hir::CoroutineSource::Fn,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
})
}
None => this.missing_expr(),
}
} else {
this.collect_expr_opt(body)
}
});
},
(true, false) => match body {
Some(e) => {
let expr = this.collect_expr(e);

this.alloc_expr_desugared(Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body: expr,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::Async,
crate::hir::CoroutineSource::Fn,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
})
}
None => this.missing_expr(),
},
(true, true) => match body {
Some(e) => {
let expr = this.collect_expr(e);

this.alloc_expr_desugared(Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body: expr,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::AsyncGen,
crate::hir::CoroutineSource::Fn,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
})
}
None => this.missing_expr(),
},
});

(self.body, self.source_map)
}
Expand Down Expand Up @@ -268,6 +320,7 @@ impl ExprCollector<'_> {
let expr = self.collect_expr_opt(e.expr());
self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
}
// https://github.com/compiler-errors/rust/blob/bd0eec74026d5f967afeadc3611bdb674a7b9de4/compiler/rustc_ast/src/ast.rs#L1430
ast::Expr::BlockExpr(e) => match e.modifier() {
Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
Some(ast::BlockModifier::Unsafe(_)) => {
Expand All @@ -288,13 +341,76 @@ impl ExprCollector<'_> {
})
})
}
// https://github.com/compiler-errors/rust/blob/closure-kind/compiler/rustc_ast/src/ast.rs#L1430
// https://github.com/compiler-errors/rust/blob/bd0eec74026d5f967afeadc3611bdb674a7b9de4/compiler/rustc_ast_lowering/src/expr.rs#L186
Some(ast::BlockModifier::Async(_)) => {
self.with_label_rib(RibKind::Closure, |this| {
this.collect_block_(e, |id, statements, tail| Expr::Async {
id,
statements,
tail,
})
let (result_expr_id, _) = this.initialize_binding_owner(syntax_ptr);

let body = this.collect_block(e);

this.body.exprs[result_expr_id] = Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::Async,
crate::hir::CoroutineSource::Block,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
};

result_expr_id
})
}
Some(ast::BlockModifier::Gen(_)) => self.with_label_rib(RibKind::Closure, |this| {
let (result_expr_id, _) = this.initialize_binding_owner(syntax_ptr);

let body = this.collect_block(e);

this.body.exprs[result_expr_id] = Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::Gen,
crate::hir::CoroutineSource::Block,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
};

result_expr_id
}),
Some(ast::BlockModifier::AsyncGen(_)) => {
self.with_label_rib(RibKind::Closure, |this| {
let (result_expr_id, _) = this.initialize_binding_owner(syntax_ptr);

let body = this.collect_block(e);

this.body.exprs[result_expr_id] = Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: None, // FIXME maybe unspecified?
body,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::AsyncGen,
crate::hir::CoroutineSource::Block,
),
Movability::Movable,
),
capture_by: CaptureBy::Ref,
};

result_expr_id
})
}
Some(ast::BlockModifier::Const(_)) => {
Expand Down Expand Up @@ -504,6 +620,7 @@ impl ExprCollector<'_> {
}
}
ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
// here
let (result_expr_id, prev_binding_owner) =
this.initialize_binding_owner(syntax_ptr);
let mut args = Vec::new();
Expand Down Expand Up @@ -536,9 +653,39 @@ impl ExprCollector<'_> {
} else {
Movability::Movable
};
ClosureKind::Coroutine(movability)
ClosureKind::Coroutine(crate::hir::CoroutineKind::Coroutine, movability)
} else if e.async_token().is_some() {
ClosureKind::Async
// https://github.com/compiler-errors/rust/blob/bd0eec74026d5f967afeadc3611bdb674a7b9de4/compiler/rustc_ast_lowering/src/expr.rs#L1199 ?

let capture_by =
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };

let inner = Expr::Closure {
args: Box::new([]),
arg_types: Box::new([]),
ret_type: ret_type.clone(),
body,
closure_kind: ClosureKind::Coroutine(
crate::hir::CoroutineKind::Desugared(
crate::hir::CoroutineDesugaring::Async,
crate::hir::CoroutineSource::Closure,
),
Movability::Movable,
),
capture_by,
};
this.is_lowering_coroutine = prev_is_lowering_coroutine;
this.current_binding_owner = prev_binding_owner;
this.current_try_block_label = prev_try_block_label;
this.body.exprs[result_expr_id] = Expr::Closure {
args: args.into(),
arg_types: arg_types.into(),
ret_type,
body: this.alloc_expr_desugared(inner),
closure_kind: ClosureKind::Closure,
capture_by,
};
return result_expr_id;
} else {
ClosureKind::Closure
};
Expand Down
62 changes: 38 additions & 24 deletions crates/hir-def/src/body/pretty.rs
Expand Up @@ -6,8 +6,8 @@ use itertools::Itertools;

use crate::{
hir::{
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst,
Movability, Statement,
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, CoroutineDesugaring,
CoroutineKind, Literal, LiteralOrConst, Movability, Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
Expand Down Expand Up @@ -377,38 +377,55 @@ impl Printer<'_> {
w!(self, "]");
}
Expr::Closure { args, arg_types, ret_type, body, closure_kind, capture_by } => {
if let ClosureKind::Coroutine(_, Movability::Static) = closure_kind {
w!(self, "static ");
}
match closure_kind {
ClosureKind::Coroutine(Movability::Static) => {
w!(self, "static ");
}
ClosureKind::Async => {
ClosureKind::Coroutine(
CoroutineKind::Desugared(CoroutineDesugaring::Async, _),
_,
) => {
w!(self, "async ");
}
_ => (),
ClosureKind::Coroutine(
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _),
_,
) => {
w!(self, "async gen ");
}
ClosureKind::Coroutine(
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _),
_,
) => {
w!(self, "gen ");
}
_ => {}
}
match capture_by {
CaptureBy::Value => {
w!(self, "move ");
}
CaptureBy::Ref => (),
}
w!(self, "|");
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
if i != 0 {
w!(self, ", ");
if let ClosureKind::Closure = closure_kind {
w!(self, "|");
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
if i != 0 {
w!(self, ", ");
}
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
self.print_type_ref(ty);
}
}
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
self.print_type_ref(ty);
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
self.print_type_ref(ret_ty);
}
self.whitespace();
}
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
self.print_type_ref(ret_ty);
}
self.whitespace();
self.print_expr(*body);
}
Expr::Tuple { exprs, is_assignee_expr: _ } => {
Expand Down Expand Up @@ -448,9 +465,6 @@ impl Printer<'_> {
Expr::Unsafe { id: _, statements, tail } => {
self.print_block(Some("unsafe "), statements, tail);
}
Expr::Async { id: _, statements, tail } => {
self.print_block(Some("async "), statements, tail);
}
Expr::Const(id) => {
w!(self, "const {{ /* {id:?} */ }}");
}
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/body/scope.rs
Expand Up @@ -220,7 +220,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
Expr::Const(_) => {
// FIXME: This is broken.
}
Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
Expr::Unsafe { id, statements, tail } => {
let mut scope = scopes.new_block_scope(*scope, *id, None);
// Overwrite the old scope for the block expr, so that every block scope can be found
// via the block itself (important for blocks that only contain items, no expressions).
Expand Down