From f772d45d967123914872cbb44dec2682586f0abf Mon Sep 17 00:00:00 2001 From: David Euresti Date: Sat, 1 Sep 2018 07:19:18 -0700 Subject: [PATCH 1/2] Avoid type-var collisions by using -1 instead of 1. By convention TypeVars for methods should have negative numbers. Since we're creating these methods we're guaranteed to have -1 free. Fixes #5542 --- mypy/plugins/attrs.py | 2 +- mypy/plugins/dataclasses.py | 4 ++-- mypy/semanal_namedtuple.py | 2 +- test-data/unit/check-attr.test | 16 ++++++++-------- test-data/unit/check-incremental.test | 16 ++++++++-------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 0966c2dee578c..ad38bd2e46dfc 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -458,7 +458,7 @@ def _add_cmp(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None: # AT = TypeVar('AT') # def __lt__(self: AT, other: AT) -> bool # This way comparisons with subclasses will work correctly. - tvd = TypeVarDef('AT', 'AT', 1, [], object_type) + tvd = TypeVarDef('AT', 'AT', -1, [], object_type) tvd_type = TypeVarType(tvd) args = [Argument(Var('other', tvd_type), tvd_type, None, ARG_POS)] for method in ['__lt__', '__le__', '__gt__', '__ge__']: diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index d545b39e7f19f..19e1f615e0f0a 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -113,7 +113,7 @@ def transform(self) -> None: # the same type as self (covariant). Note the # "self_type" parameter to _add_method. obj_type = ctx.api.named_type('__builtins__.object') - cmp_tvar_def = TypeVarDef('T', 'T', 1, [], obj_type) + cmp_tvar_def = TypeVarDef('T', 'T', -1, [], obj_type) cmp_other_type = TypeVarType(cmp_tvar_def) cmp_return_type = ctx.api.named_type('__builtins__.bool') @@ -135,7 +135,7 @@ def transform(self) -> None: # Like for __eq__ and __ne__, we want "other" to match # the self type. obj_type = ctx.api.named_type('__builtins__.object') - order_tvar_def = TypeVarDef('T', 'T', 1, [], obj_type) + order_tvar_def = TypeVarDef('T', 'T', -1, [], obj_type) order_other_type = TypeVarType(order_tvar_def) order_return_type = ctx.api.named_type('__builtins__.bool') order_args = [ diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index e6060d0655de8..094ab51ac98e9 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -333,7 +333,7 @@ def add_field(var: Var, is_initialized_in_class: bool = False, add_field(Var('__annotations__', ordereddictype), is_initialized_in_class=True) add_field(Var('__doc__', strtype), is_initialized_in_class=True) - tvd = TypeVarDef('NT', 'NT', 1, [], info.tuple_type) + tvd = TypeVarDef('NT', 'NT', -1, [], info.tuple_type) selftype = TypeVarType(tvd) def add_method(funcname: str, diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index 8ffb516a8a2ec..f5426197f7933 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -187,10 +187,10 @@ class A: reveal_type(A) # E: Revealed type is 'def (a: builtins.int) -> __main__.A' reveal_type(A.__eq__) # E: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool' reveal_type(A.__ne__) # E: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool' -reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__le__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__gt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__ge__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' +reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__le__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__gt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__ge__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' A(1) < A(2) A(1) <= A(2) @@ -654,10 +654,10 @@ class C(A, B): pass @attr.s class D(A): pass -reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(B.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(C.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(D.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' +reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(B.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(C.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(D.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' A() < A() B() < B() diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 926e05d249da9..26a1f6e7f48be 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -3642,10 +3642,10 @@ from a import A reveal_type(A) # E: Revealed type is 'def (a: builtins.int) -> a.A' reveal_type(A.__eq__) # E: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool' reveal_type(A.__ne__) # E: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool' -reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__le__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__gt__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -reveal_type(A.__ge__) # E: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' +reveal_type(A.__lt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__le__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__gt__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +reveal_type(A.__ge__) # E: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' A(1) < A(2) A(1) <= A(2) @@ -3681,10 +3681,10 @@ class A: main:2: error: Revealed type is 'def (a: builtins.int) -> a.A' main:3: error: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool' main:4: error: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool' -main:5: error: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -main:6: error: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -main:7: error: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' -main:8: error: Revealed type is 'def [AT] (self: AT`1, other: AT`1) -> builtins.bool' +main:5: error: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +main:6: error: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +main:7: error: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' +main:8: error: Revealed type is 'def [AT] (self: AT`-1, other: AT`-1) -> builtins.bool' main:17: error: Unsupported operand types for < ("A" and "int") main:18: error: Unsupported operand types for <= ("A" and "int") main:19: error: Unsupported operand types for > ("A" and "int") From d20bee8eb9583cf2592569d9e34d3d0f09cc7d39 Mon Sep 17 00:00:00 2001 From: David Euresti Date: Sat, 1 Sep 2018 21:19:56 -0700 Subject: [PATCH 2/2] Add test and fix dataclasses test --- test-data/unit/check-attr.test | 12 ++++++++++++ test-data/unit/check-incremental.test | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index f5426197f7933..4a780e536ada2 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -909,3 +909,15 @@ class A: A(None, None) [builtins fixtures/attr.pyi] + +[case testAttrsTypeVarNoCollision] +from typing import TypeVar, Generic +import attr + +T = TypeVar("T", bytes, str) + +# Make sure the generated __le__ (and friends) don't use T for their arguments. +@attr.s(auto_attribs=True) +class A(Generic[T]): + v: T +[builtins fixtures/attr.pyi] diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 26a1f6e7f48be..7be110c72caef 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -4526,10 +4526,10 @@ class A: tmp/b.py:3: error: Revealed type is 'def (a: builtins.int) -> a.A' tmp/b.py:4: error: Revealed type is 'def (builtins.object, builtins.object) -> builtins.bool' tmp/b.py:5: error: Revealed type is 'def (builtins.object, builtins.object) -> builtins.bool' -tmp/b.py:6: error: Revealed type is 'def [T] (self: T`1, other: T`1) -> builtins.bool' -tmp/b.py:7: error: Revealed type is 'def [T] (self: T`1, other: T`1) -> builtins.bool' -tmp/b.py:8: error: Revealed type is 'def [T] (self: T`1, other: T`1) -> builtins.bool' -tmp/b.py:9: error: Revealed type is 'def [T] (self: T`1, other: T`1) -> builtins.bool' +tmp/b.py:6: error: Revealed type is 'def [T] (self: T`-1, other: T`-1) -> builtins.bool' +tmp/b.py:7: error: Revealed type is 'def [T] (self: T`-1, other: T`-1) -> builtins.bool' +tmp/b.py:8: error: Revealed type is 'def [T] (self: T`-1, other: T`-1) -> builtins.bool' +tmp/b.py:9: error: Revealed type is 'def [T] (self: T`-1, other: T`-1) -> builtins.bool' tmp/b.py:18: error: Unsupported operand types for < ("A" and "int") tmp/b.py:19: error: Unsupported operand types for <= ("A" and "int") tmp/b.py:20: error: Unsupported operand types for > ("A" and "int")