From 1776b7898633e7a845c6aaaecba7eba39a67e399 Mon Sep 17 00:00:00 2001 From: zohnannor Date: Thu, 7 Aug 2025 20:23:42 +0300 Subject: [PATCH] Support phantom types inside a method body --- src/lib.rs | 22 +++++++++++++--------- tests/function-body.rs | 6 ++++++ tests/ui/autotraits.stderr | 4 ++-- tests/ui/ffi.stderr | 2 +- tests/ui/function-body.rs | 8 -------- tests/ui/invariant.stderr | 8 ++++---- tests/ui/pattern-match.stderr | 20 ++++++++++---------- 7 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 tests/function-body.rs delete mode 100644 tests/ui/function-body.rs diff --git a/src/lib.rs b/src/lib.rs index 03479e7..60f8e9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,7 +251,7 @@ pub fn phantom(args: TokenStream, input: TokenStream) -> TokenStream { let ident = &input.ident; let call_site = Span::call_site(); let void_namespace = Ident::new(&format!("__void_{}", ident), call_site); - let value_namespace = Ident::new(&format!("__value_{}", ident), call_site); + let fake_ident = Ident::new(&format!("{}__Phantom", ident), ident.span()); let vis = &input.vis; let vis_super = visibility::vis_super(vis); @@ -296,7 +296,11 @@ pub fn phantom(args: TokenStream, input: TokenStream) -> TokenStream { ty_generics.push(quote!(#lifetime)); phantoms.push(variance::apply(param, elem, &type_param)); } - GenericParam::Const(_) => {} + GenericParam::Const(param) => { + let ident = ¶m.ident; + impl_generics.push(quote!(#param)); + ty_generics.push(quote!(#ident)); + } } } @@ -355,19 +359,19 @@ pub fn phantom(args: TokenStream, input: TokenStream) -> TokenStream { } } - mod #value_namespace { - #[doc(hidden)] - #vis_super use super::#ident::#ident; - } - + #[doc(hidden)] + #[allow(non_camel_case_types)] #(#attrs)* - #vis #enum_token #ident #generics #where_clause { + #vis #enum_token #fake_ident #generics #where_clause { __Phantom(#void_namespace::#ident <#(#ty_generics),*>), #ident, } #[doc(hidden)] - #vis use self::#value_namespace::*; + #vis use #fake_ident::*; + + #[allow(unused_imports, type_alias_bounds)] + #vis type #ident #generics #where_clause = #fake_ident <#(#ty_generics),*>; #derives }) diff --git a/tests/function-body.rs b/tests/function-body.rs new file mode 100644 index 0000000..32a730d --- /dev/null +++ b/tests/function-body.rs @@ -0,0 +1,6 @@ +use ghost::phantom; + +const fn main() { + #[phantom] + struct MyPhantom; +} diff --git a/tests/ui/autotraits.stderr b/tests/ui/autotraits.stderr index 1f3174d..d3da58e 100644 --- a/tests/ui/autotraits.stderr +++ b/tests/ui/autotraits.stderr @@ -15,7 +15,7 @@ note: required because it appears within the type `__void_MyPhantom::MyPhantom<* | 4 | struct MyPhantom; | ^^^^^^^^^ -note: required because it appears within the type `MyPhantom<*const u8>` +note: required because it appears within the type `MyPhantom__Phantom<*const u8>` --> tests/ui/autotraits.rs:4:8 | 4 | struct MyPhantom; @@ -44,7 +44,7 @@ note: required because it appears within the type `__void_MyPhantom::MyPhantom<* | 4 | struct MyPhantom; | ^^^^^^^^^ -note: required because it appears within the type `MyPhantom<*const u8>` +note: required because it appears within the type `MyPhantom__Phantom<*const u8>` --> tests/ui/autotraits.rs:4:8 | 4 | struct MyPhantom; diff --git a/tests/ui/ffi.stderr b/tests/ui/ffi.stderr index c555316..98eabf9 100644 --- a/tests/ui/ffi.stderr +++ b/tests/ui/ffi.stderr @@ -1,4 +1,4 @@ -error: `extern` fn uses type `MyPhantom`, which is not FFI-safe +error: `extern` fn uses type `MyPhantom__Phantom`, which is not FFI-safe --> tests/ui/ffi.rs:8:39 | 8 | pub extern "C" fn extern_fn(_phantom: MyPhantom) {} diff --git a/tests/ui/function-body.rs b/tests/ui/function-body.rs deleted file mode 100644 index 6fcd7c2..0000000 --- a/tests/ui/function-body.rs +++ /dev/null @@ -1,8 +0,0 @@ -use ghost::phantom; - -fn main() { - // Not supported. https://github.com/dtolnay/ghost/issues/1 - - #[phantom] - struct MyPhantom; -} diff --git a/tests/ui/invariant.stderr b/tests/ui/invariant.stderr index 5689025..849157b 100644 --- a/tests/ui/invariant.stderr +++ b/tests/ui/invariant.stderr @@ -6,8 +6,8 @@ error: lifetime may not live long enough 7 | phantom | ^^^^^^^ returning this value requires that `'a` must outlive `'static` | - = note: requirement occurs because of the type `InvariantPhantom<&str>`, which makes the generic argument `&str` invariant - = note: the enum `InvariantPhantom` is invariant over the parameter `T` + = note: requirement occurs because of the type `InvariantPhantom__Phantom<&str>`, which makes the generic argument `&str` invariant + = note: the enum `InvariantPhantom__Phantom` is invariant over the parameter `T` = help: see for more information about variance error: lifetime may not live long enough @@ -18,6 +18,6 @@ error: lifetime may not live long enough 11 | phantom | ^^^^^^^ returning this value requires that `'a` must outlive `'static` | - = note: requirement occurs because of the type `InvariantPhantom<&str>`, which makes the generic argument `&str` invariant - = note: the enum `InvariantPhantom` is invariant over the parameter `T` + = note: requirement occurs because of the type `InvariantPhantom__Phantom<&str>`, which makes the generic argument `&str` invariant + = note: the enum `InvariantPhantom__Phantom` is invariant over the parameter `T` = help: see for more information about variance diff --git a/tests/ui/pattern-match.stderr b/tests/ui/pattern-match.stderr index c437d5a..1835540 100644 --- a/tests/ui/pattern-match.stderr +++ b/tests/ui/pattern-match.stderr @@ -1,39 +1,39 @@ -error[E0004]: non-exhaustive patterns: `MyPhantom::__Phantom(_)` not covered +error[E0004]: non-exhaustive patterns: `MyPhantom__Phantom::__Phantom(_)` not covered --> tests/ui/pattern-match.rs:9:11 | 9 | match phantom { - | ^^^^^^^ pattern `MyPhantom::__Phantom(_)` not covered + | ^^^^^^^ pattern `MyPhantom__Phantom::__Phantom(_)` not covered | -note: `MyPhantom` defined here +note: `MyPhantom__Phantom` defined here --> tests/ui/pattern-match.rs:4:8 | 3 | #[phantom] | ---------- not covered 4 | struct MyPhantom; | ^^^^^^^^^ - = note: the matched value is of type `MyPhantom` + = note: the matched value is of type `MyPhantom__Phantom` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 10~ MyPhantom => {}, -11+ MyPhantom::__Phantom(_) => todo!() +11+ MyPhantom__Phantom::__Phantom(_) => todo!() | -error[E0004]: non-exhaustive patterns: `MyPhantom::__Phantom(_)` not covered +error[E0004]: non-exhaustive patterns: `MyPhantom__Phantom::__Phantom(_)` not covered --> tests/ui/pattern-match.rs:13:11 | 13 | match phantom { - | ^^^^^^^ pattern `MyPhantom::__Phantom(_)` not covered + | ^^^^^^^ pattern `MyPhantom__Phantom::__Phantom(_)` not covered | -note: `MyPhantom` defined here +note: `MyPhantom__Phantom` defined here --> tests/ui/pattern-match.rs:4:8 | 3 | #[phantom] | ---------- not covered 4 | struct MyPhantom; | ^^^^^^^^^ - = note: the matched value is of type `MyPhantom` + = note: the matched value is of type `MyPhantom__Phantom` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 14 ~ MyPhantom:: => {}, -15 + MyPhantom::__Phantom(_) => todo!() +15 + MyPhantom__Phantom::__Phantom(_) => todo!() |