Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further improve slice typecheck #84

Merged
merged 2 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 3 additions & 47 deletions impl/src/declaration.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use crate::{attr, linker};
use crate::{attr, linker, ty};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{
bracketed, Attribute, Error, GenericArgument, Ident, Lifetime, PathArguments, Token, Type,
Visibility,
};
use syn::{bracketed, Attribute, Error, Ident, Token, Type, Visibility};

struct Declaration {
attrs: Vec<Attribute>,
Expand Down Expand Up @@ -69,7 +66,7 @@ pub fn expand(input: TokenStream) -> TokenStream {
Err(err) => return err.to_compile_error(),
};

populate_static_lifetimes(&mut ty);
ty::populate_static_lifetimes(&mut ty);

let used = if cfg!(feature = "used_linker") {
quote!(#[used(linker)])
Expand Down Expand Up @@ -266,44 +263,3 @@ pub fn expand(input: TokenStream) -> TokenStream {
#vis use #link_section_macro as #ident;
}
}

fn populate_static_lifetimes(ty: &mut Type) {
match ty {
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
Type::Array(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Group(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Paren(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Path(ty) => {
if let Some(qself) = &mut ty.qself {
populate_static_lifetimes(&mut qself.ty);
}
for segment in &mut ty.path.segments {
if let PathArguments::AngleBracketed(segment) = &mut segment.arguments {
for arg in &mut segment.args {
if let GenericArgument::Type(arg) = arg {
populate_static_lifetimes(arg);
}
}
}
}
}
Type::Ptr(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Reference(ty) => {
if ty.lifetime.is_none() {
ty.lifetime = Some(Lifetime::new("'static", ty.and_token.span));
}
populate_static_lifetimes(&mut ty.elem);
}
Type::Slice(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Tuple(ty) => ty.elems.iter_mut().for_each(populate_static_lifetimes),
Type::ImplTrait(_)
| Type::Infer(_)
| Type::Macro(_)
| Type::Never(_)
| Type::TraitObject(_)
| Type::BareFn(_)
| Type::Verbatim(_) => {}

_ => unimplemented!("unknown Type"),
}
}
14 changes: 8 additions & 6 deletions impl/src/element.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::attr;
use crate::{attr, ty};
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use syn::parse::{Error, Parse, ParseStream, Result};
Expand Down Expand Up @@ -204,19 +204,21 @@ fn do_expand(path: Path, pos: Option<usize>, input: Element) -> TokenStream {
let mut attrs = input.attrs;
let vis = input.vis;
let ident = input.ident;
let ty = input.ty;
let mut ty = input.ty;
let expr = input.expr;
let orig_item = input.orig_item;

ty::populate_static_lifetimes(&mut ty);

let linkme_path = match attr::linkme_path(&mut attrs) {
Ok(path) => path,
Err(err) => return err.to_compile_error(),
};

let sort_key = pos.into_iter().map(|pos| format!("{:04}", pos));

let new = quote_spanned!(input.start_span=> __new);
let uninit = quote_spanned!(input.end_span=> #new());
let factory = quote_spanned!(input.start_span=> __new);
let get = quote_spanned!(input.end_span=> #factory());

quote! {
#path ! {
Expand All @@ -228,9 +230,9 @@ fn do_expand(path: Path, pos: Option<usize>, input: Element) -> TokenStream {
#vis static #ident : #ty = {
#[allow(clippy::no_effect_underscore_binding)]
unsafe fn __typecheck(_: #linkme_path::__private::Void) {
let #new = || (|| &#ident) as fn() -> _;
let #factory = || -> fn() -> &'static #ty { || &#ident };
unsafe {
#linkme_path::DistributedSlice::private_typecheck(#path, #uninit);
#linkme_path::DistributedSlice::private_typecheck(#path, #get);
}
}

Expand Down
1 change: 1 addition & 0 deletions impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod declaration;
mod element;
mod hash;
mod linker;
mod ty;

use crate::args::Args;
use crate::hash::hash;
Expand Down
42 changes: 42 additions & 0 deletions impl/src/ty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use syn::{GenericArgument, Lifetime, PathArguments, Type};

pub(crate) fn populate_static_lifetimes(ty: &mut Type) {
match ty {
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
Type::Array(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Group(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Paren(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Path(ty) => {
if let Some(qself) = &mut ty.qself {
populate_static_lifetimes(&mut qself.ty);
}
for segment in &mut ty.path.segments {
if let PathArguments::AngleBracketed(segment) = &mut segment.arguments {
for arg in &mut segment.args {
if let GenericArgument::Type(arg) = arg {
populate_static_lifetimes(arg);
}
}
}
}
}
Type::Ptr(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Reference(ty) => {
if ty.lifetime.is_none() {
ty.lifetime = Some(Lifetime::new("'static", ty.and_token.span));
}
populate_static_lifetimes(&mut ty.elem);
}
Type::Slice(ty) => populate_static_lifetimes(&mut ty.elem),
Type::Tuple(ty) => ty.elems.iter_mut().for_each(populate_static_lifetimes),
Type::ImplTrait(_)
| Type::Infer(_)
| Type::Macro(_)
| Type::Never(_)
| Type::TraitObject(_)
| Type::BareFn(_)
| Type::Verbatim(_) => {}

_ => unimplemented!("unknown Type"),
}
}
5 changes: 0 additions & 5 deletions src/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,3 @@ impl<T> Slice for [T] {

#[doc(hidden)]
pub enum Void {}

#[doc(hidden)]
pub fn value<T>() -> T {
panic!()
}
4 changes: 2 additions & 2 deletions tests/ui/attempted_coercion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ error[E0308]: mismatched types
8 | #[distributed_slice(SLICE)]
| --------------------------- arguments to this function are incorrect
9 | static ELEMENT: &&str = &"uhoh";
| ^^^^^ expected `str`, found `&str`
| ^^^^^ expected `str`, found `&'static str`
|
= note: expected fn pointer `fn() -> &'static &'static _`
found fn pointer `fn() -> &&&_`
found fn pointer `fn() -> &'static &'static &'static _`
note: method defined here
--> src/distributed_slice.rs
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/mismatched_types.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ error[E0308]: mismatched types
| ^^^^^ expected fn pointer, found `usize`
|
= note: expected fn pointer `fn() -> &'static for<'a> fn(&'a mut Bencher)`
found fn pointer `fn() -> &usize`
found fn pointer `fn() -> &'static usize`
note: method defined here
--> src/distributed_slice.rs
|
Expand All @@ -23,7 +23,7 @@ error[E0308]: mismatched types
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Bencher`, found `()`
|
= note: expected fn pointer `fn() -> &'static for<'a> fn(&'a mut Bencher)`
found fn pointer `fn() -> &for<'a> fn(&'a mut ())`
found fn pointer `fn() -> &'static for<'a> fn(&'a mut ())`
note: method defined here
--> src/distributed_slice.rs
|
Expand Down
Loading