File tree Expand file tree Collapse file tree 5 files changed +74
-0
lines changed Expand file tree Collapse file tree 5 files changed +74
-0
lines changed Original file line number Diff line number Diff line change @@ -642,6 +642,26 @@ of the above sections.
642642
643643 assert text is not None # OK, check against None is allowed as a special case.
644644
645+ .. option :: --strict-bool
646+
647+ By default ``bool `` values are treated as subtypes of ``int ``,
648+ just like in runtime:
649+
650+ .. code-block :: python
651+
652+ >> > bool .__mro__
653+ (< class ' bool' > , < class ' int' > , < class ' object' > )
654+
655+ While it will work in runtime,
656+ some cases might require a little bit more strictness.
657+ With this flag enabled, you will get the following error:
658+
659+ .. code-block :: python
660+
661+ def requires_int (arg : int ) -> None : ...
662+
663+ requires_int(5 > 0 ) # Error: Argument 1 has incompatible type "bool"; expected "int"
664+
645665 .. option :: --extra-checks
646666
647667 This flag enables additional checks that are technically correct but may be
Original file line number Diff line number Diff line change @@ -843,6 +843,14 @@ def add_invertible_flag(
843843 group = strictness_group ,
844844 )
845845
846+ add_invertible_flag (
847+ "--strict-bool" ,
848+ default = False ,
849+ strict_flag = True ,
850+ help = "Prohib to treat bool as int" ,
851+ group = strictness_group ,
852+ )
853+
846854 add_invertible_flag (
847855 "--extra-checks" ,
848856 default = False ,
Original file line number Diff line number Diff line change @@ -50,6 +50,7 @@ class BuildType:
5050 "mypyc" ,
5151 "strict_concatenate" ,
5252 "strict_equality" ,
53+ "strict_bool" ,
5354 "strict_optional" ,
5455 "warn_no_return" ,
5556 "warn_return_any" ,
@@ -208,6 +209,10 @@ def __init__(self) -> None:
208209 # This makes 1 == '1', 1 in ['1'], and 1 is '1' errors.
209210 self .strict_equality = False
210211
212+ # Prohibit to treat `bool` as `int` in subtyping contexts.
213+ # This makes `1 + True` an error.
214+ self .strict_bool = False
215+
211216 # Deprecated, use extra_checks instead.
212217 self .strict_concatenate = False
213218
Original file line number Diff line number Diff line change @@ -512,6 +512,13 @@ def visit_instance(self, left: Instance) -> bool:
512512 if left .type .alt_promote and left .type .alt_promote .type is right .type :
513513 return True
514514 rname = right .type .fullname
515+ if (
516+ self .options
517+ and self .options .strict_bool
518+ and left .type .fullname == "builtins.bool"
519+ and rname == "builtins.int"
520+ ):
521+ return False
515522 # Always try a nominal check if possible,
516523 # there might be errors that a user wants to silence *once*.
517524 # NamedTuples are a special case, because `NamedTuple` is not listed
Original file line number Diff line number Diff line change @@ -2284,3 +2284,37 @@ class C(Generic[T]): ...
22842284
22852285A = Union[C, List] # OK
22862286[builtins fixtures/list.pyi]
2287+
2288+ [case testStrictBool]
2289+ # flags: --strict-bool --show-error-codes
2290+ from typing import List, Union
2291+
2292+ def a(x: int): ...
2293+ a(True) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2294+ a(False) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2295+
2296+ bl: bool
2297+ a(bl) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2298+
2299+ def b() -> int:
2300+ return bl # E: Incompatible return value type (got "bool", expected "int") [return-value]
2301+
2302+ c: List[int] = [
2303+ True, # E: List item 0 has incompatible type "bool"; expected "int" [list-item]
2304+ False, # E: List item 1 has incompatible type "bool"; expected "int" [list-item]
2305+ bl, # E: List item 2 has incompatible type "bool"; expected "int" [list-item]
2306+ ]
2307+
2308+ # OK:
2309+ def d(x: Union[int, bool], y: bool): ...
2310+ d(1, True)
2311+ d(True, False)
2312+ d(bl, bl)
2313+ [builtins fixtures/list.pyi]
2314+
2315+ [case testStrictBoolWithStrictFlag]
2316+ # flags: --strict
2317+
2318+ def a(x: int) -> None: ...
2319+ b: bool
2320+ a(b) # E: Argument 1 to "a" has incompatible type "bool"; expected "int"
You can’t perform that action at this time.
0 commit comments