Skip to content

New semantic analyzer: track line numbers of placeholders #6983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 15 additions & 9 deletions mypy/newsemanal/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None:
self.add_symbol(name, var, dummy_context())
else:
self.add_symbol(name,
PlaceholderNode(self.qualified_name(name), file_node),
PlaceholderNode(self.qualified_name(name), file_node, -1),
dummy_context())

def add_builtin_aliases(self, tree: MypyFile) -> None:
Expand Down Expand Up @@ -994,8 +994,8 @@ def analyze_class(self, defn: ClassDef) -> None:
# resolved. We don't want this to cause a deferral, since if there
# are no incomplete references, we'll replace this with a TypeInfo
# before returning.
self.add_symbol(defn.name, PlaceholderNode(fullname, defn, True), defn,
can_defer=False)
placeholder = PlaceholderNode(fullname, defn, defn.line, becomes_typeinfo=True)
self.add_symbol(defn.name, placeholder, defn, can_defer=False)

tag = self.track_incomplete_refs()

Expand Down Expand Up @@ -1607,6 +1607,7 @@ def analyze_metaclass(self, defn: ClassDef) -> None:
#

def visit_import(self, i: Import) -> None:
self.statement = i
for id, as_id in i.ids:
if as_id is not None:
self.add_module_symbol(id, as_id, module_public=True, context=i)
Expand Down Expand Up @@ -1668,6 +1669,7 @@ def allow_patching(self, parent_mod: MypyFile, child: str) -> bool:
return False

def visit_import_from(self, imp: ImportFrom) -> None:
self.statement = imp
import_id = self.correct_relative_import(imp)
self.add_submodules_to_parent_modules(import_id, True)
module = self.modules.get(import_id)
Expand Down Expand Up @@ -2370,8 +2372,11 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
if self.found_incomplete_ref(tag) or isinstance(res, PlaceholderType):
# Since we have got here, we know this must be a type alias (incomplete refs
# may appear in nested positions), therefore use becomes_typeinfo=True.
self.add_symbol(lvalue.name, PlaceholderNode(self.qualified_name(lvalue.name),
rvalue, becomes_typeinfo=True), s)
placeholder = PlaceholderNode(self.qualified_name(lvalue.name),
rvalue,
s.line,
becomes_typeinfo=True)
self.add_symbol(lvalue.name, placeholder, s)
return True
self.add_type_alias_deps(depends_on)
# In addition to the aliases used, we add deps on unbound
Expand Down Expand Up @@ -3820,7 +3825,8 @@ class C:
return (node is None
or node.line < self.statement.line
or not self.is_defined_in_current_module(node.fullname())
or isinstance(node, TypeInfo))
or isinstance(node, TypeInfo)
or (isinstance(node, PlaceholderNode) and node.becomes_typeinfo))

def is_defined_in_current_module(self, fullname: Optional[str]) -> bool:
if fullname is None:
Expand Down Expand Up @@ -4265,9 +4271,9 @@ def mark_incomplete(self, name: str, node: Node,
self.incomplete = True
elif name not in self.current_symbol_table() and not self.is_global_or_nonlocal(name):
fullname = self.qualified_name(name)
self.add_symbol(name,
PlaceholderNode(fullname, node, becomes_typeinfo),
context=dummy_context())
placeholder = PlaceholderNode(fullname, node, self.statement.line,
becomes_typeinfo=becomes_typeinfo)
self.add_symbol(name, placeholder, context=dummy_context())
self.missing_names.add(name)

def is_incomplete_namespace(self, fullname: str) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions mypy/newsemanal/semanal_newtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def process_newtype_declaration(self, s: AssignmentStmt) -> bool:
if (not call.analyzed or
isinstance(call.analyzed, NewTypeExpr) and not call.analyzed.info):
# Start from labeling this as a future class, as we do for normal ClassDefs.
self.api.add_symbol(name, PlaceholderNode(fullname, s, becomes_typeinfo=True), s,
can_defer=False)
placeholder = PlaceholderNode(fullname, s, s.line, becomes_typeinfo=True)
self.api.add_symbol(name, placeholder, s, can_defer=False)

old_type, should_defer = self.check_newtype_args(name, call, s)
if not call.analyzed:
Expand Down
5 changes: 3 additions & 2 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2792,11 +2792,12 @@ class C(Sequence[C]): ...
something that can support general recursive types.
"""

def __init__(self, fullname: str, node: Node, becomes_typeinfo: bool = False) -> None:
def __init__(self, fullname: str, node: Node, line: int, *,
becomes_typeinfo: bool = False) -> None:
self._fullname = fullname
self.node = node
self.becomes_typeinfo = becomes_typeinfo
self.line = -1
self.line = line

def name(self) -> str:
return self._fullname.split('.')[-1]
Expand Down
17 changes: 16 additions & 1 deletion test-data/unit/check-newsemanal.test
Original file line number Diff line number Diff line change
Expand Up @@ -830,8 +830,8 @@ reveal_type(o.x.t) # E: Revealed type is '__main__.C.Other'
reveal_type(i.t) # E: Revealed type is '__main__.C.Other'

class C:
Out = NamedTuple('Out', [('x', In), ('y', Other)])
In = NamedTuple('In', [('s', str), ('t', Other)])
Out = NamedTuple('Out', [('x', In), ('y', Other)])
class Other: pass


Expand Down Expand Up @@ -2471,3 +2471,18 @@ class Something:

IDS = [87]
[builtins fixtures/list.pyi]

[case testNewAnalyzerPlaceholderFromOuterScope]
import b
[file a.py]
import b
class A(B): ...
class B: ...

[file b.py]
from a import A

class C:
A = A # Initially rvalue will be a placeholder

reveal_type(C.A) # E: Revealed type is 'def () -> a.A'