66import re
77import difflib
88
9- from typing import cast , List , Dict , Any , Sequence , Iterable
9+ from typing import cast , List , Dict , Any , Sequence , Iterable , Tuple
1010
1111from mypy .errors import Errors
1212from mypy .types import (
@@ -136,12 +136,12 @@ def note(self, msg: str, context: Context, file: str = None) -> None:
136136 """Report an error message (unless disabled)."""
137137 self .report (msg , context , 'note' , file = file )
138138
139- def format (self , typ : Type , verbose : bool = False ) -> str :
139+ def format (self , typ : Type , verbosity : int = 0 ) -> str :
140140 """Convert a type to a relatively short string that is suitable for error messages.
141141
142142 Mostly behave like format_simple below, but never return an empty string.
143143 """
144- s = self .format_simple (typ )
144+ s = self .format_simple (typ , verbosity )
145145 if s != '' :
146146 # If format_simple returns a non-trivial result, use that.
147147 return s
@@ -152,7 +152,7 @@ def format(self, typ: Type, verbose: bool = False) -> str:
152152 # return type (this always works).
153153 itype = cast (Instance , func .items ()[0 ].ret_type )
154154 result = self .format (itype )
155- if verbose :
155+ if verbosity >= 1 :
156156 # In some contexts we want to be explicit about the distinction
157157 # between type X and the type of type object X.
158158 result += ' (type object)'
@@ -172,7 +172,7 @@ def format(self, typ: Type, verbose: bool = False) -> str:
172172 # Default case; we simply have to return something meaningful here.
173173 return 'object'
174174
175- def format_simple (self , typ : Type ) -> str :
175+ def format_simple (self , typ : Type , verbosity : int = 0 ) -> str :
176176 """Convert simple types to string that is suitable for error messages.
177177
178178 Return "" for complex types. Try to keep the length of the result
@@ -187,7 +187,10 @@ def format_simple(self, typ: Type) -> str:
187187 if isinstance (typ , Instance ):
188188 itype = cast (Instance , typ )
189189 # Get the short name of the type.
190- base_str = itype .type .name ()
190+ if verbosity >= 2 :
191+ base_str = itype .type .fullname ()
192+ else :
193+ base_str = itype .type .name ()
191194 if itype .args == []:
192195 # No type arguments. Place the type name in quotes to avoid
193196 # potential for confusion: otherwise, the type name could be
@@ -252,6 +255,19 @@ def format_simple(self, typ: Type) -> str:
252255 # message.
253256 return ''
254257
258+ def format_distinctly (self , type1 : Type , type2 : Type ) -> Tuple [str , str ]:
259+ """Jointly format a pair of types to distinct strings.
260+
261+ Increase the verbosity of the type strings until they become distinct.
262+ """
263+ verbosity = 0
264+ for verbosity in range (3 ):
265+ str1 = self .format (type1 , verbosity = verbosity )
266+ str2 = self .format (type2 , verbosity = verbosity )
267+ if str1 != str2 :
268+ return (str1 , str2 )
269+ return (str1 , str2 )
270+
255271 #
256272 # Specific operations
257273 #
@@ -432,12 +448,7 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
432448 expected_type = callee .arg_types [m - 1 ]
433449 except IndexError : # Varargs callees
434450 expected_type = callee .arg_types [- 1 ]
435- arg_type_str = self .format (arg_type )
436- expected_type_str = self .format (expected_type )
437- # If type names turn out ambiguous, attempt to disambiguate.
438- if arg_type_str == expected_type_str :
439- arg_type_str = self .format (arg_type , verbose = True )
440- expected_type_str = self .format (expected_type , verbose = True )
451+ arg_type_str , expected_type_str = self .format_distinctly (arg_type , expected_type )
441452 msg = 'Argument {} {}has incompatible type {}; expected {}' .format (
442453 n , target , arg_type_str , expected_type_str )
443454 self .fail (msg , context )
0 commit comments