Skip to content

Commit 1504830

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

File tree

17 files changed

+120
-193
lines changed

17 files changed

+120
-193
lines changed

Diff for: 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
}

Diff for: 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 ");

Diff for: 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);

Diff for: crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,22 @@ fn main() {
4242
}
4343
}
4444
"#,
45-
expect![[r#"
45+
expect![[r##"
4646
#[rustc_builtin_macro]
47-
macro_rules! column {() => {}}
47+
macro_rules! asm {() => {}}
4848
49-
fn main() { 0 as u32; }
50-
"#]],
49+
fn main() {
50+
let i: u64 = 3;
51+
let o: u64;
52+
unsafe {
53+
builtin #asm ( {
54+
$crate::format_args!("mov {0}, {1}");
55+
$crate::format_args!("add {0}, 5");
56+
}
57+
);
58+
}
59+
}
60+
"##]],
5161
);
5262
}
5363

Diff for: crates/hir-expand/src/builtin_fn_macro.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -419,9 +419,9 @@ fn asm_expand(
419419

420420
let pound = quote! {@PUNCT '#'};
421421
let expanded = quote! {
422-
builtin #pound asm {
423-
##literals
424-
}
422+
builtin #pound asm (
423+
{##literals}
424+
)
425425
};
426426
ExpandResult::ok(expanded)
427427
}

Diff for: 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);

Diff for: 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);

Diff for: 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);

Diff for: crates/hir-ty/src/mir/lower.rs

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

Diff for: crates/hir-ty/src/tests/simple.rs

+26-63
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,6 @@ use expect_test::expect;
22

33
use super::{check, check_infer, check_no_mismatches, check_types};
44

5-
#[test]
6-
fn infer_box() {
7-
check_types(
8-
r#"
9-
//- /main.rs crate:main deps:std
10-
fn test() {
11-
let x = box 1;
12-
let t = (x, box x, box &1, box [1]);
13-
t;
14-
} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
15-
16-
//- /std.rs crate:std
17-
#[prelude_import] use prelude::*;
18-
mod prelude {}
19-
20-
mod boxed {
21-
#[lang = "owned_box"]
22-
pub struct Box<T: ?Sized> {
23-
inner: *mut T,
24-
}
25-
}
26-
"#,
27-
);
28-
}
29-
30-
#[test]
31-
fn infer_box_with_allocator() {
32-
check_types(
33-
r#"
34-
//- /main.rs crate:main deps:std
35-
fn test() {
36-
let x = box 1;
37-
let t = (x, box x, box &1, box [1]);
38-
t;
39-
} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
40-
41-
//- /std.rs crate:std
42-
#[prelude_import] use prelude::*;
43-
mod boxed {
44-
#[lang = "owned_box"]
45-
pub struct Box<T: ?Sized, A: Allocator> {
46-
inner: *mut T,
47-
allocator: A,
48-
}
49-
}
50-
"#,
51-
);
52-
}
53-
545
#[test]
556
fn infer_adt_self() {
567
check_types(
@@ -2763,8 +2714,8 @@ impl<T> [T] {
27632714
}
27642715
27652716
fn test() {
2766-
let vec = <[_]>::into_vec(box [1i32]);
2767-
let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
2717+
let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32]));
2718+
let v: Vec<Box<dyn B>> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)]));
27682719
}
27692720
27702721
trait B{}
@@ -2774,20 +2725,20 @@ impl B for Astruct {}
27742725
expect![[r#"
27752726
604..608 'self': Box<[T], A>
27762727
637..669 '{ ... }': Vec<T, A>
2777-
683..796 '{ ...t]); }': ()
2728+
683..853 '{ ...])); }': ()
27782729
693..696 'vec': Vec<i32, Global>
27792730
699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
2780-
699..726 '<[_]>:...1i32])': Vec<i32, Global>
2781-
715..725 'box [1i32]': Box<[i32; 1], Global>
2782-
719..725 '[1i32]': [i32; 1]
2783-
720..724 '1i32': i32
2784-
736..737 'v': Vec<Box<dyn B, Global>, Global>
2785-
757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
2786-
757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
2787-
775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
2788-
779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
2789-
780..791 'box Astruct': Box<Astruct, Global>
2790-
784..791 'Astruct': Astruct
2731+
699..745 '<[_]>:...i32]))': Vec<i32, Global>
2732+
715..744 '#[rust...1i32])': Box<[i32; 1], Global>
2733+
737..743 '[1i32]': [i32; 1]
2734+
738..742 '1i32': i32
2735+
755..756 'v': Vec<Box<dyn B, Global>, Global>
2736+
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
2737+
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
2738+
794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
2739+
816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
2740+
817..847 '#[rust...truct)': Box<Astruct, Global>
2741+
839..846 'Astruct': Astruct
27912742
"#]],
27922743
)
27932744
}
@@ -3649,3 +3600,15 @@ fn main() {
36493600
"#,
36503601
);
36513602
}
3603+
3604+
#[test]
3605+
fn offset_of() {
3606+
check_types(
3607+
r#"
3608+
fn main() {
3609+
builtin#offset_of((,), 0);
3610+
// ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
3611+
}
3612+
"#,
3613+
);
3614+
}

Diff for: crates/hir-ty/src/tests/traits.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,16 @@ unsafe impl Allocator for Global {}
162162
163163
#[lang = "owned_box"]
164164
#[fundamental]
165-
pub struct Box<T: ?Sized, A: Allocator = Global>;
165+
pub struct Box<T: ?Sized, A: Allocator = Global>(T);
166166
167167
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
168168
169169
fn send() -> Box<dyn Future<Output = ()> + Send + 'static>{
170-
box async move {}
170+
Box(async move {})
171171
}
172172
173173
fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
174-
box async move {}
174+
Box(async move {})
175175
}
176176
"#,
177177
);
@@ -3057,7 +3057,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
30573057
30583058
fn foo() {
30593059
let s = None;
3060-
let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
3060+
let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) };
30613061
f(&s);
30623062
}"#,
30633063
expect![[r#"
@@ -3068,19 +3068,19 @@ fn foo() {
30683068
186..197 '*self.inner': T
30693069
187..191 'self': &Box<T>
30703070
187..197 'self.inner': *mut T
3071-
218..308 '{ ...&s); }': ()
3071+
218..324 '{ ...&s); }': ()
30723072
228..229 's': Option<i32>
30733073
232..236 'None': Option<i32>
30743074
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
3075-
281..294 'box (|ps| {})': Box<impl Fn(&Option<i32>)>
3076-
286..293 '|ps| {}': impl Fn(&Option<i32>)
3077-
287..289 'ps': &Option<i32>
3078-
291..293 '{}': ()
3079-
300..301 'f': Box<dyn FnOnce(&Option<i32>)>
3080-
300..305 'f(&s)': ()
3081-
302..304 '&s': &Option<i32>
3082-
303..304 's': Option<i32>
3083-
281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<impl Fn(&Option<i32>)>
3075+
281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
3076+
294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
3077+
300..307 '|ps| {}': impl Fn(&Option<i32>)
3078+
301..303 'ps': &Option<i32>
3079+
305..307 '{}': ()
3080+
316..317 'f': Box<dyn FnOnce(&Option<i32>)>
3081+
316..321 'f(&s)': ()
3082+
318..320 '&s': &Option<i32>
3083+
319..320 's': Option<i32>
30843084
"#]],
30853085
);
30863086
}

Diff for: 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![')']);

0 commit comments

Comments
 (0)