Skip to content

Commit fa1cab1

Browse files
committed
Native subclassing part 1
1 parent ad5ffb6 commit fa1cab1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+838
-399
lines changed

derive-impl/src/pyclass.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,10 @@ fn generate_class_def(
307307
ident: &Ident,
308308
name: &str,
309309
module_name: Option<&str>,
310-
base: Option<String>,
310+
base: Option<&Ident>,
311311
metaclass: Option<String>,
312312
unhashable: bool,
313+
no_payload: bool,
313314
attrs: &[Attribute],
314315
) -> Result<TokenStream> {
315316
let doc = attrs.doc().or_else(|| {
@@ -356,10 +357,7 @@ fn generate_class_def(
356357
let base_class = if is_pystruct {
357358
Some(quote! { rustpython_vm::builtins::PyTuple })
358359
} else {
359-
base.as_ref().map(|typ| {
360-
let typ = Ident::new(typ, ident.span());
361-
quote_spanned! { ident.span() => #typ }
362-
})
360+
base.map(|typ| quote!(#typ))
363361
}
364362
.map(|typ| {
365363
quote! {
@@ -381,12 +379,21 @@ fn generate_class_def(
381379
});
382380

383381
let base_or_object = if let Some(base) = base {
384-
let base = Ident::new(&base, ident.span());
385382
quote! { #base }
386383
} else {
387384
quote! { ::rustpython_vm::builtins::PyBaseObject }
388385
};
389386

387+
let type_id = if no_payload || is_pystruct {
388+
quote!(::std::option::Option::None)
389+
} else {
390+
quote! {
391+
fn _check<__T: ::rustpython_vm::PyPayload>() {}
392+
_check::<Self>();
393+
::std::option::Option::Some(::std::any::TypeId::of::<Self>())
394+
}
395+
};
396+
390397
let tokens = quote! {
391398
impl ::rustpython_vm::class::PyClassDef for #ident {
392399
const NAME: &'static str = #name;
@@ -399,14 +406,18 @@ fn generate_class_def(
399406
type Base = #base_or_object;
400407
}
401408

402-
impl ::rustpython_vm::class::StaticType for #ident {
409+
unsafe impl ::rustpython_vm::class::StaticType for #ident {
403410
fn static_cell() -> &'static ::rustpython_vm::common::static_cell::StaticCell<::rustpython_vm::builtins::PyTypeRef> {
404411
::rustpython_vm::common::static_cell! {
405412
static CELL: ::rustpython_vm::builtins::PyTypeRef;
406413
}
407414
&CELL
408415
}
409416

417+
fn type_id() -> ::std::option::Option<::std::any::TypeId> {
418+
#type_id
419+
}
420+
410421
#meta_class
411422

412423
#base_class
@@ -427,14 +438,16 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
427438
let base = class_meta.base()?;
428439
let metaclass = class_meta.metaclass()?;
429440
let unhashable = class_meta.unhashable()?;
441+
let no_payload = class_meta.no_payload()?;
430442

431443
let class_def = generate_class_def(
432444
ident,
433445
&class_name,
434446
module_name.as_deref(),
435-
base,
447+
base.as_ref(),
436448
metaclass,
437449
unhashable,
450+
no_payload,
438451
attrs,
439452
)?;
440453

@@ -490,9 +503,14 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
490503
let impl_payload = if let Some(ctx_type_name) = class_meta.ctx_name()? {
491504
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span()); // FIXME span
492505

506+
let base = base
507+
.as_ref()
508+
.map(|t| quote!(#t))
509+
.unwrap_or_else(|| quote!(::rustpython_vm::builtins::PyBaseObject));
493510
// We need this to make extend mechanism work:
494511
quote! {
495512
impl ::rustpython_vm::PyPayload for #ident {
513+
type Super = #base;
496514
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
497515
ctx.types.#ctx_type_ident
498516
}
@@ -537,13 +555,16 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result
537555
let class_meta = ExceptionItemMeta::from_nested(ident.clone(), fake_ident, attr.into_iter())?;
538556
let class_name = class_meta.class_name()?;
539557

540-
let base_class_name = class_meta.base()?;
558+
let base_class_name = class_meta
559+
.base()?
560+
.ok_or_else(|| syn::Error::new(Span::call_site(), "pyexception must specify base"))?;
541561
let impl_payload = if let Some(ctx_type_name) = class_meta.ctx_name()? {
542562
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span()); // FIXME span
543563

544564
// We need this to make extend mechanism work:
545565
quote! {
546566
impl ::rustpython_vm::PyPayload for #ident {
567+
type Super = #base_class_name;
547568
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
548569
ctx.exceptions.#ctx_type_ident
549570
}
@@ -561,6 +582,8 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result
561582
quote! {}
562583
};
563584

585+
let base_class_name = base_class_name.to_string();
586+
564587
let ret = quote! {
565588
#[pyclass(module = false, name = #class_name, base = #base_class_name)]
566589
#item

derive-impl/src/pypayload.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub(crate) fn impl_pypayload(input: DeriveInput) -> Result<TokenStream> {
77

88
let ret = quote! {
99
impl ::rustpython_vm::PyPayload for #ty {
10+
type Super = ::rustpython_vm::builtins::PyBaseObject;
1011
fn class(_ctx: &::rustpython_vm::vm::Context) -> &'static rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
1112
<Self as ::rustpython_vm::class::StaticType>::static_type()
1213
}

derive-impl/src/util.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,31 @@ impl ItemMetaInner {
187187
Ok(value)
188188
}
189189

190+
pub fn _optional_parse<T: syn::parse::Parse>(&self, key: &str) -> Result<Option<T>> {
191+
let value = if let Some((_, meta)) = self.meta_map.get(key) {
192+
let Meta::NameValue(syn::MetaNameValue {
193+
value:
194+
syn::Expr::Lit(syn::ExprLit {
195+
lit: syn::Lit::Str(lit),
196+
..
197+
}),
198+
..
199+
}) = meta
200+
else {
201+
bail_span!(
202+
meta,
203+
"#[{}({} = ...)] must exist as a string",
204+
self.meta_name(),
205+
key
206+
)
207+
};
208+
Some(lit.parse()?)
209+
} else {
210+
None
211+
};
212+
Ok(value)
213+
}
214+
190215
pub fn _has_key(&self, key: &str) -> Result<bool> {
191216
Ok(matches!(self.meta_map.get(key), Some((_, _))))
192217
}
@@ -336,6 +361,7 @@ impl ItemMeta for ClassItemMeta {
336361
"base",
337362
"metaclass",
338363
"unhashable",
364+
"no_payload",
339365
"ctx",
340366
"impl",
341367
"traverse",
@@ -379,14 +405,18 @@ impl ClassItemMeta {
379405
self.inner()._optional_str("ctx")
380406
}
381407

382-
pub fn base(&self) -> Result<Option<String>> {
383-
self.inner()._optional_str("base")
408+
pub fn base(&self) -> Result<Option<Ident>> {
409+
self.inner()._optional_parse("base")
384410
}
385411

386412
pub fn unhashable(&self) -> Result<bool> {
387413
self.inner()._bool("unhashable")
388414
}
389415

416+
pub fn no_payload(&self) -> Result<bool> {
417+
self.inner()._bool("no_payload")
418+
}
419+
390420
pub fn metaclass(&self) -> Result<Option<String>> {
391421
self.inner()._optional_str("metaclass")
392422
}
@@ -441,7 +471,8 @@ impl ClassItemMeta {
441471
pub(crate) struct ExceptionItemMeta(ClassItemMeta);
442472

443473
impl ItemMeta for ExceptionItemMeta {
444-
const ALLOWED_NAMES: &'static [&'static str] = &["name", "base", "unhashable", "ctx", "impl"];
474+
const ALLOWED_NAMES: &'static [&'static str] =
475+
&["name", "base", "unhashable", "no_payload", "ctx", "impl"];
445476

446477
fn from_inner(inner: ItemMetaInner) -> Self {
447478
Self(ClassItemMeta(inner))

vm/src/builtins/asyncgenerator.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub struct PyAsyncGen {
2121
type PyAsyncGenRef = PyRef<PyAsyncGen>;
2222

2323
impl PyPayload for PyAsyncGen {
24+
type Super = crate::builtins::PyBaseObject;
2425
fn class(ctx: &Context) -> &'static Py<PyType> {
2526
ctx.types.async_generator
2627
}
@@ -141,6 +142,7 @@ impl Unconstructible for PyAsyncGen {}
141142
#[derive(Debug)]
142143
pub(crate) struct PyAsyncGenWrappedValue(pub PyObjectRef);
143144
impl PyPayload for PyAsyncGenWrappedValue {
145+
type Super = crate::builtins::PyBaseObject;
144146
fn class(ctx: &Context) -> &'static Py<PyType> {
145147
ctx.types.async_generator_wrapped_value
146148
}
@@ -190,6 +192,7 @@ pub(crate) struct PyAsyncGenASend {
190192
}
191193

192194
impl PyPayload for PyAsyncGenASend {
195+
type Super = crate::builtins::PyBaseObject;
193196
fn class(ctx: &Context) -> &'static Py<PyType> {
194197
ctx.types.async_generator_asend
195198
}
@@ -285,6 +288,7 @@ pub(crate) struct PyAsyncGenAThrow {
285288
}
286289

287290
impl PyPayload for PyAsyncGenAThrow {
291+
type Super = crate::builtins::PyBaseObject;
288292
fn class(ctx: &Context) -> &'static Py<PyType> {
289293
ctx.types.async_generator_athrow
290294
}

vm/src/builtins/bool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ impl PyObjectRef {
8181
pub struct PyBool;
8282

8383
impl PyPayload for PyBool {
84+
type Super = crate::builtins::PyBaseObject;
8485
fn class(ctx: &Context) -> &'static Py<PyType> {
8586
ctx.types.bool_type
8687
}

vm/src/builtins/builtin_func.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct PyNativeFunction {
1717
}
1818

1919
impl PyPayload for PyNativeFunction {
20+
type Super = crate::builtins::PyBaseObject;
2021
fn class(ctx: &Context) -> &'static Py<PyType> {
2122
ctx.types.builtin_function_or_method_type
2223
}
@@ -179,6 +180,7 @@ impl PyNativeMethod {
179180
}
180181

181182
impl PyPayload for PyNativeMethod {
183+
type Super = crate::builtins::PyBaseObject;
182184
fn class(ctx: &Context) -> &'static Py<PyType> {
183185
ctx.types.builtin_method_type
184186
}

vm/src/builtins/bytearray.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl From<Vec<u8>> for PyByteArray {
6161
}
6262

6363
impl PyPayload for PyByteArray {
64+
type Super = crate::builtins::PyBaseObject;
6465
fn class(ctx: &Context) -> &'static Py<PyType> {
6566
ctx.types.bytearray_type
6667
}
@@ -878,6 +879,7 @@ pub struct PyByteArrayIterator {
878879
}
879880

880881
impl PyPayload for PyByteArrayIterator {
882+
type Super = crate::builtins::PyBaseObject;
881883
fn class(ctx: &Context) -> &'static Py<PyType> {
882884
ctx.types.bytearray_iterator_type
883885
}

vm/src/builtins/bytes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl AsRef<[u8]> for PyBytesRef {
7878
}
7979

8080
impl PyPayload for PyBytes {
81+
type Super = crate::builtins::PyBaseObject;
8182
fn class(ctx: &Context) -> &'static Py<PyType> {
8283
ctx.types.bytes_type
8384
}
@@ -683,6 +684,7 @@ pub struct PyBytesIterator {
683684
}
684685

685686
impl PyPayload for PyBytesIterator {
687+
type Super = crate::builtins::PyBaseObject;
686688
fn class(ctx: &Context) -> &'static Py<PyType> {
687689
ctx.types.bytes_iterator_type
688690
}

vm/src/builtins/classmethod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl From<PyObjectRef> for PyClassMethod {
4141
}
4242

4343
impl PyPayload for PyClassMethod {
44+
type Super = crate::builtins::PyBaseObject;
4445
fn class(ctx: &Context) -> &'static Py<PyType> {
4546
ctx.types.classmethod_type
4647
}

vm/src/builtins/code.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ impl fmt::Debug for PyCode {
214214
}
215215

216216
impl PyPayload for PyCode {
217+
type Super = crate::builtins::PyBaseObject;
217218
fn class(ctx: &Context) -> &'static Py<PyType> {
218219
ctx.types.code_type
219220
}

0 commit comments

Comments
 (0)