Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Address part of CR
  • Loading branch information
hamdanal committed Feb 20, 2024
commit 310c75d7c625c2d05ab5df0655c662652e268fe7
9 changes: 6 additions & 3 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2022,7 +2022,7 @@ def analyze_unbound_tvar_impl(
self, t: UnboundType, is_unpacked: bool = False, is_typealias_param: bool = False
) -> tuple[str, TypeVarLikeExpr] | None:
if is_unpacked and is_typealias_param:
return None # This should be unreachable
assert False, "Unreachable"
sym = self.lookup_qualified(t.name, t)
if sym and isinstance(sym.node, PlaceholderNode):
self.record_incomplete_ref()
Expand Down Expand Up @@ -3538,6 +3538,7 @@ def analyze_alias(
in_dynamic_func=dynamic,
global_scope=global_scope,
allowed_alias_tvars=tvar_defs,
has_type_params=declared_type_vars is not None,
)

# There can be only one variadic variable at most, the error is reported elsewhere.
Expand Down Expand Up @@ -3588,9 +3589,11 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
type_params: TypeVarLikeList | None
if self.check_type_alias_type_call(s.rvalue, name=lvalue.name):
rvalue = s.rvalue.args[1]
pep_695 = True
type_params = self.analyze_type_alias_type_params(s.rvalue)
else:
rvalue = s.rvalue
pep_695 = False
type_params = None

if isinstance(rvalue, CallExpr) and rvalue.analyzed:
Expand Down Expand Up @@ -3631,7 +3634,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
# without this rule, this typical use case will require a lot of explicit
# annotations (see the second rule).
return False
if not pep_613 and not self.can_be_type_alias(rvalue):
if not pep_613 and not pep_695 and not self.can_be_type_alias(rvalue):
return False

if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)):
Expand Down Expand Up @@ -3686,7 +3689,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
and isinstance(res, Instance)
and not res.args
and not empty_tuple_index
and type_params is None
and not pep_695
)
if isinstance(res, ProperType) and isinstance(res, Instance):
if not validate_instance(res, self.fail, empty_tuple_index):
Expand Down
36 changes: 24 additions & 12 deletions mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def analyze_type_alias(
in_dynamic_func: bool = False,
global_scope: bool = True,
allowed_alias_tvars: list[TypeVarLikeType] | None = None,
has_type_params: bool = False,
) -> tuple[Type, set[str]]:
"""Analyze r.h.s. of a (potential) type alias definition.

Expand All @@ -153,6 +154,7 @@ def analyze_type_alias(
allow_placeholder=allow_placeholder,
prohibit_self_type="type alias target",
allowed_alias_tvars=allowed_alias_tvars,
has_type_params=has_type_params,
)
analyzer.in_dynamic_func = in_dynamic_func
analyzer.global_scope = global_scope
Expand Down Expand Up @@ -205,6 +207,7 @@ def __init__(
prohibit_self_type: str | None = None,
allowed_alias_tvars: list[TypeVarLikeType] | None = None,
allow_type_any: bool = False,
has_type_params: bool = False,
) -> None:
self.api = api
self.fail_func = api.fail
Expand All @@ -226,6 +229,7 @@ def __init__(
if allowed_alias_tvars is None:
allowed_alias_tvars = []
self.allowed_alias_tvars = allowed_alias_tvars
self.has_type_params = has_type_params
# If false, record incomplete ref if we generate PlaceholderType.
self.allow_placeholder = allow_placeholder
# Are we in a context where Required[] is allowed?
Expand Down Expand Up @@ -320,7 +324,11 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
if tvar_def is None:
if self.allow_unbound_tvars:
return t
self.fail(f'ParamSpec "{t.name}" is unbound', t, code=codes.VALID_TYPE)
if self.has_type_params:
msg = f'ParamSpec "{t.name}" is not included in type_params'
else:
msg = f'ParamSpec "{t.name}" is unbound'
self.fail(msg, t, code=codes.VALID_TYPE)
return AnyType(TypeOfAny.from_error)
assert isinstance(tvar_def, ParamSpecType)
if len(t.args) > 0:
Expand All @@ -344,11 +352,11 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
and not defining_literal
and (tvar_def is None or tvar_def not in self.allowed_alias_tvars)
):
self.fail(
f'Can\'t use bound type variable "{t.name}" to define generic alias',
t,
code=codes.VALID_TYPE,
)
if self.has_type_params:
msg = f'Type variable "{t.name}" is not included in type_params'
else:
msg = f'Can\'t use bound type variable "{t.name}" to define generic alias'
self.fail(msg, t, code=codes.VALID_TYPE)
return AnyType(TypeOfAny.from_error)
if isinstance(sym.node, TypeVarExpr) and tvar_def is not None:
assert isinstance(tvar_def, TypeVarType)
Expand All @@ -363,17 +371,21 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
and self.defining_alias
and tvar_def not in self.allowed_alias_tvars
):
self.fail(
f'Can\'t use bound type variable "{t.name}" to define generic alias',
t,
code=codes.VALID_TYPE,
)
if self.has_type_params:
msg = f'Type variable "{t.name}" is not included in type_params'
else:
msg = f'Can\'t use bound type variable "{t.name}" to define generic alias'
self.fail(msg, t, code=codes.VALID_TYPE)
return AnyType(TypeOfAny.from_error)
if isinstance(sym.node, TypeVarTupleExpr):
if tvar_def is None:
if self.allow_unbound_tvars:
return t
self.fail(f'TypeVarTuple "{t.name}" is unbound', t, code=codes.VALID_TYPE)
if self.has_type_params:
msg = f'TypeVarTuple "{t.name}" is not included in type_params'
else:
msg = f'TypeVarTuple "{t.name}" is unbound'
self.fail(msg, t, code=codes.VALID_TYPE)
return AnyType(TypeOfAny.from_error)
assert isinstance(tvar_def, TypeVarTupleType)
if not self.allow_type_var_tuple:
Expand Down
40 changes: 33 additions & 7 deletions test-data/unit/check-type-aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -1085,17 +1085,18 @@ T1 = T2 = TypeAliasType("T", int)
t1: T1 # E: Variable "__main__.T1" is not valid as a type \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases

T3 = TypeAliasType("T3", -1)
t3: T3 # E: Variable "__main__.T3" is not valid as a type \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
T3 = TypeAliasType("T3", -1) # E: Invalid type: try using Literal[-1] instead?
t3: T3
reveal_type(t3) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]

[case testTypeAliasTypeGeneric]
from typing_extensions import TypeAliasType, TypeVarTuple, ParamSpec
from typing import Callable, Dict, TypeVar, Tuple, Unpack
from typing import Callable, Dict, Generic, TypeVar, Tuple
from typing_extensions import TypeAliasType, TypeVarTuple, ParamSpec, Unpack

K = TypeVar('K')
V = TypeVar('V')
T = TypeVar('T')
Ts = TypeVarTuple("Ts")
Ts1 = TypeVarTuple("Ts1")
P = ParamSpec("P")
Expand Down Expand Up @@ -1123,14 +1124,20 @@ def g(x: int, y: float) -> int: return 1
xp1: ParamAlias[str, float] = f
xp2: ParamAlias[str, float] = g # E: Incompatible types in assignment (expression has type "Callable[[int, float], int]", variable has type "Callable[[str, float], int]")
xp3: ParamAlias[str, float] = lambda x, y: 1

class G(Generic[P, T]): ...
ParamAlias2 = TypeAliasType("ParamAlias2", G[P, T], type_params=(P, T))
xp: ParamAlias2[[int], str]
reveal_type(xp) # N: Revealed type is "__main__.G[[builtins.int], builtins.str]"
[builtins fixtures/dict.pyi]

[case testTypeAliasTypeInvalidGeneric]
from typing_extensions import TypeAliasType, TypeVarTuple, ParamSpec
from typing import Dict, TypeVar, Tuple, Unpack
from typing import Callable, Dict, Generic, TypeVar, Tuple, Unpack

K = TypeVar('K')
V = TypeVar('V')
T = TypeVar('T')
Ts = TypeVarTuple("Ts")
Ts1 = TypeVarTuple("Ts1")
P = ParamSpec("P")
Expand All @@ -1139,7 +1146,7 @@ Ta1 = TypeAliasType("Ta1", int, type_params=K) # E: Tuple literal expected as t

Ta2 = TypeAliasType("Ta2", int, type_params=(None,)) # E: Free type variable expected in type_params argument to TypeAliasType

Ta3 = TypeAliasType("Ta3", Dict[K, V], type_params=(V,)) # E: Can't use bound type variable "K" to define generic alias
Ta3 = TypeAliasType("Ta3", Dict[K, V], type_params=(V,)) # E: Type variable "K" is not included in type_params
partially_generic1: Ta3[int] = {"a": 1}
reveal_type(partially_generic1) # N: Revealed type is "builtins.dict[Any, builtins.int]"
partially_generic2: Ta3[int] = {1: "a"} # E: Dict entry 0 has incompatible type "int": "str"; expected "Any": "int"
Expand All @@ -1148,6 +1155,25 @@ Ta4 = TypeAliasType("Ta4", Tuple[Unpack[Ts]], type_params=(Ts, Ts1)) # E: Can o

Ta5 = TypeAliasType("Ta5", Dict) # Unlike old style aliases, this is not generic
Comment thread
JelleZijlstra marked this conversation as resolved.
non_generic_dict: Ta5[int, str] # E: Bad number of arguments for type alias, expected 0, given 2
reveal_type(non_generic_dict) # N: Revealed type is "builtins.dict[Any, Any]"

Ta6 = TypeAliasType("Ta6", Tuple[Unpack[Ts]]) # E: TypeVarTuple "Ts" is not included in type_params
unbound_tvt_alias: Ta6[int] # E: Bad number of arguments for type alias, expected 0, given 1
reveal_type(unbound_tvt_alias) # N: Revealed type is "builtins.tuple[Any, ...]"

class G(Generic[P, T]): ...
Ta7 = TypeAliasType("Ta7", G[P, T]) # E: ParamSpec "P" is not included in type_params \
# E: Type variable "T" is not included in type_params
unbound_ps_alias: Ta7[[int], str] # E: Bracketed expression "[...]" is not valid as a type \
# N: Did you mean "List[...]"? \
# E: Bad number of arguments for type alias, expected 0, given 2
reveal_type(unbound_ps_alias) # N: Revealed type is "__main__.G[Any, Any]"

# TODO this does not work yet, it should report unbound P
# Ta8 = TypeAliasType("Ta8", Callable[P, int])
# unbound_ps_alias: Ta8[int]
# reveal_type(unbound_ps_alias)
Comment thread
JelleZijlstra marked this conversation as resolved.
Outdated


[builtins fixtures/dict.pyi]

Expand Down