Skip to content

Commit d9febe6

Browse files
rchen152facebook-github-bot
authored andcommitted
Add extra_items to remaining update() overloads
Summary: With this, PEP 728 support is complete! The remaining conformance failures will be fixed by python/typing#2073. Fixes #946. Reviewed By: PIG208, samwgoldman Differential Revision: D80870312 fbshipit-source-id: 7fcbfbc9e099ca1bbf9cc3ea0e06db793493293e
1 parent 6accf12 commit d9febe6

File tree

2 files changed

+27
-15
lines changed

2 files changed

+27
-15
lines changed

pyrefly/lib/alt/class/typed_dict.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,12 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
273273
fields: &SmallMap<Name, bool>,
274274
) -> ClassSynthesizedField {
275275
let metadata = FuncMetadata::def(self.module().name(), cls.name().clone(), UPDATE_METHOD);
276-
277276
let self_param = self.class_self_param(cls, true);
277+
let extra = if let ExtraItems::Extra(extra) = self.typed_dict_extra_items(cls) {
278+
Some(extra.ty)
279+
} else {
280+
None
281+
};
278282

279283
// ---- Overload: def update(m: Partial[C], /)
280284
let full_typed_dict = self.as_typed_dict_unchecked(cls);
@@ -296,16 +300,15 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
296300
});
297301

298302
// ---- Overload: update(m: Iterable[tuple[Literal["key"], value]], /)
299-
let tuple_types: Vec<Type> = self
303+
let get_tuple = |name, ty| Type::Tuple(Tuple::Concrete(vec![self.name_or_str(name), ty]));
304+
let mut tuple_types: Vec<Type> = self
300305
.names_to_fields(cls, fields)
301306
.filter(|(_, field)| !field.is_read_only()) // filter read-only fields
302-
.map(|(name, field)| {
303-
Type::Tuple(Tuple::Concrete(vec![
304-
name_to_literal_type(name),
305-
field.ty.clone(),
306-
]))
307-
})
307+
.map(|(name, field)| get_tuple(Some(name), field.ty))
308308
.collect();
309+
if let Some(extra) = &extra {
310+
tuple_types.push(get_tuple(None, extra.clone()));
311+
}
309312

310313
let iterable_ty = self.stdlib.iterable(self.unions(tuple_types)).to_type();
311314

@@ -321,13 +324,16 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
321324
});
322325

323326
// ---- Overload: update(*, x=..., y=...)
324-
let keyword_params: Vec<_> = self
327+
let mut keyword_params = self
325328
.names_to_fields(cls, fields)
326329
.filter(|(_, field)| !field.is_read_only()) // filter read-only fields
327330
.map(|(name, field)| {
328331
Param::KwOnly(name.clone(), field.ty.clone(), Required::Optional(None))
329332
})
330-
.collect();
333+
.collect::<Vec<_>>();
334+
if let Some(extra) = extra {
335+
keyword_params.push(Param::Kwargs(None, extra));
336+
}
331337

332338
let overload_kwargs = OverloadType::Function(Function {
333339
signature: Callable::list(
@@ -463,14 +469,18 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
463469
}))
464470
}
465471

472+
fn name_or_str(&self, name: Option<&Name>) -> Type {
473+
if let Some(name) = name {
474+
name_to_literal_type(name)
475+
} else {
476+
self.stdlib.str().clone().to_type()
477+
}
478+
}
479+
466480
fn key_param(&self, name: Option<&Name>) -> Param {
467481
Param::PosOnly(
468482
Some(KEY_PARAM.clone()),
469-
if let Some(name) = name {
470-
name_to_literal_type(name)
471-
} else {
472-
self.stdlib.str().clone().to_type()
473-
},
483+
self.name_or_str(name),
474484
Required::Required,
475485
)
476486
}

pyrefly/lib/test/typed_dict.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,8 @@ class C(TypedDict, extra_items=int):
14611461
def f(a: A, b: B, c: C):
14621462
a.update(b)
14631463
a.update(c) # E: No matching overload
1464+
a.update(x='ok')
1465+
a.update([('x', 'ok')])
14641466
"#,
14651467
);
14661468

0 commit comments

Comments
 (0)