Skip to content

Commit 612e943

Browse files
authored
Merge pull request #3394 from Snowapril/fix-ga-param-chaining
Fix `GenericAlias` parameter chaining
2 parents 0de92bd + f6c2999 commit 612e943

File tree

3 files changed

+31
-28
lines changed

3 files changed

+31
-28
lines changed

Lib/test/test_genericalias.py

-4
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,6 @@ def test_exposed_type(self):
173173
self.assertEqual(a.__args__, (int,))
174174
self.assertEqual(a.__parameters__, ())
175175

176-
# TODO: RUSTPYTHON
177-
@unittest.expectedFailure
178176
def test_parameters(self):
179177
from typing import List, Dict, Callable
180178
D0 = dict[str, int]
@@ -214,8 +212,6 @@ def test_parameters(self):
214212
self.assertEqual(L5.__args__, (Callable[[K, V], K],))
215213
self.assertEqual(L5.__parameters__, (K, V))
216214

217-
# TODO: RUSTPYTHON
218-
@unittest.expectedFailure
219215
def test_parameter_chaining(self):
220216
from typing import List, Dict, Union, Callable
221217
self.assertEqual(list[T][int], list[int])

extra_tests/snippets/test_typing.py

-4
This file was deleted.

vm/src/builtins/genericalias.rs

+31-20
Original file line numberDiff line numberDiff line change
@@ -175,20 +175,25 @@ fn is_typevar(obj: &PyObjectRef) -> bool {
175175
}
176176

177177
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
178-
let mut parameters: Vec<PyObjectRef> = vec![];
178+
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
179179
for arg in args.as_slice() {
180180
if is_typevar(arg) {
181-
parameters.push(arg.clone());
182-
} else if let Ok(tuple) = arg
181+
if !parameters.iter().any(|param| param.is(arg)) {
182+
parameters.push(arg.clone());
183+
}
184+
} else if let Ok(subparams) = arg
183185
.clone()
184186
.get_attr("__parameters__", vm)
185187
.and_then(|obj| PyTupleRef::try_from_object(vm, obj))
186188
{
187-
for subparam in tuple.as_slice() {
188-
parameters.push(subparam.clone());
189+
for subparam in subparams.as_slice() {
190+
if !parameters.iter().any(|param| param.is(subparam)) {
191+
parameters.push(subparam.clone());
192+
}
189193
}
190194
}
191195
}
196+
parameters.shrink_to_fit();
192197

193198
PyTuple::new_ref(parameters, &vm.ctx)
194199
}
@@ -204,27 +209,33 @@ fn subs_tvars(
204209
argitems: &[PyObjectRef],
205210
vm: &VirtualMachine,
206211
) -> PyResult {
207-
obj.clone_class()
208-
.get_attr("__parameters__")
212+
obj.clone()
213+
.get_attr("__parameters__", vm)
214+
.ok()
209215
.and_then(|sub_params| {
210216
PyTupleRef::try_from_object(vm, sub_params)
211217
.ok()
212218
.map(|sub_params| {
213-
let sub_args = sub_params
214-
.as_slice()
215-
.iter()
216-
.map(|arg| {
217-
if let Some(idx) = tuple_index(params, arg) {
218-
argitems[idx].clone()
219-
} else {
220-
arg.clone()
221-
}
222-
})
223-
.collect::<Vec<_>>();
224-
let sub_args: PyObjectRef = PyTuple::new_ref(sub_args, &vm.ctx).into();
225-
obj.get_item(sub_args, vm)
219+
if sub_params.len() > 0 {
220+
let sub_args = sub_params
221+
.as_slice()
222+
.iter()
223+
.map(|arg| {
224+
if let Some(idx) = tuple_index(params, arg) {
225+
argitems[idx].clone()
226+
} else {
227+
arg.clone()
228+
}
229+
})
230+
.collect::<Vec<_>>();
231+
let sub_args: PyObjectRef = PyTuple::new_ref(sub_args, &vm.ctx).into();
232+
Some(obj.get_item(sub_args, vm))
233+
} else {
234+
None
235+
}
226236
})
227237
})
238+
.flatten()
228239
.unwrap_or(Ok(obj))
229240
}
230241

0 commit comments

Comments
 (0)