Skip to content

Commit 246fab6

Browse files
flag: DISALLOW_INSTANTIATION (RustPython#6445)
* Set tp_new slot when build heap/static type * Improve type tp_call impl to check tp_new existence and error if not exist * Set DISALLOW_INSTANTIATION flag on several types according to cpython impl * Allow #[pyslot] for function pointer * Fix DISALLOW_INSTANTIATION --------- Signed-off-by: snowapril <sinjihng@gmail.com> Co-authored-by: snowapril <sinjihng@gmail.com>
1 parent aef4de4 commit 246fab6

30 files changed

Lines changed: 184 additions & 163 deletions

Lib/test/test_descr.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,7 +1788,6 @@ class D(C):
17881788
self.assertEqual(b.foo, 3)
17891789
self.assertEqual(b.__class__, D)
17901790

1791-
@unittest.expectedFailure
17921791
def test_bad_new(self):
17931792
self.assertRaises(TypeError, object.__new__)
17941793
self.assertRaises(TypeError, object.__new__, '')

crates/derive-impl/src/pyclass.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,10 @@ where
954954
} else if let Ok(f) = args.item.function_or_method() {
955955
(&f.sig().ident, f.span())
956956
} else {
957-
return Err(self.new_syn_error(args.item.span(), "can only be on a method"));
957+
return Err(self.new_syn_error(
958+
args.item.span(),
959+
"can only be on a method or const function pointer",
960+
));
958961
};
959962

960963
let item_attr = args.attrs.remove(self.index());
@@ -1496,7 +1499,9 @@ impl SlotItemMeta {
14961499
}
14971500
} else {
14981501
let ident_str = self.inner().item_name();
1499-
let name = if let Some(stripped) = ident_str.strip_prefix("slot_") {
1502+
// Convert to lowercase to handle both SLOT_NEW and slot_new
1503+
let ident_lower = ident_str.to_lowercase();
1504+
let name = if let Some(stripped) = ident_lower.strip_prefix("slot_") {
15001505
proc_macro2::Ident::new(stripped, inner.item_ident.span())
15011506
} else {
15021507
inner.item_ident.clone()
@@ -1609,7 +1614,6 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
16091614
}];
16101615
let mut payload = None;
16111616

1612-
let mut has_constructor = false;
16131617
for attr in attr {
16141618
match attr {
16151619
NestedMeta::Meta(Meta::List(MetaList { path, nested, .. })) => {
@@ -1634,9 +1638,6 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
16341638
"Try `#[pyclass(with(Constructor, ...))]` instead of `#[pyclass(with(DefaultConstructor, ...))]`. DefaultConstructor implicitly implements Constructor."
16351639
)
16361640
}
1637-
if path.is_ident("Constructor") || path.is_ident("Unconstructible") {
1638-
has_constructor = true;
1639-
}
16401641
(
16411642
quote!(<Self as #path>::__extend_py_class),
16421643
quote!(<Self as #path>::__OWN_METHOD_DEFS),
@@ -1689,11 +1690,6 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
16891690
attr => bail_span!(attr, "Unknown pyimpl attribute"),
16901691
}
16911692
}
1692-
// TODO: DISALLOW_INSTANTIATION check is required
1693-
let _ = has_constructor;
1694-
// if !withs.is_empty() && !has_constructor {
1695-
// bail_span!(item, "#[pyclass(with(...))] does not have a Constructor. Either #[pyclass(with(Constructor, ...))] or #[pyclass(with(Unconstructible, ...))] is mandatory. Consider to add `impl DefaultConstructor for T {{}}` or `impl Unconstructible for T {{}}`.")
1696-
// }
16971693

16981694
Ok(ExtractedImplAttrs {
16991695
payload,

crates/stdlib/src/array.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,7 @@ mod array {
13991399
internal: PyMutex<PositionIterInternal<PyArrayRef>>,
14001400
}
14011401

1402-
#[pyclass(with(IterNext, Iterable), flags(HAS_DICT))]
1402+
#[pyclass(with(IterNext, Iterable), flags(HAS_DICT, DISALLOW_INSTANTIATION))]
14031403
impl PyArrayIter {
14041404
#[pymethod]
14051405
fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {

crates/stdlib/src/csv.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ mod _csv {
908908
}
909909
}
910910

911-
#[pyclass(with(IterNext, Iterable))]
911+
#[pyclass(with(IterNext, Iterable), flags(DISALLOW_INSTANTIATION))]
912912
impl Reader {
913913
#[pygetset]
914914
fn line_num(&self) -> u64 {
@@ -1059,7 +1059,7 @@ mod _csv {
10591059
}
10601060
}
10611061

1062-
#[pyclass]
1062+
#[pyclass(flags(DISALLOW_INSTANTIATION))]
10631063
impl Writer {
10641064
#[pygetset(name = "dialect")]
10651065
const fn get_dialect(&self, _vm: &VirtualMachine) -> PyDialect {

crates/stdlib/src/pystruct.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) mod _struct {
1616
function::{ArgBytesLike, ArgMemoryBuffer, PosArgs},
1717
match_class,
1818
protocol::PyIterReturn,
19-
types::{Constructor, IterNext, Iterable, Representable, SelfIter, Unconstructible},
19+
types::{Constructor, IterNext, Iterable, Representable, SelfIter},
2020
};
2121
use crossbeam_utils::atomic::AtomicCell;
2222

@@ -189,15 +189,15 @@ pub(crate) mod _struct {
189189
}
190190
}
191191

192-
#[pyclass(with(Unconstructible, IterNext, Iterable))]
192+
#[pyclass(with(IterNext, Iterable), flags(DISALLOW_INSTANTIATION))]
193193
impl UnpackIterator {
194194
#[pymethod]
195195
fn __length_hint__(&self) -> usize {
196196
self.buffer.len().saturating_sub(self.offset.load()) / self.format_spec.size
197197
}
198198
}
199199
impl SelfIter for UnpackIterator {}
200-
impl Unconstructible for UnpackIterator {}
200+
201201
impl IterNext for UnpackIterator {
202202
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
203203
let size = zelf.format_spec.size;

crates/stdlib/src/sqlite.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ mod _sqlite {
7575
sliceable::{SaturatedSliceIter, SliceableSequenceOp},
7676
types::{
7777
AsMapping, AsNumber, AsSequence, Callable, Comparable, Constructor, Hashable,
78-
Initializer, IterNext, Iterable, PyComparisonOp, SelfIter, Unconstructible,
78+
Initializer, IterNext, Iterable, PyComparisonOp, SelfIter,
7979
},
8080
utils::ToCString,
8181
};
@@ -2197,8 +2197,6 @@ mod _sqlite {
21972197
inner: PyMutex<Option<BlobInner>>,
21982198
}
21992199

2200-
impl Unconstructible for Blob {}
2201-
22022200
#[derive(Debug)]
22032201
struct BlobInner {
22042202
blob: SqliteBlob,
@@ -2211,7 +2209,7 @@ mod _sqlite {
22112209
}
22122210
}
22132211

2214-
#[pyclass(with(AsMapping, Unconstructible, AsNumber, AsSequence))]
2212+
#[pyclass(flags(DISALLOW_INSTANTIATION), with(AsMapping, AsNumber, AsSequence))]
22152213
impl Blob {
22162214
#[pymethod]
22172215
fn close(&self) {
@@ -2592,9 +2590,7 @@ mod _sqlite {
25922590
}
25932591
}
25942592

2595-
impl Unconstructible for Statement {}
2596-
2597-
#[pyclass(with(Unconstructible))]
2593+
#[pyclass(flags(DISALLOW_INSTANTIATION))]
25982594
impl Statement {
25992595
fn new(
26002596
connection: &Connection,

crates/stdlib/src/unicodedata.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ mod unicodedata {
105105
}
106106
}
107107

108-
#[pyclass]
108+
#[pyclass(flags(DISALLOW_INSTANTIATION))]
109109
impl Ucd {
110110
#[pymethod]
111111
fn category(&self, character: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {

crates/stdlib/src/zlib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ mod zlib {
225225
inner: PyMutex<PyDecompressInner>,
226226
}
227227

228-
#[pyclass]
228+
#[pyclass(flags(DISALLOW_INSTANTIATION))]
229229
impl PyDecompress {
230230
#[pygetset]
231231
fn eof(&self) -> bool {
@@ -383,7 +383,7 @@ mod zlib {
383383
inner: PyMutex<CompressState<CompressInner>>,
384384
}
385385

386-
#[pyclass]
386+
#[pyclass(flags(DISALLOW_INSTANTIATION))]
387387
impl PyCompress {
388388
#[pymethod]
389389
fn compress(&self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult<Vec<u8>> {

crates/vm/src/builtins/asyncgenerator.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
frame::FrameRef,
99
function::OptionalArg,
1010
protocol::PyIterReturn,
11-
types::{IterNext, Iterable, Representable, SelfIter, Unconstructible},
11+
types::{IterNext, Iterable, Representable, SelfIter},
1212
};
1313

1414
use crossbeam_utils::atomic::AtomicCell;
@@ -32,7 +32,7 @@ impl PyPayload for PyAsyncGen {
3232
}
3333
}
3434

35-
#[pyclass(with(PyRef, Unconstructible, Representable))]
35+
#[pyclass(flags(DISALLOW_INSTANTIATION), with(PyRef, Representable))]
3636
impl PyAsyncGen {
3737
pub const fn as_coro(&self) -> &Coro {
3838
&self.inner
@@ -201,8 +201,6 @@ impl Representable for PyAsyncGen {
201201
}
202202
}
203203

204-
impl Unconstructible for PyAsyncGen {}
205-
206204
#[pyclass(module = false, name = "async_generator_wrapped_value")]
207205
#[derive(Debug)]
208206
pub(crate) struct PyAsyncGenWrappedValue(pub PyObjectRef);

crates/vm/src/builtins/builtin_func.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
common::wtf8::Wtf8,
66
convert::TryFromObject,
77
function::{FuncArgs, PyComparisonValue, PyMethodDef, PyMethodFlags, PyNativeFn},
8-
types::{Callable, Comparable, PyComparisonOp, Representable, Unconstructible},
8+
types::{Callable, Comparable, PyComparisonOp, Representable},
99
};
1010
use std::fmt;
1111

@@ -74,7 +74,7 @@ impl Callable for PyNativeFunction {
7474
}
7575
}
7676

77-
#[pyclass(with(Callable, Unconstructible), flags(HAS_DICT))]
77+
#[pyclass(with(Callable), flags(HAS_DICT, DISALLOW_INSTANTIATION))]
7878
impl PyNativeFunction {
7979
#[pygetset]
8080
fn __module__(zelf: NativeFunctionOrMethod) -> Option<&'static PyStrInterned> {
@@ -145,8 +145,6 @@ impl Representable for PyNativeFunction {
145145
}
146146
}
147147

148-
impl Unconstructible for PyNativeFunction {}
149-
150148
// `PyCMethodObject` in CPython
151149
#[pyclass(name = "builtin_method", module = false, base = PyNativeFunction, ctx = "builtin_method_type")]
152150
pub struct PyNativeMethod {
@@ -155,8 +153,8 @@ pub struct PyNativeMethod {
155153
}
156154

157155
#[pyclass(
158-
with(Unconstructible, Callable, Comparable, Representable),
159-
flags(HAS_DICT)
156+
with(Callable, Comparable, Representable),
157+
flags(HAS_DICT, DISALLOW_INSTANTIATION)
160158
)]
161159
impl PyNativeMethod {
162160
#[pygetset]
@@ -246,8 +244,6 @@ impl Representable for PyNativeMethod {
246244
}
247245
}
248246

249-
impl Unconstructible for PyNativeMethod {}
250-
251247
pub fn init(context: &Context) {
252248
PyNativeFunction::extend_class(context, context.types.builtin_function_or_method_type);
253249
PyNativeMethod::extend_class(context, context.types.builtin_method_type);

0 commit comments

Comments
 (0)