Skip to content

Commit 0ca0ae6

Browse files
author
Roy Williams
committed
Take suggestion from Jukka to have calls to typed dicts always result in exact declared type
See #2621 (comment)
1 parent 465bf00 commit 0ca0ae6

File tree

3 files changed

+15
-8
lines changed

3 files changed

+15
-8
lines changed

mypy/checkexpr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,12 @@ def check_typeddict_call_with_kwargs(self, callee: TypedDictType,
246246
for (item_name, item_expected_type) in callee.items.items():
247247
item_value = kwargs[item_name]
248248

249-
item_actual_type = self.chk.check_simple_assignment(
249+
self.chk.check_simple_assignment(
250250
lvalue_type=item_expected_type, rvalue=item_value, context=item_value,
251251
msg=messages.INCOMPATIBLE_TYPES,
252252
lvalue_name='TypedDict item "{}"'.format(item_name),
253253
rvalue_name='expression')
254-
items[item_name] = item_actual_type
254+
items[item_name] = item_expected_type
255255

256256
mapping_value_type = join.join_type_list(list(items.values()))
257257
fallback = self.chk.named_generic_type('typing.Mapping',

mypy/subtypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
211211
if not left.names_are_wider_than(right):
212212
return False
213213
for (_, l, r) in left.zip(right):
214-
if not is_subtype(l, r, self.check_type_parameter):
214+
if not is_equivalent(l, r, self.check_type_parameter):
215215
return False
216216
# (NOTE: Fallbacks don't matter.)
217217
return True

test-data/unit/check-typeddict.test

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ def convert(op: ObjectPoint) -> Point:
8888
return op # E: Incompatible return value type (got "ObjectPoint", expected "Point")
8989
[builtins fixtures/dict.pyi]
9090

91+
[case testCannotConvertTypedDictToSimilarTypedDictWithWiderItemTypes]
92+
from mypy_extensions import TypedDict
93+
Point = TypedDict('Point', {'x': int, 'y': int})
94+
ObjectPoint = TypedDict('ObjectPoint', {'x': object, 'y': object})
95+
def convert(p: Point) -> ObjectPoint:
96+
return p # E: Incompatible return value type (got "Point", expected "ObjectPoint")
97+
[builtins fixtures/dict.pyi]
98+
9199
[case testCannotConvertTypedDictToSimilarTypedDictWithIncompatibleItemTypes]
92100
from mypy_extensions import TypedDict
93101
Point = TypedDict('Point', {'x': int, 'y': int})
@@ -143,7 +151,6 @@ Point = TypedDict('Point', {'x': int, 'y': int})
143151
def create_point() -> Point:
144152
return Point(x=1.2, y=2.5)
145153
[out]
146-
main:5: error: Incompatible return value type (got "TypedDict(x=float, y=float)", expected "Point")
147154
main:5: error: Incompatible types (expression has type "float", TypedDict item "x" has type "int")
148155
main:5: error: Incompatible types (expression has type "float", TypedDict item "y" has type "int")
149156
[builtins fixtures/dict.pyi]
@@ -214,9 +221,9 @@ CellWithObject = TypedDict('CellWithObject', {'value': object, 'meta': object})
214221
c1 = CellWithInt(value=1, meta=42)
215222
c2 = CellWithObject(value=2, meta='turtle doves')
216223
joined_cells = [c1, c2]
217-
reveal_type(c1) # E: Revealed type is 'TypedDict(value=builtins.int, meta=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])'
218-
reveal_type(c2) # E: Revealed type is 'TypedDict(value=builtins.int, meta=builtins.str, _fallback=typing.Mapping[builtins.str, builtins.object])'
219-
reveal_type(joined_cells) # E: Revealed type is 'builtins.list[TypedDict(value=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]'
224+
reveal_type(c1) # E: Revealed type is 'TypedDict(value=builtins.object, meta=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.object])'
225+
reveal_type(c2) # E: Revealed type is 'TypedDict(value=builtins.object, meta=builtins.object, _fallback=typing.Mapping[builtins.str, builtins.object])'
226+
reveal_type(joined_cells) # E: Revealed type is 'builtins.list[TypedDict(value=builtins.object, _fallback=typing.Mapping[builtins.str, builtins.object])]'
220227
[builtins fixtures/dict.pyi]
221228

222229
[case testJoinOfDisjointTypedDictsIsEmptyTypedDict]
@@ -227,7 +234,7 @@ d1 = Point(x=0, y=0)
227234
d2 = Cell(value='pear tree')
228235
joined_dicts = [d1, d2]
229236
reveal_type(d1) # E: Revealed type is 'TypedDict(x=builtins.int, y=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])'
230-
reveal_type(d2) # E: Revealed type is 'TypedDict(value=builtins.str, _fallback=typing.Mapping[builtins.str, builtins.str])'
237+
reveal_type(d2) # E: Revealed type is 'TypedDict(value=builtins.object, _fallback=typing.Mapping[builtins.str, builtins.object])'
231238
reveal_type(joined_dicts) # E: Revealed type is 'builtins.list[TypedDict(_fallback=typing.Mapping[builtins.str, builtins.None])]'
232239
[builtins fixtures/dict.pyi]
233240

0 commit comments

Comments
 (0)