@@ -542,6 +542,7 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
542
542
target = 'to {} ' .format (name )
543
543
544
544
msg = ''
545
+ notes = [] # type: List[str]
545
546
if callee .name == '<list>' :
546
547
name = callee .name [1 :- 1 ]
547
548
n -= 1
@@ -610,7 +611,12 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
610
611
arg_type_str = '**' + arg_type_str
611
612
msg = 'Argument {} {}has incompatible type {}; expected {}' .format (
612
613
n , target , arg_type_str , expected_type_str )
614
+ if isinstance (arg_type , Instance ) and isinstance (expected_type , Instance ):
615
+ notes = append_invariance_notes (notes , arg_type , expected_type )
613
616
self .fail (msg , context )
617
+ if notes :
618
+ for note_msg in notes :
619
+ self .note (note_msg , context )
614
620
615
621
def invalid_index_type (self , index_type : Type , expected_type : Type , base_str : str ,
616
622
context : Context ) -> None :
@@ -1345,6 +1351,33 @@ def pretty_or(args: List[str]) -> str:
1345
1351
return ", " .join (quoted [:- 1 ]) + ", or " + quoted [- 1 ]
1346
1352
1347
1353
1354
+ def append_invariance_notes (notes : List [str ], arg_type : Instance ,
1355
+ expected_type : Instance ) -> List [str ]:
1356
+ """Explain that the type is invariant and give notes for how to solve the issue."""
1357
+ from mypy .subtypes import is_subtype
1358
+ from mypy .sametypes import is_same_type
1359
+ invariant_type = ''
1360
+ covariant_suggestion = ''
1361
+ if (arg_type .type .fullname () == 'builtins.list' and
1362
+ expected_type .type .fullname () == 'builtins.list' and
1363
+ is_subtype (arg_type .args [0 ], expected_type .args [0 ])):
1364
+ invariant_type = 'List'
1365
+ covariant_suggestion = 'Consider using "Sequence" instead, which is covariant'
1366
+ elif (arg_type .type .fullname () == 'builtins.dict' and
1367
+ expected_type .type .fullname () == 'builtins.dict' and
1368
+ is_same_type (arg_type .args [0 ], expected_type .args [0 ]) and
1369
+ is_subtype (arg_type .args [1 ], expected_type .args [1 ])):
1370
+ invariant_type = 'Dict'
1371
+ covariant_suggestion = ('Consider using "Mapping" instead, '
1372
+ 'which is covariant in the value type' )
1373
+ if invariant_type and covariant_suggestion :
1374
+ notes .append (
1375
+ '"{}" is invariant -- see ' .format (invariant_type ) +
1376
+ 'http://mypy.readthedocs.io/en/latest/common_issues.html#variance' )
1377
+ notes .append (covariant_suggestion )
1378
+ return notes
1379
+
1380
+
1348
1381
def make_inferred_type_note (context : Context , subtype : Type ,
1349
1382
supertype : Type , supertype_str : str ) -> str :
1350
1383
"""Explain that the user may have forgotten to type a variable.
0 commit comments