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

API, Rustc: Add AwaitExpr and support async blocks and fns #197

Merged
merged 11 commits into from
Aug 3, 2023
5 changes: 4 additions & 1 deletion marker_api/src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub enum ExprKind<'ast> {
For(&'ast ForExpr<'ast>),
Loop(&'ast LoopExpr<'ast>),
While(&'ast WhileExpr<'ast>),
Await(&'ast AwaitExpr<'ast>),
Unstable(&'ast UnstableExpr<'ast>),
}

Expand Down Expand Up @@ -163,6 +164,7 @@ pub enum ExprPrecedence {
For = 0x1400_0004,
Loop = 0x1400_0005,
While = 0x1400_0006,
Await = 0x1400_0007,

Path = 0x1300_0000,

Expand Down Expand Up @@ -252,6 +254,7 @@ macro_rules! impl_expr_kind_fn {
Call, Method,
Array, Tuple, Ctor, Range,
If, Let, Match, Break, Return, Continue, For, Loop, While,
Await,
Unstable
);
};
Expand Down Expand Up @@ -376,7 +379,7 @@ mod test {
assert_eq!(48, size_of::<StrLitExpr<'_>>(), "StrLitExpr<'_>");
assert_eq!(24, size_of::<CharLitExpr<'_>>(), "CharLitExpr<'_>");
assert_eq!(24, size_of::<BoolLitExpr<'_>>(), "BoolLitExpr<'_>");
assert_eq!(88, size_of::<BlockExpr<'_>>(), "BlockExpr<'_>");
assert_eq!(96, size_of::<BlockExpr<'_>>(), "BlockExpr<'_>");
assert_eq!(72, size_of::<ClosureExpr<'_>>(), "ClosureExpr<'_>");
assert_eq!(40, size_of::<UnaryOpExpr<'_>>(), "UnaryOpExpr<'_>");
assert_eq!(40, size_of::<RefExpr<'_>>(), "RefExpr<'_>");
Expand Down
47 changes: 41 additions & 6 deletions marker_api/src/ast/expr/block_expr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
ast::{pat::PatKind, stmt::StmtKind, ty::SynTyKind, BodyId, Ident, Span, SpanId},
ast::{pat::PatKind, stmt::StmtKind, ty::SynTyKind, BodyId, Ident, Safety, Span, SpanId, Syncness},
context::with_cx,
ffi::{FfiOption, FfiSlice},
};
Expand All @@ -23,6 +23,9 @@ use super::{CommonExprData, ExprKind};
///
/// // vvvvvv An optional label to be targeted by break expressions
/// let _ = 'label: {
/// let _ = 18;
/// // ^^^^^^^^^^^
/// // A statement in the block
/// 12
/// };
/// ```
Expand All @@ -31,14 +34,19 @@ use super::{CommonExprData, ExprKind};
/// expression at the end of a block is called *block expression*. The meaning
/// depends on the context. Marker's documentation will try to make the meaning
/// clear by linking directly to the [`BlockExpr`] struct or calling it a *block*.
///
/// This expression also represents async blocks, the internal desugar used by
/// rustc is resugared for this.
#[repr(C)]
#[derive(Debug)]
pub struct BlockExpr<'ast> {
data: CommonExprData<'ast>,
stmts: FfiSlice<'ast, StmtKind<'ast>>,
expr: FfiOption<ExprKind<'ast>>,
label: FfiOption<Ident<'ast>>,
is_unsafe: bool,
safety: Safety,
syncness: Syncness,
capture_kind: CaptureKind,
}

impl<'ast> BlockExpr<'ast> {
Expand All @@ -58,8 +66,31 @@ impl<'ast> BlockExpr<'ast> {
self.label.get()
}

pub fn is_unsafe(&self) -> bool {
self.is_unsafe
pub fn safety(&self) -> Safety {
self.safety
}

pub fn syncness(&self) -> Syncness {
self.syncness
}

/// The capture kind of this block. For normal blocks, this will always be
/// [`CaptureKind::Default`], which in this context means no capture at all.
/// Async blocks are special, as they can capture values by move, indicated
/// by the `move` keyword, like in this:
///
/// ```
/// # use std::future::Future;
/// # fn foo<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
/// // The whole block expression
/// // vvvvvvvvvvvvvvvvv
/// async move { *x }
/// // ^^^^
/// // The move keyword defining the capture kind
/// # }
/// ```
pub fn capture_kind(&self) -> CaptureKind {
self.capture_kind
}
}

Expand All @@ -72,14 +103,18 @@ impl<'ast> BlockExpr<'ast> {
stmts: &'ast [StmtKind<'ast>],
expr: Option<ExprKind<'ast>>,
label: Option<Ident<'ast>>,
is_unsafe: bool,
safety: Safety,
syncness: Syncness,
capture_kind: CaptureKind,
) -> Self {
Self {
data,
stmts: stmts.into(),
expr: expr.into(),
label: label.into(),
is_unsafe,
safety,
syncness,
capture_kind,
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions marker_api/src/ast/expr/op_exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,44 @@ impl<'ast> AssignExpr<'ast> {
}
}
}

/// An `.await` expression on a future, like:
///
/// ```
/// # async fn foo() -> u8 {
/// # 16
/// # }
/// # async fn wrapper() {
/// // The await expression
/// // vvvvvvvvvvv
/// foo().await;
/// // ^^^^^
/// // The future, that will be awaited
/// # }
/// ```
///
/// Marker specificity hides the desugar of `.await` expressions. The [Rust Reference]
/// contains more information how rustc desugars `.await` expressions.
///
/// [Rust Reference]: <https://doc.rust-lang.org/reference/expressions/await-expr.html>
#[repr(C)]
#[derive(Debug)]
pub struct AwaitExpr<'ast> {
data: CommonExprData<'ast>,
expr: ExprKind<'ast>,
}

impl<'ast> AwaitExpr<'ast> {
pub fn expr(&self) -> ExprKind<'ast> {
self.expr
}
}

super::impl_expr_data!(AwaitExpr<'ast>, Await);

#[cfg(feature = "driver-api")]
impl<'ast> AwaitExpr<'ast> {
pub fn new(data: CommonExprData<'ast>, expr: ExprKind<'ast>) -> Self {
Self { data, expr }
}
}
12 changes: 12 additions & 0 deletions marker_api/src/ast/item/fn_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,20 @@ use super::CommonItemData;
/// // A function without a body
/// fn baz(_: i32);
/// }
///
/// // An async function.
/// async fn foo_async() -> u8 {
/// // ...
/// # 16
/// }
/// ```
///
/// Async functions in Rustc actually return a future with the defined output type.
/// The return type `-> u8` gets desugared to `impl Future<Output = u8>`. Marker will
/// resugar the type to what the user had originally written. In this case it would
/// just return `u8`. The semantic return type of an async function can be retrieved
/// from the expression of the [`Body`][super::Body].
///
/// See: <https://doc.rust-lang.org/reference/items/functions.html>
#[repr(C)]
#[derive(Debug)]
Expand Down
4 changes: 4 additions & 0 deletions marker_api/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ pub use crate::ast::ty::SynTyData;
// Common types
pub use crate::ast::expr::ExprKind;
pub use crate::ast::item::ItemKind;
pub use crate::ast::pat::PatKind;
pub use crate::ast::stmt::StmtKind;
pub use crate::ast::ty::SemTyKind;
pub use crate::ast::ty::SynTyKind;
pub use crate::ast::Ident;
pub use crate::ast::Span;
pub use crate::AstContext;
37 changes: 20 additions & 17 deletions marker_rustc_driver/src/conversion/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,26 @@ impl<'ast, 'tcx> MarkerConverterInner<'ast, 'tcx> {
{
self.storage.alloc_slice(iter)
}

pub fn with_body<U, F>(&self, rustc_body_id: hir::BodyId, f: F) -> U
where
F: FnOnce() -> U,
{
// Body-Translation-Stack push
let prev_rustc_body_id = self.rustc_body.replace(Some(rustc_body_id));
let prev_rustc_ty_check = self.rustc_ty_check.take();
self.fill_rustc_ty_check();

// Operation
let res = f();

// Body-Translation-Stack pop
self.rustc_body.replace(prev_rustc_body_id);
self.rustc_ty_check.replace(prev_rustc_ty_check);

// Return result
res
}
}

impl<'ast, 'tcx> MarkerConverterInner<'ast, 'tcx> {
Expand All @@ -219,20 +239,3 @@ impl<'ast, 'tcx> MarkerConverterInner<'ast, 'tcx> {
))
}
}

macro_rules! with_body {
($cx:expr, $id:expr, $with:expr) => {
// Body-Translation-Stack push
let prev_rustc_body_id = $cx.rustc_body.replace(Some($id));
let prev_rustc_ty_check = $cx.rustc_ty_check.take();
$cx.fill_rustc_ty_check();

// Operation
$with

// Body-Translation-Stack pop
$cx.rustc_body.replace(prev_rustc_body_id);
$cx.rustc_ty_check.replace(prev_rustc_ty_check);
};
}
use with_body;
Loading