diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 4a43c2a16d52..4fecbfdcbbfd 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -9,7 +9,7 @@ from mypy.applytype import apply_generic_arguments from mypy.checker import TypeChecker from mypy.errorcodes import LITERAL_REQ -from mypy.expandtype import expand_type +from mypy.expandtype import expand_type, expand_type_by_instance from mypy.exprtotype import TypeTranslationError, expr_to_unanalyzed_type from mypy.messages import format_type_bare from mypy.nodes import ( @@ -986,6 +986,8 @@ def evolve_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> Callabl ) return ctx.default_signature + attrs_init_type = expand_type_by_instance(attrs_init_type, attrs_type) + # AttrClass.__init__ has the following signature (or similar, if having kw-only & defaults): # def __init__(self, attr1: Type1, attr2: Type2) -> None: # We want to generate a signature for evolve that looks like this: diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index 45c673b269c5..d0caac4f860e 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -1970,6 +1970,26 @@ reveal_type(ret) # N: Revealed type is "Any" [typing fixtures/typing-medium.pyi] +[case testEvolveGeneric] +import attrs +from typing import Generic, TypeVar + +T = TypeVar('T') + +@attrs.define +class A(Generic[T]): + x: T + + +a = A(x=42) +reveal_type(a) # N: Revealed type is "__main__.A[builtins.int]" +a2 = attrs.evolve(a, x=42) +reveal_type(a2) # N: Revealed type is "__main__.A[builtins.int]" +a2 = attrs.evolve(a, x='42') # E: Argument "x" to "evolve" of "A[int]" has incompatible type "str"; expected "int" +reveal_type(a2) # N: Revealed type is "__main__.A[builtins.int]" + +[builtins fixtures/attr.pyi] + [case testEvolveTypeVarBound] import attrs from typing import TypeVar