Skip to content

Update documentation of SymbolTableNode #4080

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 3 commits into from
Oct 9, 2017
Merged
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
48 changes: 42 additions & 6 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2233,19 +2233,53 @@ def __getattribute__(self, attr: str) -> None:


class SymbolTableNode:
"""Description of a name binding in a symbol table.

These are only used as values in module (global), function (local)
and class symbol tables (see SymbolTable). The name that is bound is
the key in SymbolTable.

Symbol tables don't contain direct references to AST nodes primarily
because there can be multiple symbol table references to a single
AST node (due to imports and aliases), and different references can
behave differently. This class describes the unique properties of
each reference.

The most fundamental attributes are 'kind' and 'node'. The 'node'
attribute defines the AST node that the name refers to.

For many bindings, including those targeting variables, functions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it will be helpful to note that this is a bit similar to how CPython symbol tables work. There are no .node, only .kind (and there are more than three kinds however). These kinds are used to emit correct lookup opcodes, so that the right .node will be found by the interpreter at runtime (I know this comparison is vague).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm talking about CPython implementation details might not be helpful, as many readers likely aren't familiar with them.

and classes, the kind is one of LDEF, GDEF or MDEF, depending on the
scope of the definition. These three kinds can usually be used
interchangeably and the difference between local, global and class
scopes is mostly descriptive, with no semantic significance.
However, some tools that consume mypy ASTs may care about these so
they should be correct.

A few definitions get special kinds, including type variables (TVAR),
imported modules and module aliases (MODULE_REF), and type aliases
(TYPE_ALIAS).

Type aliases are very special and have additional attributes that
are only used for them ('type_override', 'alias_tvars' at least).
"""
# TODO: This is a mess. Refactor!
# TODO: Describe how type aliases work.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type aliases are quite complicated (due to several corner cases). I tried to make some simplifications recently. It seems to me that we can introduce a dedicated SybmolNode (like Var or TypeInfo) and deprecate type_override and friends and just point .node to this new symbol node. This is major refactoring, but I think it may help.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I was thinking about. I'd also like to deprecate the special handling of module references and other special node kinds so that we could remove the kind attribute and replace it with a scope attribute, with only 3 possible values, corresponding to LDEF, GDEF and MDEF. Not sure how feasible this would be. It would be quite a big refactoring in any case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it makes sense to open an issue to track this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #4082.


# Kind of node. Possible values:
# - LDEF: local definition (of any kind)
# - LDEF: local definition
# - GDEF: global (module-level) definition
# - MDEF: class member definition
# - TVAR: TypeVar(...) definition
# - TVAR: TypeVar(...) definition in any scope
# - MODULE_REF: reference to a module
# - TYPE_ALIAS: type alias
# - UNBOUND_IMPORTED: temporary kind for imported names
# - UNBOUND_IMPORTED: temporary kind for imported names (we don't know the final kind yet)
kind = None # type: int
# AST node of definition (FuncDef/Var/TypeInfo/Decorator/TypeVarExpr,
# AST node of definition (among others, this can be FuncDef/Var/TypeInfo/TypeVarExpr/MypyFile,
# or None for a bound type variable).
node = None # type: Optional[SymbolNode]
# If this not None, override the type of the 'node' attribute.
# If this not None, override the type of the 'node' attribute. This is only used for
# type aliases.
type_override = None # type: Optional[mypy.types.Type]
# For generic aliases this stores the (qualified) names of type variables.
# (For example see testGenericAliasWithTypeVarsFromDifferentModules.)
Expand All @@ -2258,7 +2292,9 @@ class SymbolTableNode:
# For deserialized MODULE_REF nodes, the referenced module name;
# for other nodes, optionally the name of the referenced object.
cross_ref = None # type: Optional[str]
# Was this node created by normalіze_type_alias?
# Used to distinguish between 'typing.List' and 'builtins.list'. This is
# True when the former has been normalized to the latter, and it allow us
# to reject 'list[str]' and similar.
normalized = False # type: bool
# Was this defined by assignment to self attribute?
implicit = False # type: bool
Expand Down