Skip to content

Commit 1de3562

Browse files
rwbartonJukkaL
authored andcommitted
Ensure that generic function type variable ids are fresh
We need to avoid reusing an id that is already assigned to a type variable of an enclosing generic function. Fixes #1335.
1 parent 782578d commit 1de3562

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

mypy/semanal.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class SemanticAnalyzer(NodeVisitor):
169169

170170
# Stack of functions being analyzed
171171
function_stack = None # type: List[FuncItem]
172+
# Stack of next available function type variable ids
173+
next_function_tvar_id_stack = None # type: List[int]
172174

173175
# Status of postponing analysis of nested function bodies. By using this we
174176
# can have mutually recursive nested functions. Values are FUNCTION_x
@@ -198,6 +200,7 @@ def __init__(self, lib_path: List[str], errors: Errors,
198200
self.bound_tvars = None
199201
self.tvar_stack = []
200202
self.function_stack = []
203+
self.next_function_tvar_id_stack = [-1]
201204
self.block_depth = [0]
202205
self.loop_depth = 0
203206
self.lib_path = lib_path
@@ -336,7 +339,9 @@ def update_function_type_variables(self, defn: FuncDef) -> None:
336339
typevars = [(name, tvar) for name, tvar in typevars
337340
if not self.is_defined_type_var(name, defn)]
338341
if typevars:
339-
defs = [TypeVarDef(tvar[0], -i - 1, tvar[1].values, self.object_type(),
342+
next_tvar_id = self.next_function_tvar_id()
343+
defs = [TypeVarDef(tvar[0], next_tvar_id - i,
344+
tvar[1].values, self.object_type(),
340345
tvar[1].variance)
341346
for i, tvar in enumerate(typevars)]
342347
functype.variables = defs
@@ -431,9 +436,17 @@ def analyze_property_with_multi_part_definition(self, defn: OverloadedFuncDef) -
431436
self.fail("Decorated property not supported", item)
432437
item.func.accept(self)
433438

439+
def next_function_tvar_id(self) -> int:
440+
return self.next_function_tvar_id_stack[-1]
441+
434442
def analyze_function(self, defn: FuncItem) -> None:
435443
is_method = self.is_class_scope()
444+
436445
tvarnodes = self.add_func_type_variables_to_symbol_table(defn)
446+
next_function_tvar_id = min([self.next_function_tvar_id()] +
447+
[n.tvar_id - 1 for n in tvarnodes])
448+
self.next_function_tvar_id_stack.append(next_function_tvar_id)
449+
437450
if defn.type:
438451
# Signature must be analyzed in the surrounding scope so that
439452
# class-level imported names and type variables are in scope.
@@ -472,7 +485,9 @@ def analyze_function(self, defn: FuncItem) -> None:
472485
self.postpone_nested_functions_stack.pop()
473486
self.postponed_functions_stack.pop()
474487

488+
self.next_function_tvar_id_stack.pop()
475489
disable_typevars(tvarnodes)
490+
476491
self.leave()
477492
self.function_stack.pop()
478493

mypy/test/data/check-functions.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,15 @@ main:7: error: Callable[..., Any] has no attribute "x"
489489
main: note: In function "h":
490490
main:11: error: Callable[..., Any] has no attribute "x"
491491

492+
[case testNestedGenericFunctions]
493+
from typing import TypeVar
494+
T = TypeVar('T')
495+
U = TypeVar('U')
496+
497+
def outer(x: T) -> T:
498+
def inner(y: U) -> T: ...
499+
return inner(1)
500+
492501

493502
-- Casts
494503
-- -----

0 commit comments

Comments
 (0)