Skip to content

Commit 7393621

Browse files
Merge pull request #18821 from ChayimFriedman2/coerce-pointee
feat: Support the new `CoercePointee` derive
2 parents c635d7e + 2a84711 commit 7393621

File tree

8 files changed

+768
-64
lines changed

8 files changed

+768
-64
lines changed

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use expect_test::expect;
44

5-
use crate::macro_expansion_tests::check;
5+
use crate::macro_expansion_tests::{check, check_errors};
66

77
#[test]
88
fn test_copy_expand_simple() {
@@ -16,7 +16,7 @@ struct Foo;
1616
#[derive(Copy)]
1717
struct Foo;
1818
19-
impl < > $crate::marker::Copy for Foo< > where {}"#]],
19+
impl <> $crate::marker::Copy for Foo< > where {}"#]],
2020
);
2121
}
2222

@@ -40,7 +40,7 @@ macro Copy {}
4040
#[derive(Copy)]
4141
struct Foo;
4242
43-
impl < > $crate::marker::Copy for Foo< > where {}"#]],
43+
impl <> $crate::marker::Copy for Foo< > where {}"#]],
4444
);
4545
}
4646

@@ -225,14 +225,14 @@ enum Bar {
225225
Bar,
226226
}
227227
228-
impl < > $crate::default::Default for Foo< > where {
228+
impl <> $crate::default::Default for Foo< > where {
229229
fn default() -> Self {
230230
Foo {
231231
field1: $crate::default::Default::default(), field2: $crate::default::Default::default(),
232232
}
233233
}
234234
}
235-
impl < > $crate::default::Default for Bar< > where {
235+
impl <> $crate::default::Default for Bar< > where {
236236
fn default() -> Self {
237237
Bar::Bar
238238
}
@@ -260,7 +260,7 @@ enum Command {
260260
Jump,
261261
}
262262
263-
impl < > $crate::cmp::PartialEq for Command< > where {
263+
impl <> $crate::cmp::PartialEq for Command< > where {
264264
fn eq(&self , other: &Self ) -> bool {
265265
match (self , other) {
266266
(Command::Move {
@@ -273,7 +273,7 @@ impl < > $crate::cmp::PartialEq for Command< > where {
273273
}
274274
}
275275
}
276-
impl < > $crate::cmp::Eq for Command< > where {}"#]],
276+
impl <> $crate::cmp::Eq for Command< > where {}"#]],
277277
);
278278
}
279279

@@ -298,7 +298,7 @@ enum Command {
298298
Jump,
299299
}
300300
301-
impl < > $crate::cmp::PartialEq for Command< > where {
301+
impl <> $crate::cmp::PartialEq for Command< > where {
302302
fn eq(&self , other: &Self ) -> bool {
303303
match (self , other) {
304304
(Command::Move {
@@ -311,7 +311,7 @@ impl < > $crate::cmp::PartialEq for Command< > where {
311311
}
312312
}
313313
}
314-
impl < > $crate::cmp::Eq for Command< > where {}"#]],
314+
impl <> $crate::cmp::Eq for Command< > where {}"#]],
315315
);
316316
}
317317

@@ -335,7 +335,7 @@ enum Command {
335335
Jump,
336336
}
337337
338-
impl < > $crate::cmp::PartialOrd for Command< > where {
338+
impl <> $crate::cmp::PartialOrd for Command< > where {
339339
fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> {
340340
match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) {
341341
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
@@ -370,7 +370,7 @@ impl < > $crate::cmp::PartialOrd for Command< > where {
370370
}
371371
}
372372
}
373-
impl < > $crate::cmp::Ord for Command< > where {
373+
impl <> $crate::cmp::Ord for Command< > where {
374374
fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering {
375375
match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) {
376376
$crate::cmp::Ordering::Equal=> {
@@ -432,7 +432,7 @@ struct Foo {
432432
z: (i32, u64),
433433
}
434434
435-
impl < > $crate::hash::Hash for Foo< > where {
435+
impl <> $crate::hash::Hash for Foo< > where {
436436
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
437437
match self {
438438
Foo {
@@ -470,7 +470,7 @@ enum Command {
470470
Jump,
471471
}
472472
473-
impl < > $crate::hash::Hash for Command< > where {
473+
impl <> $crate::hash::Hash for Command< > where {
474474
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
475475
$crate::mem::discriminant(self ).hash(ra_expand_state);
476476
match self {
@@ -516,7 +516,7 @@ enum Command {
516516
Jump,
517517
}
518518
519-
impl < > $crate::fmt::Debug for Command< > where {
519+
impl <> $crate::fmt::Debug for Command< > where {
520520
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
521521
match self {
522522
Command::Move {
@@ -578,7 +578,7 @@ enum HideAndShowEnum {
578578
}
579579
}
580580
581-
impl < > $crate::fmt::Debug for HideAndShow< > where {
581+
impl <> $crate::fmt::Debug for HideAndShow< > where {
582582
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
583583
match self {
584584
HideAndShow {
@@ -588,7 +588,7 @@ impl < > $crate::fmt::Debug for HideAndShow< > where {
588588
}
589589
}
590590
}
591-
impl < > $crate::fmt::Debug for HideAndShowEnum< > where {
591+
impl <> $crate::fmt::Debug for HideAndShowEnum< > where {
592592
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
593593
match self {
594594
HideAndShowEnum::AlwaysShow {
@@ -640,17 +640,109 @@ enum Bar {
640640
Bar,
641641
}
642642
643-
impl < > $crate::default::Default for Foo< > where {
643+
impl <> $crate::default::Default for Foo< > where {
644644
fn default() -> Self {
645645
Foo {
646646
field1: $crate::default::Default::default(), field4: $crate::default::Default::default(),
647647
}
648648
}
649649
}
650-
impl < > $crate::default::Default for Bar< > where {
650+
impl <> $crate::default::Default for Bar< > where {
651651
fn default() -> Self {
652652
Bar::Bar
653653
}
654654
}"##]],
655655
);
656656
}
657+
658+
#[test]
659+
fn coerce_pointee_expansion() {
660+
check(
661+
r#"
662+
//- minicore: coerce_pointee
663+
664+
use core::marker::CoercePointee;
665+
666+
pub trait Trait<T: ?Sized> {}
667+
668+
#[derive(CoercePointee)]
669+
#[repr(transparent)]
670+
pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
671+
where
672+
U: Trait<U> + ToString;"#,
673+
expect![[r#"
674+
675+
use core::marker::CoercePointee;
676+
677+
pub trait Trait<T: ?Sized> {}
678+
679+
#[derive(CoercePointee)]
680+
#[repr(transparent)]
681+
pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
682+
where
683+
U: Trait<U> + ToString;
684+
impl <T, U, const N: u32, __S> $crate::ops::DispatchFromDyn<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, U:?Sized, {}
685+
impl <T, U, const N: u32, __S> $crate::ops::CoerceUnsized<Foo<'a, T, __S, N>> for Foo<T, U, N, > where U: Trait<U> +ToString, T: Trait<__S>, __S: ?Sized, __S: Trait<__S> +ToString, U: ::core::marker::Unsize<__S>, T:?Sized+Trait<U>, U:?Sized, {}"#]],
686+
);
687+
}
688+
689+
#[test]
690+
fn coerce_pointee_errors() {
691+
check_errors(
692+
r#"
693+
//- minicore: coerce_pointee
694+
695+
use core::marker::CoercePointee;
696+
697+
#[derive(CoercePointee)]
698+
enum Enum {}
699+
700+
#[derive(CoercePointee)]
701+
struct Struct1;
702+
703+
#[derive(CoercePointee)]
704+
struct Struct2();
705+
706+
#[derive(CoercePointee)]
707+
struct Struct3 {}
708+
709+
#[derive(CoercePointee)]
710+
struct Struct4<T: ?Sized>(T);
711+
712+
#[derive(CoercePointee)]
713+
#[repr(transparent)]
714+
struct Struct5(i32);
715+
716+
#[derive(CoercePointee)]
717+
#[repr(transparent)]
718+
struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U);
719+
720+
#[derive(CoercePointee)]
721+
#[repr(transparent)]
722+
struct Struct7<T: ?Sized, U: ?Sized>(T, U);
723+
724+
#[derive(CoercePointee)]
725+
#[repr(transparent)]
726+
struct Struct8<#[pointee] T, U: ?Sized>(T);
727+
728+
#[derive(CoercePointee)]
729+
#[repr(transparent)]
730+
struct Struct9<T>(T);
731+
732+
#[derive(CoercePointee)]
733+
#[repr(transparent)]
734+
struct Struct9<#[pointee] T, U>(T) where T: ?Sized;
735+
"#,
736+
expect![[r#"
737+
35..72: `CoercePointee` can only be derived on `struct`s
738+
74..114: `CoercePointee` can only be derived on `struct`s with at least one field
739+
116..158: `CoercePointee` can only be derived on `struct`s with at least one field
740+
160..202: `CoercePointee` can only be derived on `struct`s with at least one field
741+
204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
742+
260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
743+
328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
744+
441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
745+
532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized`
746+
623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]],
747+
);
748+
}

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ mod proc_macros;
1616

1717
use std::{iter, ops::Range, sync};
1818

19+
use base_db::SourceDatabase;
1920
use expect_test::Expect;
2021
use hir_expand::{
2122
db::ExpandDatabase,
2223
proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind},
2324
span_map::SpanMapRef,
24-
InFile, MacroFileId, MacroFileIdExt,
25+
InFile, MacroCallKind, MacroFileId, MacroFileIdExt,
2526
};
2627
use intern::Symbol;
28+
use itertools::Itertools;
2729
use span::{Edition, Span};
2830
use stdx::{format_to, format_to_acc};
2931
use syntax::{
@@ -44,6 +46,36 @@ use crate::{
4446
AdtId, AsMacroCall, Lookup, ModuleDefId,
4547
};
4648

49+
#[track_caller]
50+
fn check_errors(ra_fixture: &str, expect: Expect) {
51+
let db = TestDB::with_files(ra_fixture);
52+
let krate = db.fetch_test_crate();
53+
let def_map = db.crate_def_map(krate);
54+
let errors = def_map
55+
.modules()
56+
.flat_map(|module| module.1.scope.all_macro_calls())
57+
.filter_map(|macro_call| {
58+
let errors = db.parse_macro_expansion_error(macro_call)?;
59+
let errors = errors.err.as_ref()?.render_to_string(&db);
60+
let macro_loc = db.lookup_intern_macro_call(macro_call);
61+
let ast_id = match macro_loc.kind {
62+
MacroCallKind::FnLike { ast_id, .. } => ast_id.map(|it| it.erase()),
63+
MacroCallKind::Derive { ast_id, .. } => ast_id.map(|it| it.erase()),
64+
MacroCallKind::Attr { ast_id, .. } => ast_id.map(|it| it.erase()),
65+
};
66+
let ast = db
67+
.parse(ast_id.file_id.file_id().expect("macros inside macros are not supported"))
68+
.syntax_node();
69+
let ast_id_map = db.ast_id_map(ast_id.file_id);
70+
let node = ast_id_map.get_erased(ast_id.value).to_node(&ast);
71+
Some((node.text_range(), errors))
72+
})
73+
.sorted_unstable_by_key(|(range, _)| range.start())
74+
.format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}")))
75+
.to_string();
76+
expect.assert_eq(&errors);
77+
}
78+
4779
#[track_caller]
4880
fn check(ra_fixture: &str, mut expect: Expect) {
4981
let extra_proc_macros = vec![(
@@ -245,7 +277,9 @@ fn pretty_print_macro_expansion(
245277
let mut res = String::new();
246278
let mut prev_kind = EOF;
247279
let mut indent_level = 0;
248-
for token in iter::successors(expn.first_token(), |t| t.next_token()) {
280+
for token in iter::successors(expn.first_token(), |t| t.next_token())
281+
.take_while(|token| token.text_range().start() < expn.text_range().end())
282+
{
249283
let curr_kind = token.kind();
250284
let space = match (prev_kind, curr_kind) {
251285
_ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",

0 commit comments

Comments
 (0)