Skip to content

Get rid of MDEF and LDEF [WIP] #2555

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

Closed
wants to merge 7 commits into from
Closed
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
5 changes: 2 additions & 3 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2284,9 +2284,8 @@ def in_checked_function(self) -> bool:
or not self.dynamic_funcs
or not self.dynamic_funcs[-1])

def lookup(self, name: str, kind: int) -> SymbolTableNode:
def lookup(self, name: str) -> SymbolTableNode:
"""Look up a definition from the symbol table with the given name.
TODO remove kind argument
"""
if name in self.globals:
return self.globals[name]
Expand All @@ -2300,7 +2299,7 @@ def lookup(self, name: str, kind: int) -> SymbolTableNode:

def lookup_qualified(self, name: str) -> SymbolTableNode:
if '.' not in name:
return self.lookup(name, GDEF) # FIX kind
return self.lookup(name)
else:
parts = name.split('.')
n = self.modules[parts[0]]
Expand Down
5 changes: 2 additions & 3 deletions mypy/fixup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from mypy.nodes import (
MypyFile, SymbolNode, SymbolTable, SymbolTableNode,
TypeInfo, FuncDef, OverloadedFuncDef, Decorator, Var,
TypeVarExpr, ClassDef,
LDEF, MDEF, GDEF
TypeVarExpr, ClassDef, GDEF,
)
from mypy.types import (
CallableType, EllipsisType, Instance, Overloaded, TupleType, TypedDictType,
Expand All @@ -27,7 +26,7 @@ def fixup_module_pass_two(tree: MypyFile, modules: Dict[str, MypyFile]) -> None:

def compute_all_mros(symtab: SymbolTable, modules: Dict[str, MypyFile]) -> None:
for key, value in symtab.items():
if value.kind in (LDEF, MDEF, GDEF) and isinstance(value.node, TypeInfo):
if value.kind == GDEF and isinstance(value.node, TypeInfo):
info = value.node
info.calculate_mro()
assert info.mro, "No MRO calculated for %s" % (info.fullname(),)
Expand Down
8 changes: 1 addition & 7 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ def get_column(self) -> int: pass
#
# TODO rename to use more descriptive names

LDEF = 0 # type: int
GDEF = 1 # type: int
MDEF = 2 # type: int
MODULE_REF = 3 # type: int
# Type variable declared using TypeVar(...) has kind UNBOUND_TVAR. It's not
# valid as a type. A type variable is valid as a type (kind BOUND_TVAR) within
Expand All @@ -62,9 +60,7 @@ def get_column(self) -> int: pass
ENUM_BASECLASS = "enum.Enum"

node_kinds = {
LDEF: 'Ldef',
GDEF: 'Gdef',
MDEF: 'Mdef',
MODULE_REF: 'ModuleRef',
UNBOUND_TVAR: 'UnboundTvar',
BOUND_TVAR: 'Tvar',
Expand Down Expand Up @@ -1132,7 +1128,7 @@ def accept(self, visitor: NodeVisitor[T]) -> T:
class RefExpr(Expression):
"""Abstract base class for name-like constructs"""

kind = None # type: int # LDEF/GDEF/MDEF/... (None if not available)
kind = None # type: int # GDEF, MODULE_REF etc. (None if not available)
node = None # type: SymbolNode # Var, FuncDef or TypeInfo that describes this
fullname = None # type: str # Fully qualified name (or name if not global)

Expand Down Expand Up @@ -2078,9 +2074,7 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo':

class SymbolTableNode:
# Kind of node. Possible values:
# - LDEF: local definition (of any kind)
# - GDEF: global (module-level) definition
# - MDEF: class member definition
# - UNBOUND_TVAR: TypeVar(...) definition, not bound
# - TVAR: type variable in a bound scope (generic function / generic clas)
# - MODULE_REF: reference to a module
Expand Down
76 changes: 31 additions & 45 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@
from mypy.nodes import (
MypyFile, TypeInfo, Node, AssignmentStmt, FuncDef, OverloadedFuncDef,
ClassDef, Var, GDEF, MODULE_REF, FuncItem, Import, Expression, Lvalue,
ImportFrom, ImportAll, Block, LDEF, NameExpr, MemberExpr,
ImportFrom, ImportAll, Block, NameExpr, MemberExpr,
IndexExpr, TupleExpr, ListExpr, ExpressionStmt, ReturnStmt,
RaiseStmt, AssertStmt, OperatorAssignmentStmt, WhileStmt,
ForStmt, BreakStmt, ContinueStmt, IfStmt, TryStmt, WithStmt, DelStmt, PassStmt,
GlobalDecl, SuperExpr, DictExpr, CallExpr, RefExpr, OpExpr, UnaryExpr,
SliceExpr, CastExpr, RevealTypeExpr, TypeApplication, Context, SymbolTable,
SymbolTableNode, BOUND_TVAR, UNBOUND_TVAR, ListComprehension, GeneratorExpr,
FuncExpr, MDEF, FuncBase, Decorator, SetExpr, TypeVarExpr, NewTypeExpr,
FuncExpr, FuncBase, Decorator, SetExpr, TypeVarExpr, NewTypeExpr,
StrExpr, BytesExpr, PrintStmt, ConditionalExpr, PromoteExpr,
ComparisonExpr, StarExpr, ARG_POS, ARG_NAMED, ARG_NAMED_OPT, MroError, type_aliases,
YieldFromExpr, NamedTupleExpr, TypedDictExpr, NonlocalDecl, SymbolNode,
Expand Down Expand Up @@ -285,7 +285,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
n = self.type.names[defn.name()].node
if not self.set_original_def(n, defn):
self.name_already_defined(defn.name(), defn)
self.type.names[defn.name()] = SymbolTableNode(MDEF, defn)
self.type.names[defn.name()] = SymbolTableNode(GDEF, defn)
self.prepare_method_signature(defn)
elif self.is_func_scope():
# Nested function
Expand Down Expand Up @@ -438,7 +438,7 @@ def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
defn.type.line = defn.line

if self.is_class_scope():
self.type.names[defn.name()] = SymbolTableNode(MDEF, defn,
self.type.names[defn.name()] = SymbolTableNode(GDEF, defn,
typ=defn.type)
defn.info = self.type
elif self.is_func_scope():
Expand Down Expand Up @@ -738,7 +738,7 @@ def analyze_namedtuple_classdef(self, defn: ClassDef) -> bool:
if base_expr.fullname == 'typing.NamedTuple':
node = self.lookup(defn.name, defn)
if node is not None:
node.kind = GDEF # TODO in process_namedtuple_definition also applies here
node.kind = GDEF
items, types = self.check_namedtuple_classdef(defn)
node.node = self.build_namedtuple_typeinfo(defn.name, items, types)
return True
Expand Down Expand Up @@ -786,10 +786,7 @@ def setup_class_def_analysis(self, defn: ClassDef) -> None:
defn.info = TypeInfo(SymbolTable(), defn, self.cur_mod_id)
defn.info._fullname = defn.info.name()
if self.is_func_scope() or self.type:
kind = MDEF
if self.is_func_scope():
kind = LDEF
self.add_symbol(defn.name, SymbolTableNode(kind, defn.info), defn)
self.add_symbol(defn.name, SymbolTableNode(GDEF, defn.info), defn)

def analyze_base_classes(self, defn: ClassDef) -> None:
"""Analyze and set up base classes.
Expand Down Expand Up @@ -1037,7 +1034,7 @@ def process_import_over_existing_name(self,
imported_id: str, existing_symbol: SymbolTableNode,
module_symbol: SymbolTableNode,
import_node: ImportBase) -> bool:
if (existing_symbol.kind in (LDEF, GDEF, MDEF) and
if (existing_symbol.kind == GDEF and
isinstance(existing_symbol.node, (Var, FuncDef, TypeInfo))):
# This is a valid import over an existing definition in the file. Construct a dummy
# assignment that we'll use to type check the import.
Expand Down Expand Up @@ -1286,7 +1283,7 @@ def analyze_lvalue(self, lval: Lvalue, nested: bool = False,
v = Var(lval.name)
lval.node = v
lval.is_def = True
lval.kind = LDEF
lval.kind = GDEF
lval.fullname = lval.name
self.add_local(v, lval)
elif not self.is_func_scope() and (self.type and
Expand All @@ -1298,9 +1295,9 @@ def analyze_lvalue(self, lval: Lvalue, nested: bool = False,
v.set_line(lval)
lval.node = v
lval.is_def = True
lval.kind = MDEF
lval.kind = GDEF
lval.fullname = lval.name
self.type.names[lval.name] = SymbolTableNode(MDEF, v)
self.type.names[lval.name] = SymbolTableNode(GDEF, v)
else:
# Bind to an existing name.
if explicit_type:
Expand Down Expand Up @@ -1359,7 +1356,7 @@ def analyze_member_lvalue(self, lval: MemberExpr) -> None:
v.is_ready = False
lval.def_var = v
lval.node = v
self.type.names[lval.name] = SymbolTableNode(MDEF, v)
self.type.names[lval.name] = SymbolTableNode(GDEF, v)
self.check_lvalue_validity(lval.node, lval)

def is_self_member_ref(self, memberexpr: MemberExpr) -> bool:
Expand Down Expand Up @@ -1430,7 +1427,6 @@ def process_newtype_declaration(self, s: AssignmentStmt) -> None:
if node is None:
self.fail("Could not find {} in current namespace".format(name), s)
return
# TODO: why does NewType work in local scopes despite always being of kind GDEF?
node.kind = GDEF
call.analyzed.info = node.node = newtype_class_info

Expand Down Expand Up @@ -1504,7 +1500,7 @@ def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance)
name=name)
init_func = FuncDef('__init__', args, Block([]), typ=signature)
init_func.info = info
info.names['__init__'] = SymbolTableNode(MDEF, init_func)
info.names['__init__'] = SymbolTableNode(GDEF, init_func)

return info

Expand Down Expand Up @@ -1651,7 +1647,7 @@ def process_namedtuple_definition(self, s: AssignmentStmt) -> None:
return
# Yes, it's a valid namedtuple definition. Add it to the symbol table.
node = self.lookup(name, s)
node.kind = GDEF # TODO locally defined namedtuple
node.kind = GDEF
node.node = named_tuple

def check_namedtuple(self, node: Expression, var_name: str = None) -> Optional[TypeInfo]:
Expand Down Expand Up @@ -1795,7 +1791,7 @@ def add_field(var: Var, is_initialized_in_class: bool = False,
var.info = info
var.is_initialized_in_class = is_initialized_in_class
var.is_property = is_property
info.names[var.name()] = SymbolTableNode(MDEF, var)
info.names[var.name()] = SymbolTableNode(GDEF, var)

vars = [Var(item, typ) for item, typ in zip(items, types)]
for var in vars:
Expand Down Expand Up @@ -1831,9 +1827,9 @@ def add_method(funcname: str, ret: Type, args: List[Argument], name=None,
v.is_classmethod = True
v.info = info
dec = Decorator(func, [NameExpr('classmethod')], v)
info.names[funcname] = SymbolTableNode(MDEF, dec)
info.names[funcname] = SymbolTableNode(GDEF, dec)
else:
info.names[funcname] = SymbolTableNode(MDEF, func)
info.names[funcname] = SymbolTableNode(GDEF, func)

add_method('_replace', ret=selftype,
args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars])
Expand Down Expand Up @@ -1870,7 +1866,7 @@ def process_typeddict_definition(self, s: AssignmentStmt) -> None:
return
# Yes, it's a valid TypedDict definition. Add it to the symbol table.
node = self.lookup(name, s)
node.kind = GDEF # TODO locally defined TypedDict
node.kind = GDEF
node.node = typed_dict

def check_typeddict(self, node: Expression, var_name: str = None) -> Optional[TypeInfo]:
Expand Down Expand Up @@ -2009,12 +2005,12 @@ def visit_decorator(self, dec: Decorator) -> None:
del dec.decorators[i]
if not dec.is_overload or dec.var.is_property:
if self.is_func_scope():
self.add_symbol(dec.var.name(), SymbolTableNode(LDEF, dec),
self.add_symbol(dec.var.name(), SymbolTableNode(GDEF, dec),
dec)
elif self.type:
dec.var.info = self.type
dec.var.is_initialized_in_class = True
self.add_symbol(dec.var.name(), SymbolTableNode(MDEF, dec),
self.add_symbol(dec.var.name(), SymbolTableNode(GDEF, dec),
dec)
if not no_type_check:
dec.func.accept(self)
Expand Down Expand Up @@ -2704,7 +2700,7 @@ def add_local(self, node: Union[Var, FuncDef, OverloadedFuncDef], ctx: Context)
if name in self.locals[-1]:
self.name_already_defined(name, ctx)
node._fullname = name
self.locals[-1][name] = SymbolTableNode(LDEF, node)
self.locals[-1][name] = SymbolTableNode(GDEF, node)

def add_exports(self, *exps: Expression) -> None:
for exp in exps:
Expand Down Expand Up @@ -2881,25 +2877,25 @@ def visit_func_def(self, func: FuncDef) -> None:
sem.function_stack.pop()

def visit_overloaded_func_def(self, func: OverloadedFuncDef) -> None:
kind = self.kind_by_scope()
if kind == GDEF:
at_module = self.sem.is_module_scope()
if at_module:
self.sem.check_no_global(func.name(), func, True)
func._fullname = self.sem.qualified_name(func.name())
if kind == GDEF:
self.sem.globals[func.name()] = SymbolTableNode(kind, func, self.sem.cur_mod_id)
if at_module:
self.sem.globals[func.name()] = SymbolTableNode(GDEF, func, self.sem.cur_mod_id)

def visit_class_def(self, cdef: ClassDef) -> None:
kind = self.kind_by_scope()
if kind == LDEF:
if self.sem.is_func_scope():
return
elif kind == GDEF:
at_module = not self.sem.is_class_scope()
if at_module:
self.sem.check_no_global(cdef.name, cdef)
cdef.fullname = self.sem.qualified_name(cdef.name)
info = TypeInfo(SymbolTable(), cdef, self.sem.cur_mod_id)
info.set_line(cdef.line, cdef.column)
cdef.info = info
if kind == GDEF:
self.sem.globals[cdef.name] = SymbolTableNode(kind, info, self.sem.cur_mod_id)
if at_module:
self.sem.globals[cdef.name] = SymbolTableNode(GDEF, info, self.sem.cur_mod_id)
self.process_nested_classes(cdef)

def process_nested_classes(self, outer_def: ClassDef) -> None:
Expand All @@ -2912,7 +2908,7 @@ def process_nested_classes(self, outer_def: ClassDef) -> None:
else:
node.info._fullname = node.info.name()
node.fullname = node.info._fullname
symbol = SymbolTableNode(MDEF, node.info)
symbol = SymbolTableNode(GDEF, node.info)
outer_def.info.names[node.name] = symbol
self.process_nested_classes(node)
elif isinstance(node, (ImportFrom, Import, ImportAll, IfStmt)):
Expand Down Expand Up @@ -2970,7 +2966,7 @@ def visit_with_stmt(self, s: WithStmt) -> None:

def visit_decorator(self, d: Decorator) -> None:
d.var._fullname = self.sem.qualified_name(d.var.name())
self.sem.add_symbol(d.var.name(), SymbolTableNode(self.kind_by_scope(), d.var), d)
self.sem.add_symbol(d.var.name(), SymbolTableNode(GDEF, d.var), d)

def visit_if_stmt(self, s: IfStmt) -> None:
infer_reachability_of_if_statement(s, pyversion=self.pyversion, platform=self.platform)
Expand All @@ -2987,16 +2983,6 @@ def analyze_lvalue(self, lvalue: Lvalue, explicit_type: bool = False) -> None:
self.sem.analyze_lvalue(lvalue, add_global=self.sem.is_module_scope(),
explicit_type=explicit_type)

def kind_by_scope(self) -> int:
if self.sem.is_module_scope():
return GDEF
elif self.sem.is_class_scope():
return MDEF
elif self.sem.is_func_scope():
return LDEF
else:
assert False, "Couldn't determine scope"


class ThirdPass(TraverserVisitor):
"""The third and final pass of semantic analysis.
Expand Down
11 changes: 2 additions & 9 deletions mypy/strconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,9 @@ def pretty_name(self, name: str, kind: int, fullname: str, is_def: bool) -> str:
n = name
if is_def:
n += '*'
if kind == mypy.nodes.GDEF or (fullname != name and
fullname is not None):
# Append fully qualified name for global references.
if fullname is not None and fullname != name:
# Append fully qualified name if non-trivially different.
n += ' [{}]'.format(fullname)
elif kind == mypy.nodes.LDEF:
# Add tag to signify a local reference.
n += ' [l]'
elif kind == mypy.nodes.MDEF:
# Add tag to signify a member reference.
n += ' [m]'
return n

def visit_member_expr(self, o: 'mypy.nodes.MemberExpr') -> str:
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/semanal-abstractclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ MypyFile:1(
Abstract
Block:8(
ReturnStmt:8(
NameExpr(self [l])))))))
NameExpr(self)))))))

[case testClassInheritingTwoAbstractClasses]
from abc import abstractmethod, ABCMeta
Expand Down
Loading