Skip to content

Commit

Permalink
Merge pull request #18821 from ChayimFriedman2/coerce-pointee
Browse files Browse the repository at this point in the history
feat: Support the new `CoercePointee` derive
  • Loading branch information
ChayimFriedman2 authored Jan 4, 2025
2 parents 061d257 + ce32362 commit 6725e04
Show file tree
Hide file tree
Showing 8 changed files with 768 additions and 64 deletions.
128 changes: 110 additions & 18 deletions crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use expect_test::expect;

use crate::macro_expansion_tests::check;
use crate::macro_expansion_tests::{check, check_errors};

#[test]
fn test_copy_expand_simple() {
Expand All @@ -16,7 +16,7 @@ struct Foo;
#[derive(Copy)]
struct Foo;
impl < > $crate::marker::Copy for Foo< > where {}"#]],
impl <> $crate::marker::Copy for Foo< > where {}"#]],
);
}

Expand All @@ -40,7 +40,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
impl < > $crate::marker::Copy for Foo< > where {}"#]],
impl <> $crate::marker::Copy for Foo< > where {}"#]],
);
}

Expand Down Expand Up @@ -225,14 +225,14 @@ enum Bar {
Bar,
}
impl < > $crate::default::Default for Foo< > where {
impl <> $crate::default::Default for Foo< > where {
fn default() -> Self {
Foo {
field1: $crate::default::Default::default(), field2: $crate::default::Default::default(),
}
}
}
impl < > $crate::default::Default for Bar< > where {
impl <> $crate::default::Default for Bar< > where {
fn default() -> Self {
Bar::Bar
}
Expand Down Expand Up @@ -260,7 +260,7 @@ enum Command {
Jump,
}
impl < > $crate::cmp::PartialEq for Command< > where {
impl <> $crate::cmp::PartialEq for Command< > where {
fn eq(&self , other: &Self ) -> bool {
match (self , other) {
(Command::Move {
Expand All @@ -273,7 +273,7 @@ impl < > $crate::cmp::PartialEq for Command< > where {
}
}
}
impl < > $crate::cmp::Eq for Command< > where {}"#]],
impl <> $crate::cmp::Eq for Command< > where {}"#]],
);
}

Expand All @@ -298,7 +298,7 @@ enum Command {
Jump,
}
impl < > $crate::cmp::PartialEq for Command< > where {
impl <> $crate::cmp::PartialEq for Command< > where {
fn eq(&self , other: &Self ) -> bool {
match (self , other) {
(Command::Move {
Expand All @@ -311,7 +311,7 @@ impl < > $crate::cmp::PartialEq for Command< > where {
}
}
}
impl < > $crate::cmp::Eq for Command< > where {}"#]],
impl <> $crate::cmp::Eq for Command< > where {}"#]],
);
}

Expand All @@ -335,7 +335,7 @@ enum Command {
Jump,
}
impl < > $crate::cmp::PartialOrd for Command< > where {
impl <> $crate::cmp::PartialOrd for Command< > where {
fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> {
match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) {
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
Expand Down Expand Up @@ -370,7 +370,7 @@ impl < > $crate::cmp::PartialOrd for Command< > where {
}
}
}
impl < > $crate::cmp::Ord for Command< > where {
impl <> $crate::cmp::Ord for Command< > where {
fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering {
match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) {
$crate::cmp::Ordering::Equal=> {
Expand Down Expand Up @@ -432,7 +432,7 @@ struct Foo {
z: (i32, u64),
}
impl < > $crate::hash::Hash for Foo< > where {
impl <> $crate::hash::Hash for Foo< > where {
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
match self {
Foo {
Expand Down Expand Up @@ -470,7 +470,7 @@ enum Command {
Jump,
}
impl < > $crate::hash::Hash for Command< > where {
impl <> $crate::hash::Hash for Command< > where {
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
$crate::mem::discriminant(self ).hash(ra_expand_state);
match self {
Expand Down Expand Up @@ -516,7 +516,7 @@ enum Command {
Jump,
}
impl < > $crate::fmt::Debug for Command< > where {
impl <> $crate::fmt::Debug for Command< > where {
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
match self {
Command::Move {
Expand Down Expand Up @@ -578,7 +578,7 @@ enum HideAndShowEnum {
}
}
impl < > $crate::fmt::Debug for HideAndShow< > where {
impl <> $crate::fmt::Debug for HideAndShow< > where {
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
match self {
HideAndShow {
Expand All @@ -588,7 +588,7 @@ impl < > $crate::fmt::Debug for HideAndShow< > where {
}
}
}
impl < > $crate::fmt::Debug for HideAndShowEnum< > where {
impl <> $crate::fmt::Debug for HideAndShowEnum< > where {
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
match self {
HideAndShowEnum::AlwaysShow {
Expand Down Expand Up @@ -640,17 +640,109 @@ enum Bar {
Bar,
}
impl < > $crate::default::Default for Foo< > where {
impl <> $crate::default::Default for Foo< > where {
fn default() -> Self {
Foo {
field1: $crate::default::Default::default(), field4: $crate::default::Default::default(),
}
}
}
impl < > $crate::default::Default for Bar< > where {
impl <> $crate::default::Default for Bar< > where {
fn default() -> Self {
Bar::Bar
}
}"##]],
);
}

#[test]
fn coerce_pointee_expansion() {
check(
r#"
//- minicore: coerce_pointee
use core::marker::CoercePointee;
pub trait Trait<T: ?Sized> {}
#[derive(CoercePointee)]
#[repr(transparent)]
pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
where
U: Trait<U> + ToString;"#,
expect![[r#"
use core::marker::CoercePointee;
pub trait Trait<T: ?Sized> {}
#[derive(CoercePointee)]
#[repr(transparent)]
pub struct Foo<'a, T: ?Sized + Trait<U>, #[pointee] U: ?Sized, const N: u32>(T)
where
U: Trait<U> + ToString;
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, {}
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, {}"#]],
);
}

#[test]
fn coerce_pointee_errors() {
check_errors(
r#"
//- minicore: coerce_pointee
use core::marker::CoercePointee;
#[derive(CoercePointee)]
enum Enum {}
#[derive(CoercePointee)]
struct Struct1;
#[derive(CoercePointee)]
struct Struct2();
#[derive(CoercePointee)]
struct Struct3 {}
#[derive(CoercePointee)]
struct Struct4<T: ?Sized>(T);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct5(i32);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct6<#[pointee] T: ?Sized, #[pointee] U: ?Sized>(T, U);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct7<T: ?Sized, U: ?Sized>(T, U);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct8<#[pointee] T, U: ?Sized>(T);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct9<T>(T);
#[derive(CoercePointee)]
#[repr(transparent)]
struct Struct9<#[pointee] T, U>(T) where T: ?Sized;
"#,
expect![[r#"
35..72: `CoercePointee` can only be derived on `struct`s
74..114: `CoercePointee` can only be derived on `struct`s with at least one field
116..158: `CoercePointee` can only be derived on `struct`s with at least one field
160..202: `CoercePointee` can only be derived on `struct`s with at least one field
204..258: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
260..326: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
328..439: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
441..530: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
532..621: `derive(CoercePointee)` requires `T` to be marked `?Sized`
623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]],
);
}
38 changes: 36 additions & 2 deletions crates/hir-def/src/macro_expansion_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ mod proc_macros;

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

use base_db::SourceDatabase;
use expect_test::Expect;
use hir_expand::{
db::ExpandDatabase,
proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind},
span_map::SpanMapRef,
InFile, MacroFileId, MacroFileIdExt,
InFile, MacroCallKind, MacroFileId, MacroFileIdExt,
};
use intern::Symbol;
use itertools::Itertools;
use span::{Edition, Span};
use stdx::{format_to, format_to_acc};
use syntax::{
Expand All @@ -44,6 +46,36 @@ use crate::{
AdtId, AsMacroCall, Lookup, ModuleDefId,
};

#[track_caller]
fn check_errors(ra_fixture: &str, expect: Expect) {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
let def_map = db.crate_def_map(krate);
let errors = def_map
.modules()
.flat_map(|module| module.1.scope.all_macro_calls())
.filter_map(|macro_call| {
let errors = db.parse_macro_expansion_error(macro_call)?;
let errors = errors.err.as_ref()?.render_to_string(&db);
let macro_loc = db.lookup_intern_macro_call(macro_call);
let ast_id = match macro_loc.kind {
MacroCallKind::FnLike { ast_id, .. } => ast_id.map(|it| it.erase()),
MacroCallKind::Derive { ast_id, .. } => ast_id.map(|it| it.erase()),
MacroCallKind::Attr { ast_id, .. } => ast_id.map(|it| it.erase()),
};
let ast = db
.parse(ast_id.file_id.file_id().expect("macros inside macros are not supported"))
.syntax_node();
let ast_id_map = db.ast_id_map(ast_id.file_id);
let node = ast_id_map.get_erased(ast_id.value).to_node(&ast);
Some((node.text_range(), errors))
})
.sorted_unstable_by_key(|(range, _)| range.start())
.format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}")))
.to_string();
expect.assert_eq(&errors);
}

#[track_caller]
fn check(ra_fixture: &str, mut expect: Expect) {
let extra_proc_macros = vec![(
Expand Down Expand Up @@ -245,7 +277,9 @@ fn pretty_print_macro_expansion(
let mut res = String::new();
let mut prev_kind = EOF;
let mut indent_level = 0;
for token in iter::successors(expn.first_token(), |t| t.next_token()) {
for token in iter::successors(expn.first_token(), |t| t.next_token())
.take_while(|token| token.text_range().start() < expn.text_range().end())
{
let curr_kind = token.kind();
let space = match (prev_kind, curr_kind) {
_ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
Expand Down
Loading

0 comments on commit 6725e04

Please sign in to comment.