Skip to content

Commit 58003af

Browse files
committed
Implement offset_of in hir-def and hir-ty
1 parent 9b8eb80 commit 58003af

File tree

15 files changed

+78
-109
lines changed

15 files changed

+78
-109
lines changed

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131
hir::{
3232
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
3333
ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
34-
Pat, PatId, RecordFieldPat, RecordLitField, Statement,
34+
OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
3535
},
3636
item_scope::BuiltinShadowMode,
3737
lang_item::LangItem,
@@ -649,7 +649,11 @@ impl ExprCollector<'_> {
649649
}
650650
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
651651
ast::Expr::AsmExpr(_) => self.missing_expr(),
652-
ast::Expr::OffsetOfExpr(_) => self.missing_expr(),
652+
ast::Expr::OffsetOfExpr(e) => {
653+
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
654+
let fields = e.fields().map(|it| it.as_name()).collect();
655+
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
656+
}
653657
ast::Expr::FormatArgsExpr(_) => self.missing_expr(),
654658
})
655659
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::fmt::{self, Write};
44

55
use hir_expand::db::ExpandDatabase;
6+
use itertools::Itertools;
67
use syntax::ast::HasName;
78

89
use crate::{
@@ -154,6 +155,15 @@ impl Printer<'_> {
154155
match expr {
155156
Expr::Missing => w!(self, "�"),
156157
Expr::Underscore => w!(self, "_"),
158+
Expr::OffsetOf(offset_of) => {
159+
w!(self, "builtin#offset_of!(");
160+
self.print_type_ref(&offset_of.container);
161+
w!(
162+
self,
163+
", {})",
164+
offset_of.fields.iter().format_with(".", |field, f| f(&field.display(self.db)))
165+
);
166+
}
157167
Expr::Path(path) => self.print_path(path),
158168
Expr::If { condition, then_branch, else_branch } => {
159169
w!(self, "if ");

crates/hir-def/src/hir.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ pub enum Expr {
281281
Array(Array),
282282
Literal(Literal),
283283
Underscore,
284+
OffsetOf(OffsetOf),
285+
}
286+
287+
#[derive(Debug, Clone, PartialEq, Eq)]
288+
pub struct OffsetOf {
289+
pub container: Interned<TypeRef>,
290+
pub fields: Box<[Name]>,
284291
}
285292

286293
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -341,7 +348,7 @@ impl Expr {
341348
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
342349
match self {
343350
Expr::Missing => {}
344-
Expr::Path(_) => {}
351+
Expr::Path(_) | Expr::OffsetOf(_) => {}
345352
Expr::If { condition, then_branch, else_branch } => {
346353
f(*condition);
347354
f(*then_branch);

crates/hir-ty/src/infer/closure.rs

+1
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ impl InferenceContext<'_> {
452452

453453
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
454454
match &self.body[tgt_expr] {
455+
Expr::OffsetOf(_) => (),
455456
Expr::If { condition, then_branch, else_branch } => {
456457
self.consume_expr(*condition);
457458
self.consume_expr(*then_branch);

crates/hir-ty/src/infer/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ impl InferenceContext<'_> {
843843
});
844844
expected
845845
}
846+
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
846847
};
847848
// use a new type variable if we got unknown here
848849
let ty = self.insert_type_vars_shallow(ty);

crates/hir-ty/src/infer/mutability.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl InferenceContext<'_> {
3535
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
3636
match &self.body[tgt_expr] {
3737
Expr::Missing => (),
38+
Expr::OffsetOf(_) => (),
3839
&Expr::If { condition, then_branch, else_branch } => {
3940
self.infer_mut_expr(condition, Mutability::Not);
4041
self.infer_mut_expr(then_branch, Mutability::Not);

crates/hir-ty/src/mir/lower.rs

+1
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
370370
mut current: BasicBlockId,
371371
) -> Result<Option<BasicBlockId>> {
372372
match &self.body.exprs[expr_id] {
373+
Expr::OffsetOf(_) => not_supported!("builtin#offset_of"),
373374
Expr::Missing => {
374375
if let DefWithBodyId::FunctionId(f) = self.owner {
375376
let assoc = f.lookup(self.db.upcast());

crates/hir-ty/src/tests/simple.rs

+12
Original file line numberDiff line numberDiff line change
@@ -3649,3 +3649,15 @@ fn main() {
36493649
"#,
36503650
);
36513651
}
3652+
3653+
#[test]
3654+
fn offset_of() {
3655+
check_types(
3656+
r#"
3657+
fn main() {
3658+
builtin#offset_of((,), 0);
3659+
// ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
3660+
}
3661+
"#,
3662+
);
3663+
}

crates/parser/src/grammar/expressions/atom.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -220,24 +220,39 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
220220
// fn foo() {
221221
// builtin#asm(0);
222222
// builtin#format_args(0);
223-
// builtin#builtin(0);
223+
// builtin#offset_of(Foo, bar.baz.0);
224224
// }
225225
fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
226226
let m = p.start();
227227
p.bump_remap(T![builtin]);
228228
p.bump(T![#]);
229229
if p.at_contextual_kw(T![offset_of]) {
230+
p.bump_remap(T![offset_of]);
230231
p.expect(T!['(']);
231232
type_(p);
232-
p.bump(T![,]);
233+
p.expect(T![,]);
234+
while !p.at(EOF) && !p.at(T![')']) {
235+
if p.at(IDENT) || p.at(INT_NUMBER) {
236+
name_ref_or_index(p);
237+
// } else if p.at(FLOAT_NUMBER) {
238+
// FIXME: needs float hack
239+
} else {
240+
p.err_and_bump("expected field name or number");
241+
}
242+
if !p.at(T![')']) {
243+
p.expect(T![.]);
244+
}
245+
}
233246
p.expect(T![')']);
234247
Some(m.complete(p, OFFSET_OF_EXPR))
235248
} else if p.at_contextual_kw(T![format_args]) {
249+
p.bump_remap(T![format_args]);
236250
p.expect(T!['(']);
237251
expr(p);
238252
p.expect(T![')']);
239253
Some(m.complete(p, FORMAT_ARGS_EXPR))
240254
} else if p.at_contextual_kw(T![asm]) {
255+
p.bump_remap(T![asm]);
241256
p.expect(T!['(']);
242257
expr(p);
243258
p.expect(T![')']);

crates/parser/test_data/parser/inline/ok/0132_box_expr.rast

-90
This file was deleted.

crates/parser/test_data/parser/inline/ok/0132_box_expr.rs

-5
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn foo() {
2+
builtin#asm(0);
3+
builtin#format_args(0);
4+
builtin#offset_of(Foo, bar.baz.0);
5+
}

crates/syntax/rust.ungram

+1-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ Expr =
376376
| UnderscoreExpr
377377

378378
OffsetOfExpr =
379-
Attr* 'builtin' '#' 'offset_of' '(' ')'
379+
Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'
380380

381381
AsmExpr =
382382
Attr* 'builtin' '#' 'asm' '(' ')'

crates/syntax/src/ast/generated/nodes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,9 @@ impl OffsetOfExpr {
10141014
support::token(&self.syntax, T![offset_of])
10151015
}
10161016
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
1017+
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
1018+
pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
1019+
pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
10171020
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
10181021
}
10191022

crates/syntax/src/tests/sourcegen_ast.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
623623
}
624624

625625
fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
626-
if lower_comma_list(acc, grammar, label, rule) {
626+
if lower_seperated_list(acc, grammar, label, rule) {
627627
return;
628628
}
629629

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

691691
// (T (',' T)* ','?)
692-
fn lower_comma_list(
692+
fn lower_seperated_list(
693693
acc: &mut Vec<Field>,
694694
grammar: &Grammar,
695695
label: Option<&String>,
@@ -699,19 +699,23 @@ fn lower_comma_list(
699699
Rule::Seq(it) => it,
700700
_ => return false,
701701
};
702-
let (node, repeat, trailing_comma) = match rule.as_slice() {
703-
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
704-
(node, repeat, trailing_comma)
702+
let (node, repeat, trailing_sep) = match rule.as_slice() {
703+
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
704+
(node, repeat, Some(trailing_sep))
705705
}
706+
[Rule::Node(node), Rule::Rep(repeat)] => (node, repeat, None),
706707
_ => return false,
707708
};
708709
let repeat = match &**repeat {
709710
Rule::Seq(it) => it,
710711
_ => return false,
711712
};
712-
match repeat.as_slice() {
713-
[comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
714-
_ => return false,
713+
if !matches!(
714+
repeat.as_slice(),
715+
[comma, Rule::Node(n)]
716+
if trailing_sep.map_or(true, |it| comma == &**it) && n == node
717+
) {
718+
return false;
715719
}
716720
let ty = grammar[*node].name.clone();
717721
let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));

0 commit comments

Comments
 (0)