Skip to content

Commit 3d951a8

Browse files
authored
Compile starred annotations (#5881)
* Fix starred annotation * uncomment starred annotation
1 parent 4ebd485 commit 3d951a8

File tree

16 files changed

+155
-165
lines changed

16 files changed

+155
-165
lines changed

Lib/test/test_typing.py

Lines changed: 97 additions & 118 deletions
Large diffs are not rendered by default.

compiler/codegen/src/compile.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct Compiler<'src> {
8080
ctx: CompileContext,
8181
class_name: Option<String>,
8282
opts: CompileOpts,
83+
in_annotation: bool,
8384
}
8485

8586
enum DoneWithFuture {
@@ -335,6 +336,7 @@ impl<'src> Compiler<'src> {
335336
},
336337
class_name: None,
337338
opts,
339+
in_annotation: false,
338340
}
339341
}
340342
}
@@ -2897,7 +2899,11 @@ impl Compiler<'_> {
28972899
.into(),
28982900
});
28992901
} else {
2900-
self.compile_expression(annotation)?;
2902+
let was_in_annotation = self.in_annotation;
2903+
self.in_annotation = true;
2904+
let result = self.compile_expression(annotation);
2905+
self.in_annotation = was_in_annotation;
2906+
result?;
29012907
}
29022908
Ok(())
29032909
}
@@ -3504,8 +3510,15 @@ impl Compiler<'_> {
35043510
Self::contains_await(elt),
35053511
)?;
35063512
}
3507-
Expr::Starred(_) => {
3508-
return Err(self.error(CodegenErrorType::InvalidStarExpr));
3513+
Expr::Starred(ExprStarred { value, .. }) => {
3514+
if self.in_annotation {
3515+
// In annotation context, starred expressions are allowed (PEP 646)
3516+
// For now, just compile the inner value without wrapping with Unpack
3517+
// This is a temporary solution until we figure out how to properly import typing
3518+
self.compile_expression(value)?;
3519+
} else {
3520+
return Err(self.error(CodegenErrorType::InvalidStarExpr));
3521+
}
35093522
}
35103523
Expr::If(ExprIf {
35113524
test, body, orelse, ..

vm/src/builtins/asyncgenerator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl PyAsyncGen {
6969

7070
#[pyclassmethod]
7171
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
72-
PyGenericAlias::new(cls, args, vm)
72+
PyGenericAlias::from_args(cls, args, vm)
7373
}
7474
}
7575

vm/src/builtins/dict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl PyDict {
322322

323323
#[pyclassmethod]
324324
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
325-
PyGenericAlias::new(cls, args, vm)
325+
PyGenericAlias::from_args(cls, args, vm)
326326
}
327327
}
328328

vm/src/builtins/enumerate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl Constructor for PyEnumerate {
5757
impl PyEnumerate {
5858
#[pyclassmethod]
5959
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
60-
PyGenericAlias::new(cls, args, vm)
60+
PyGenericAlias::from_args(cls, args, vm)
6161
}
6262
}
6363

vm/src/builtins/genericalias.rs

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ impl Constructor for PyGenericAlias {
6363
return Err(vm.new_type_error("GenericAlias() takes no keyword arguments"));
6464
}
6565
let (origin, arguments): (_, PyObjectRef) = args.bind(vm)?;
66-
PyGenericAlias::new(origin, arguments, vm)
66+
let args = if let Ok(tuple) = arguments.try_to_ref::<PyTuple>(vm) {
67+
tuple.to_owned()
68+
} else {
69+
PyTuple::new_ref(vec![arguments], &vm.ctx)
70+
};
71+
PyGenericAlias::new(origin, args, false, vm)
6772
.into_ref_with_type(vm, cls)
6873
.map(Into::into)
6974
}
@@ -84,35 +89,24 @@ impl Constructor for PyGenericAlias {
8489
flags(BASETYPE)
8590
)]
8691
impl PyGenericAlias {
87-
pub fn new(origin: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> Self {
88-
let args = if let Ok(tuple) = args.try_to_ref::<PyTuple>(vm) {
89-
tuple.to_owned()
90-
} else {
91-
PyTuple::new_ref(vec![args], &vm.ctx)
92-
};
93-
92+
pub fn new(origin: PyTypeRef, args: PyTupleRef, starred: bool, vm: &VirtualMachine) -> Self {
9493
let parameters = make_parameters(&args, vm);
9594
Self {
9695
origin,
9796
args,
9897
parameters,
99-
starred: false, // default to false
98+
starred,
10099
}
101100
}
102101

103-
fn with_tuple_args(
104-
origin: PyTypeRef,
105-
args: PyTupleRef,
106-
starred: bool,
107-
vm: &VirtualMachine,
108-
) -> Self {
109-
let parameters = make_parameters(&args, vm);
110-
Self {
111-
origin,
112-
args,
113-
parameters,
114-
starred,
115-
}
102+
/// Create a GenericAlias from an origin and PyObjectRef arguments (helper for compatibility)
103+
pub fn from_args(origin: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> Self {
104+
let args = if let Ok(tuple) = args.try_to_ref::<PyTuple>(vm) {
105+
tuple.to_owned()
106+
} else {
107+
PyTuple::new_ref(vec![args], &vm.ctx)
108+
};
109+
Self::new(origin, args, false, vm)
116110
}
117111

118112
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
@@ -146,7 +140,7 @@ impl PyGenericAlias {
146140
}
147141
}
148142

149-
Ok(format!(
143+
let repr_str = format!(
150144
"{}[{}]",
151145
repr_item(self.origin.clone().into(), vm)?,
152146
if self.args.is_empty() {
@@ -158,7 +152,14 @@ impl PyGenericAlias {
158152
.collect::<PyResult<Vec<_>>>()?
159153
.join(", ")
160154
}
161-
))
155+
);
156+
157+
// Add * prefix if this is a starred GenericAlias
158+
Ok(if self.starred {
159+
format!("*{repr_str}")
160+
} else {
161+
repr_str
162+
})
162163
}
163164

164165
#[pygetset]
@@ -200,10 +201,7 @@ impl PyGenericAlias {
200201
vm,
201202
)?;
202203

203-
Ok(
204-
PyGenericAlias::new(zelf.origin.clone(), new_args.to_pyobject(vm), vm)
205-
.into_pyobject(vm),
206-
)
204+
Ok(PyGenericAlias::new(zelf.origin.clone(), new_args, false, vm).into_pyobject(vm))
207205
}
208206

209207
#[pymethod]
@@ -598,7 +596,7 @@ impl Iterable for PyGenericAlias {
598596
// CPython's ga_iter creates an iterator that yields one starred GenericAlias
599597
// we don't have gaiterobject yet
600598

601-
let starred_alias = PyGenericAlias::with_tuple_args(
599+
let starred_alias = PyGenericAlias::new(
602600
zelf.origin.clone(),
603601
zelf.args.clone(),
604602
true, // starred

vm/src/builtins/list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ impl PyList {
337337

338338
#[pyclassmethod]
339339
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
340-
PyGenericAlias::new(cls, args, vm)
340+
PyGenericAlias::from_args(cls, args, vm)
341341
}
342342
}
343343

vm/src/builtins/mappingproxy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl PyMappingProxy {
176176

177177
#[pyclassmethod]
178178
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
179-
PyGenericAlias::new(cls, args, vm)
179+
PyGenericAlias::from_args(cls, args, vm)
180180
}
181181

182182
#[pymethod]

vm/src/builtins/set.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ impl PySet {
790790

791791
#[pyclassmethod]
792792
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
793-
PyGenericAlias::new(cls, args, vm)
793+
PyGenericAlias::from_args(cls, args, vm)
794794
}
795795
}
796796

@@ -1134,7 +1134,7 @@ impl PyFrozenSet {
11341134

11351135
#[pyclassmethod]
11361136
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
1137-
PyGenericAlias::new(cls, args, vm)
1137+
PyGenericAlias::from_args(cls, args, vm)
11381138
}
11391139
}
11401140

vm/src/builtins/tuple.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl PyTuple {
343343

344344
#[pyclassmethod]
345345
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
346-
PyGenericAlias::new(cls, args, vm)
346+
PyGenericAlias::from_args(cls, args, vm)
347347
}
348348
}
349349

0 commit comments

Comments
 (0)