8000 Last strict optional fixes by ilevkivskyi · Pull Request #4070 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Last strict optional fixes #4070

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 22 commits into from
Oct 24, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
Deal with self.type
  • Loading branch information
ilevkivskyi committed Oct 7, 2017
commit 583c00e5093289de5cadaf3b7a123eab4d19688e
6 changes: 3 additions & 3 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1770,9 +1770,9 @@ def check_lvalue(self, lvalue: Lvalue) -> Tuple[Optional[Type],
self.store_type(lvalue, lvalue_type)
elif isinstance(lvalue, TupleExpr) or isinstance(lvalue, ListExpr):
types = [self.check_lvalue(sub_expr)[0] or
# This type will be used as a context for further inference of rvalue
# we put Any if there is no information available from lvalue.
AnyType(TypeOfAny.special_form) for sub_expr in lvalue.items]
# This type will be used as a context for further inference of rvalue,
# we put Uninhabited if there is no information available from lvalue.
UninhabitedType() for sub_expr in lvalue.items]
lvalue_type = TupleType(types, self.named_type('builtins.tuple'))
else:
lvalue_type = self.expr_checker.accept(lvalue)
Expand Down
18 changes: 12 additions & 6 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ class SemanticAnalyzer(NodeVisitor[None]):
# Names declated using "nonlocal" (separate set for each scope)
nonlocal_decls = None # type: List[Set[str]]
# Local names of function scopes; None for non-function scopes.
locals = None # type: List[SymbolTable]
locals = None # type: List[Optional[SymbolTable]]
# Nested block depths of scopes
block_depth = None # type: List[int]
# TypeInfo of directly enclosing class (or None)
type = None # type: Optional[TypeInfo]
# Stack of outer classes (the second tuple item contains tvars).
type_stack = None # type: List[TypeInfo]
type_stack = None # type: List[Optional[TypeInfo]]
# Type variables that are bound by the directly enclosing class
bound_tvars = None # type: List[SymbolTableNode]
# Type variables bound by the current scope, be it class or function
Expand Down Expand Up @@ -289,6 +289,7 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options,
for name in implicit_module_attrs:
v = self.globals[name].node
if isinstance(v, Var):
assert v.type is not None, "Type of implicit attribute not set"
v.type = self.anal_type(v.type)
v.is_ready = True

Expand Down Expand Up @@ -381,6 +382,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
# be a win.
if self.is_class_scope():
# Method definition
assert self.type is not None, "Type not set at class scope"
defn.info = self.type
if not defn.is_decorated and not defn.is_overload:
if (defn.name() in self.type.names and
Expand Down Expand Up @@ -433,6 +435,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
def prepare_method_signature(self, func: FuncDef) -> None:
"""Check basic signature validity and tweak annotation of self/cls argument."""
# Only non-static methods are special.
assert self.type is not None, "This method should be only called inside a class"
Copy link
Collaborator

Choose a reason for hiding this comment

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

You could remove this assert by adding a TypeInfo argument and passing it from the caller.

functype = func.type
if not func.is_static:
if not func.arguments:
Expand Down Expand Up @@ -546,7 +549,7 @@ def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
assert defn.impl is defn.items[-1]
defn.items = defn.items[:-1]
elif not self.is_stub_file and not non_overload_indexes:
if not (self.is_class_scope() and self.type.is_protocol):
if not (self.type and not self.is_func_scope() and self.type.is_protocol):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Random observation: Here it would be useful is is_class_scope() could return the binding self.type is not None when it returns true (there is a feature proposal about this, I think).

Copy link
Member Author
@ilevkivskyi ilevkivskyi Oct 20, 2017

Choose a reason for hiding this comment

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

Yes, I also noticed it would be very useful to somehow "remember" the bindings. For simple cases I was thinking about something like inlining methods (very approximately):

    @inline
    def meth(self) -> bool:
        return self.x is not None and self.y is not None
    if self.meth(): # use original expression returned by 'meth' here
        ...

self.fail(
"An overloaded function outside a stub file must have an implementation",
defn)
Expand All @@ -566,7 +569,7 @@ def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
# redfinitions already.
return

if self.is_class_scope():
if self.type and not self.is_func_scope():
self.type.names[defn.name()] = SymbolTableNode(MDEF, defn,
typ=defn.type)
defn.info = self.type
Expand Down Expand Up @@ -1778,9 +1781,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> None:
if not res:
return
node = self.lookup(lvalue.name, lvalue)
assert node is not None
if not lvalue.is_def:
# Only a definition can create a type alias, not regular assignment.
if node and node.kind == TYPE_ALIAS or isinstance(node.node, TypeInfo):
if node.kind == TYPE_ALIAS or isinstance(node.node, TypeInfo):
self.fail('Cannot assign multiple types to name "{}"'
' without an explicit "Type[...]" annotation'
8000 .format(lvalue.name), lvalue)
Expand Down Expand Up @@ -1916,6 +1920,7 @@ def analyze_tuple_or_list_lvalue(self, lval: Union[ListExpr, TupleExpr],
def analyze_member_lvalue(self, lval: MemberExpr) -> None:
lval.accept(self)
if self.is_self_member_ref(lval):
assert self.type, "Self member outside a class"
node = self.type.get(lval.name)
if node is None or isinstance(node.node, Var) and node.node.is_abstract_var:
if self.type.is_protocol and node is None:
Expand Down Expand Up @@ -2133,6 +2138,7 @@ def process_typevar_declaration(self, s: AssignmentStmt) -> None:
context=s)
# Yes, it's a valid type variable definition! Add it to the symbol table.
node = self.lookup(name, s)
assert node is not None
node.kind = TVAR
TypeVar = TypeVarExpr(name, node.fullname, values, upper_bound, variance)
TypeVar.line = call.line
Expand Down Expand Up @@ -3549,7 +3555,7 @@ def lookup(self, name: str, ctx: Context,
self.name_not_defined(name, ctx)
return None
# 2. Class attributes (if within class definition)
if self.is_class_scope() and name in self.type.names:
if self.type and not self.is_func_scope() and name in self.type.names:
node = self.type.names[name]
if not node.implicit:
return node
Expand Down
3 changes: 0 additions & 3 deletions mypy_self_check.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ disallow_any = generics, unimported
warn_redundant_casts = True
warn_unused_ignores = True

# historical exception
[mypy-mypy.semanal]
strict_optional = False
You are viewing a condensed version of this merge commit. You can view the full changes here.
0