Skip to content

Commit

Permalink
Implement offset_of in hir-def and hir-ty
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Sep 5, 2023
1 parent 9b8eb80 commit 4127ed4
Show file tree
Hide file tree
Showing 16 changed files with 92 additions and 116 deletions.
8 changes: 6 additions & 2 deletions crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
hir::{
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
Pat, PatId, RecordFieldPat, RecordLitField, Statement,
OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
Expand Down Expand Up @@ -649,7 +649,11 @@ impl ExprCollector<'_> {
}
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(_) => self.missing_expr(),
ast::Expr::OffsetOfExpr(_) => self.missing_expr(),
ast::Expr::OffsetOfExpr(e) => {
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
let fields = e.fields().map(|it| it.as_name()).collect();
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
}
ast::Expr::FormatArgsExpr(_) => self.missing_expr(),
})
}
Expand Down
10 changes: 10 additions & 0 deletions crates/hir-def/src/body/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::fmt::{self, Write};

use hir_expand::db::ExpandDatabase;
use itertools::Itertools;
use syntax::ast::HasName;

use crate::{
Expand Down Expand Up @@ -154,6 +155,15 @@ impl Printer<'_> {
match expr {
Expr::Missing => w!(self, "�"),
Expr::Underscore => w!(self, "_"),
Expr::OffsetOf(offset_of) => {
w!(self, "builtin#offset_of!(");
self.print_type_ref(&offset_of.container);
w!(
self,
", {})",
offset_of.fields.iter().format_with(".", |field, f| f(&field.display(self.db)))
);
}
Expr::Path(path) => self.print_path(path),
Expr::If { condition, then_branch, else_branch } => {
w!(self, "if ");
Expand Down
9 changes: 8 additions & 1 deletion crates/hir-def/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ pub enum Expr {
Array(Array),
Literal(Literal),
Underscore,
OffsetOf(OffsetOf),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetOf {
pub container: Interned<TypeRef>,
pub fields: Box<[Name]>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -341,7 +348,7 @@ impl Expr {
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
match self {
Expr::Missing => {}
Expr::Path(_) => {}
Expr::Path(_) | Expr::OffsetOf(_) => {}
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
f(*then_branch);
Expand Down
18 changes: 14 additions & 4 deletions crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,22 @@ fn main() {
}
}
"#,
expect![[r#"
expect![[r##"
#[rustc_builtin_macro]
macro_rules! column {() => {}}
macro_rules! asm {() => {}}
fn main() { 0 as u32; }
"#]],
fn main() {
let i: u64 = 3;
let o: u64;
unsafe {
builtin #asm ( {
$crate::format_args!("mov {0}, {1}");
$crate::format_args!("add {0}, 5");
}
);
}
}
"##]],
);
}

Expand Down
6 changes: 3 additions & 3 deletions crates/hir-expand/src/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,9 @@ fn asm_expand(

let pound = quote! {@PUNCT '#'};
let expanded = quote! {
builtin #pound asm {
##literals
}
builtin #pound asm (
{##literals}
)
};
ExpandResult::ok(expanded)
}
Expand Down
1 change: 1 addition & 0 deletions crates/hir-ty/src/infer/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ impl InferenceContext<'_> {

fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
match &self.body[tgt_expr] {
Expr::OffsetOf(_) => (),
Expr::If { condition, then_branch, else_branch } => {
self.consume_expr(*condition);
self.consume_expr(*then_branch);
Expand Down
1 change: 1 addition & 0 deletions crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,7 @@ impl InferenceContext<'_> {
});
expected
}
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
};
// use a new type variable if we got unknown here
let ty = self.insert_type_vars_shallow(ty);
Expand Down
1 change: 1 addition & 0 deletions crates/hir-ty/src/infer/mutability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl InferenceContext<'_> {
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
match &self.body[tgt_expr] {
Expr::Missing => (),
Expr::OffsetOf(_) => (),
&Expr::If { condition, then_branch, else_branch } => {
self.infer_mut_expr(condition, Mutability::Not);
self.infer_mut_expr(then_branch, Mutability::Not);
Expand Down
3 changes: 3 additions & 0 deletions crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
mut current: BasicBlockId,
) -> Result<Option<BasicBlockId>> {
match &self.body.exprs[expr_id] {
Expr::OffsetOf(_) => {
not_supported!("builtin#offset_of")
}
Expr::Missing => {
if let DefWithBodyId::FunctionId(f) = self.owner {
let assoc = f.lookup(self.db.upcast());
Expand Down
12 changes: 12 additions & 0 deletions crates/hir-ty/src/tests/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3649,3 +3649,15 @@ fn main() {
"#,
);
}

#[test]
fn offset_of() {
check_types(
r#"
fn main() {
builtin#offset_of((,), 0);
// ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
}
"#,
);
}
19 changes: 17 additions & 2 deletions crates/parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,24 +220,39 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
// fn foo() {
// builtin#asm(0);
// builtin#format_args(0);
// builtin#builtin(0);
// builtin#offset_of(Foo, bar.baz.0);
// }
fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
let m = p.start();
p.bump_remap(T![builtin]);
p.bump(T![#]);
if p.at_contextual_kw(T![offset_of]) {
p.bump_remap(T![offset_of]);
p.expect(T!['(']);
type_(p);
p.bump(T![,]);
p.expect(T![,]);
while !p.at(EOF) && !p.at(T![')']) {
if p.at(IDENT) || p.at(INT_NUMBER) {
name_ref_or_index(p);
// } else if p.at(FLOAT_NUMBER) {
// FIXME: needs float hack
} else {
p.err_and_bump("expected field name or number");
}
if !p.at(T![')']) {
p.expect(T![.]);
}
}
p.expect(T![')']);
Some(m.complete(p, OFFSET_OF_EXPR))
} else if p.at_contextual_kw(T![format_args]) {
p.bump_remap(T![format_args]);
p.expect(T!['(']);
expr(p);
p.expect(T![')']);
Some(m.complete(p, FORMAT_ARGS_EXPR))
} else if p.at_contextual_kw(T![asm]) {
p.bump_remap(T![asm]);
p.expect(T!['(']);
expr(p);
p.expect(T![')']);
Expand Down
90 changes: 0 additions & 90 deletions crates/parser/test_data/parser/inline/ok/0132_box_expr.rast

This file was deleted.

5 changes: 0 additions & 5 deletions crates/parser/test_data/parser/inline/ok/0132_box_expr.rs

This file was deleted.

2 changes: 1 addition & 1 deletion crates/syntax/rust.ungram
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ Expr =
| UnderscoreExpr

OffsetOfExpr =
Attr* 'builtin' '#' 'offset_of' '(' ')'
Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'

AsmExpr =
Attr* 'builtin' '#' 'asm' '(' ')'
Expand Down
3 changes: 3 additions & 0 deletions crates/syntax/src/ast/generated/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,9 @@ impl OffsetOfExpr {
support::token(&self.syntax, T![offset_of])
}
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
}

Expand Down
20 changes: 12 additions & 8 deletions crates/syntax/src/tests/sourcegen_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
}

fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
if lower_comma_list(acc, grammar, label, rule) {
if lower_seperated_list(acc, grammar, label, rule) {
return;
}

Expand Down Expand Up @@ -689,7 +689,7 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
}

// (T (',' T)* ','?)
fn lower_comma_list(
fn lower_seperated_list(
acc: &mut Vec<Field>,
grammar: &Grammar,
label: Option<&String>,
Expand All @@ -699,19 +699,23 @@ fn lower_comma_list(
Rule::Seq(it) => it,
_ => return false,
};
let (node, repeat, trailing_comma) = match rule.as_slice() {
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
(node, repeat, trailing_comma)
let (node, repeat, trailing_sep) = match rule.as_slice() {
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
(node, repeat, Some(trailing_sep))
}
[Rule::Node(node), Rule::Rep(repeat)] => (node, repeat, None),
_ => return false,
};
let repeat = match &**repeat {
Rule::Seq(it) => it,
_ => return false,
};
match repeat.as_slice() {
[comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
_ => return false,
if !matches!(
repeat.as_slice(),
[comma, Rule::Node(n)]
if trailing_sep.map_or(true, |it| comma == &**it) && n == node
) {
return false;
}
let ty = grammar[*node].name.clone();
let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
Expand Down

0 comments on commit 4127ed4

Please sign in to comment.