forked from Rust-related/RustPython
new name collition detection
This commit is contained in:
@@ -107,8 +107,8 @@ pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream
|
||||
} = extract_impl_attrs(attr, &Ident::new("e!(ty).to_string(), ty.span()))?;
|
||||
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
let extend_impl = context.impl_extend_items.validate()?;
|
||||
let slots_impl = context.extend_slots_items.validate()?;
|
||||
let class_extensions = &context.class_extensions;
|
||||
quote! {
|
||||
#imp
|
||||
@@ -143,8 +143,8 @@ pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream
|
||||
} = extract_impl_attrs(attr, &trai.ident)?;
|
||||
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
let extend_impl = &context.impl_extend_items.validate()?;
|
||||
let slots_impl = &context.extend_slots_items.validate()?;
|
||||
let class_extensions = &context.class_extensions;
|
||||
let extra_methods = iter_chain![
|
||||
parse_quote! {
|
||||
@@ -502,9 +502,12 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
args.context
|
||||
.impl_extend_items
|
||||
.add_item(py_name, args.cfgs.to_vec(), tokens)?;
|
||||
args.context.impl_extend_items.add_item(
|
||||
ident.clone(),
|
||||
vec![py_name],
|
||||
args.cfgs.to_vec(),
|
||||
tokens,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -560,8 +563,10 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let pyname = format!("(slot {})", slot_name);
|
||||
args.context.extend_slots_items.add_item(
|
||||
format!("(slot {})", slot_name),
|
||||
ident.clone(),
|
||||
vec![pyname],
|
||||
args.cfgs.to_vec(),
|
||||
tokens,
|
||||
)?;
|
||||
@@ -583,32 +588,34 @@ where
|
||||
let py_name = item_meta.simple_name()?;
|
||||
Ok(py_name)
|
||||
};
|
||||
let (py_name, tokens) = if args.item.function_or_method().is_ok() || args.item.is_const() {
|
||||
let ident = args.item.get_ident().unwrap();
|
||||
let py_name = get_py_name(&attr, ident)?;
|
||||
let (ident, py_name, tokens) =
|
||||
if args.item.function_or_method().is_ok() || args.item.is_const() {
|
||||
let ident = args.item.get_ident().unwrap();
|
||||
let py_name = get_py_name(&attr, ident)?;
|
||||
|
||||
let value = if args.item.is_const() {
|
||||
// TODO: ctx.new_value
|
||||
quote_spanned!(ident.span() => ctx.new_int(Self::#ident).into())
|
||||
let value = if args.item.is_const() {
|
||||
// TODO: ctx.new_value
|
||||
quote_spanned!(ident.span() => ctx.new_int(Self::#ident).into())
|
||||
} else {
|
||||
quote_spanned!(ident.span() => Self::#ident(ctx))
|
||||
};
|
||||
(
|
||||
ident,
|
||||
py_name.clone(),
|
||||
quote! {
|
||||
class.set_str_attr(#py_name, #value);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
quote_spanned!(ident.span() => Self::#ident(ctx))
|
||||
return Err(self.new_syn_error(
|
||||
args.item.span(),
|
||||
"can only be on a const or an associated method without argument",
|
||||
));
|
||||
};
|
||||
(
|
||||
py_name.clone(),
|
||||
quote! {
|
||||
class.set_str_attr(#py_name, #value);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
return Err(self.new_syn_error(
|
||||
args.item.span(),
|
||||
"can only be on a const or an associated method without argument",
|
||||
));
|
||||
};
|
||||
|
||||
args.context
|
||||
.impl_extend_items
|
||||
.add_item(py_name, cfgs, tokens)?;
|
||||
.add_item(ident.clone(), vec![py_name], cfgs, tokens)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
|
||||
|
||||
// append additional items
|
||||
let module_name = context.name.as_str();
|
||||
let module_extend_items = context.module_extend_items;
|
||||
let module_extend_items = context.module_extend_items.validate()?;
|
||||
let doc = doc.or_else(|| {
|
||||
crate::doc::try_read(module_name)
|
||||
.ok()
|
||||
@@ -317,7 +317,7 @@ impl ModuleItem for FunctionItem {
|
||||
let py_name = item_meta.simple_name()?;
|
||||
let sig_doc = text_signature(func.sig(), &py_name);
|
||||
|
||||
let item = {
|
||||
let (tokens, py_names) = {
|
||||
let module = args.module_name();
|
||||
let doc = args.attrs.doc().or_else(|| {
|
||||
crate::doc::try_module_item(module, &py_name)
|
||||
@@ -340,13 +340,16 @@ impl ModuleItem for FunctionItem {
|
||||
);
|
||||
|
||||
if self.pyattrs.is_empty() {
|
||||
quote_spanned! { ident.span() => {
|
||||
let func = #new_func;
|
||||
vm.__module_set_attr(module, #py_name, func).unwrap();
|
||||
}}
|
||||
(
|
||||
quote_spanned! { ident.span() => {
|
||||
let func = #new_func;
|
||||
vm.__module_set_attr(module, #py_name, func).unwrap();
|
||||
}},
|
||||
vec![py_name],
|
||||
)
|
||||
} else {
|
||||
let mut py_names = HashSet::new();
|
||||
py_names.insert(py_name.clone());
|
||||
py_names.insert(py_name);
|
||||
for attr_index in self.pyattrs.iter().rev() {
|
||||
let mut loop_unit = || {
|
||||
let attr_attr = args.attrs.remove(*attr_index);
|
||||
@@ -368,18 +371,24 @@ impl ModuleItem for FunctionItem {
|
||||
args.context.errors.ok_or_push(r);
|
||||
}
|
||||
let py_names: Vec<_> = py_names.into_iter().collect();
|
||||
quote_spanned! { ident.span().resolved_at(Span::call_site()) => {
|
||||
let func = #new_func;
|
||||
for name in [#(#py_names,)*] {
|
||||
vm.__module_set_attr(module, name, func.clone()).unwrap();
|
||||
}
|
||||
}}
|
||||
(
|
||||
quote_spanned! { ident.span().resolved_at(Span::call_site()) => {
|
||||
let func = #new_func;
|
||||
for name in [#(#py_names,)*] {
|
||||
vm.__module_set_attr(module, name, func.clone()).unwrap();
|
||||
}
|
||||
}},
|
||||
py_names,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, args.cfgs.to_vec(), item)?;
|
||||
args.context.module_extend_items.add_item(
|
||||
ident.clone(),
|
||||
py_names,
|
||||
args.cfgs.to_vec(),
|
||||
tokens,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -422,7 +431,7 @@ impl ModuleItem for ClassItem {
|
||||
(class_name, class_new)
|
||||
};
|
||||
|
||||
let mut names = Vec::new();
|
||||
let mut py_names = Vec::new();
|
||||
for attr_index in self.pyattrs.iter().rev() {
|
||||
let mut loop_unit = || {
|
||||
let attr_attr = args.attrs.remove(*attr_index);
|
||||
@@ -431,7 +440,7 @@ impl ModuleItem for ClassItem {
|
||||
let py_name = item_meta
|
||||
.optional_name()
|
||||
.unwrap_or_else(|| class_name.clone());
|
||||
names.push(py_name);
|
||||
py_names.push(py_name);
|
||||
|
||||
Ok(())
|
||||
};
|
||||
@@ -439,25 +448,26 @@ impl ModuleItem for ClassItem {
|
||||
args.context.errors.ok_or_push(r);
|
||||
}
|
||||
|
||||
let set_attr = match names.len() {
|
||||
let set_attr = match py_names.len() {
|
||||
0 => quote! {
|
||||
let _ = new_class;
|
||||
},
|
||||
1 => {
|
||||
let py_name = &names[0];
|
||||
let py_name = &py_names[0];
|
||||
quote! {
|
||||
vm.__module_set_attr(&module, #py_name, new_class).unwrap();
|
||||
}
|
||||
}
|
||||
_ => quote! {
|
||||
for name in [#(#names,)*] {
|
||||
for name in [#(#py_names,)*] {
|
||||
vm.__module_set_attr(&module, name, new_class.clone()).unwrap();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
args.context.module_extend_items.add_item(
|
||||
ident.to_string(),
|
||||
ident.clone(),
|
||||
py_names,
|
||||
args.cfgs.to_vec(),
|
||||
quote_spanned! { ident.span() => {
|
||||
#class_new
|
||||
@@ -542,9 +552,12 @@ impl ModuleItem for AttributeItem {
|
||||
let tokens = quote_spanned! { ident.span() =>
|
||||
vm.__module_set_attr(module, #py_name, vm.new_pyobj(#ident)).unwrap();
|
||||
};
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, cfgs.clone(), tokens)?;
|
||||
args.context.module_extend_items.add_item(
|
||||
ident.clone(),
|
||||
vec![py_name],
|
||||
cfgs.clone(),
|
||||
tokens,
|
||||
)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -555,13 +568,16 @@ impl ModuleItem for AttributeItem {
|
||||
}
|
||||
};
|
||||
|
||||
let tokens = if self.pyattrs.is_empty() {
|
||||
quote_spanned! { ident.span() => {
|
||||
#let_obj
|
||||
vm.__module_set_attr(module, #py_name, obj).unwrap();
|
||||
}}
|
||||
let (tokens, py_names) = if self.pyattrs.is_empty() {
|
||||
(
|
||||
quote_spanned! { ident.span() => {
|
||||
#let_obj
|
||||
vm.__module_set_attr(module, #py_name, obj).unwrap();
|
||||
}},
|
||||
vec![py_name],
|
||||
)
|
||||
} else {
|
||||
let mut names = vec![py_name.clone()];
|
||||
let mut names = vec![py_name];
|
||||
for attr_index in self.pyattrs.iter().rev() {
|
||||
let mut loop_unit = || {
|
||||
let attr_attr = args.attrs.remove(*attr_index);
|
||||
@@ -585,17 +601,20 @@ impl ModuleItem for AttributeItem {
|
||||
let r = loop_unit();
|
||||
args.context.errors.ok_or_push(r);
|
||||
}
|
||||
quote_spanned! { ident.span() => {
|
||||
#let_obj
|
||||
for name in [(#(#names,)*)] {
|
||||
vm.__module_set_attr(module, name, obj.clone()).unwrap();
|
||||
}
|
||||
}}
|
||||
(
|
||||
quote_spanned! { ident.span() => {
|
||||
#let_obj
|
||||
for name in [(#(#names,)*)] {
|
||||
vm.__module_set_attr(module, name, obj.clone()).unwrap();
|
||||
}
|
||||
}},
|
||||
names,
|
||||
)
|
||||
};
|
||||
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, cfgs, tokens)?;
|
||||
.add_item(ident, py_names, cfgs, tokens)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use indexmap::map::IndexMap;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use syn::{
|
||||
spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result, Signature,
|
||||
UseTree,
|
||||
@@ -25,34 +24,62 @@ pub(crate) const ALL_ALLOWED_NAMES: &[&str] = &[
|
||||
"extend_class",
|
||||
];
|
||||
|
||||
struct NurseryItem {
|
||||
attr_name: Ident,
|
||||
py_names: Vec<String>,
|
||||
cfgs: Vec<Attribute>,
|
||||
tokens: TokenStream,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ItemNursery(IndexMap<(String, Vec<Attribute>), TokenStream>);
|
||||
pub(crate) struct ItemNursery(Vec<NurseryItem>);
|
||||
|
||||
pub(crate) struct ValidatedItemNursery(ItemNursery);
|
||||
|
||||
impl ItemNursery {
|
||||
pub fn add_item(
|
||||
&mut self,
|
||||
name: String,
|
||||
attr_name: Ident,
|
||||
py_names: Vec<String>,
|
||||
cfgs: Vec<Attribute>,
|
||||
tokens: TokenStream,
|
||||
) -> Result<()> {
|
||||
if let Some(existing) = self.0.insert((name.clone(), cfgs), tokens) {
|
||||
Err(syn::Error::new_spanned(
|
||||
existing,
|
||||
format!("Duplicated #[py*] attribute found for '{}'", name),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
self.0.push(NurseryItem {
|
||||
attr_name,
|
||||
py_names,
|
||||
cfgs,
|
||||
tokens,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate(self) -> Result<ValidatedItemNursery> {
|
||||
let mut by_name: HashSet<(String, Vec<Attribute>)> = HashSet::new();
|
||||
for item in &self.0 {
|
||||
for py_name in &item.py_names {
|
||||
let inserted = by_name.insert((py_name.clone(), item.cfgs.clone()));
|
||||
if !inserted {
|
||||
return Err(syn::Error::new(
|
||||
item.attr_name.span(),
|
||||
&format!("Duplicated #[py*] attribute found for {:?}", &item.py_names),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(ValidatedItemNursery(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ItemNursery {
|
||||
impl ToTokens for ValidatedItemNursery {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.extend(self.0.iter().map(|((_, cfgs), item)| {
|
||||
let nursery = &self.0;
|
||||
tokens.extend(nursery.0.iter().map(|item| {
|
||||
let cfgs = &item.cfgs;
|
||||
let tokens = &item.tokens;
|
||||
quote! {
|
||||
#( #cfgs )*
|
||||
{
|
||||
#item
|
||||
#tokens
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user