Navigation Menu

Skip to content

Commit

Permalink
Fix mypyc crash with plugins using get_customize_class_mro_hook (#7075
Browse files Browse the repository at this point in the history
)

The semanal code that invoked it created an `Expression` directly,
which mypyc barfs on because it is a trait.

Fixes #6706.
  • Loading branch information
msullivan committed Jun 27, 2019
1 parent 43d2be1 commit 262fe3d
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 3 deletions.
5 changes: 3 additions & 2 deletions mypy/newsemanal/semanal.py
Expand Up @@ -74,7 +74,8 @@
PlaceholderNode, COVARIANT, CONTRAVARIANT, INVARIANT,
nongen_builtins, get_member_expr_fullname, REVEAL_TYPE,
REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_target_versions,
EnumCallExpr, RUNTIME_PROTOCOL_DECOS
EnumCallExpr, RUNTIME_PROTOCOL_DECOS,
FakeExpression,
)
from mypy.tvar_scope import TypeVarScope
from mypy.typevars import fill_typevars
Expand Down Expand Up @@ -1459,7 +1460,7 @@ def calculate_class_mro(self, defn: ClassDef,
if defn.fullname:
hook = self.plugin.get_customize_class_mro_hook(defn.fullname)
if hook:
hook(ClassDefContext(defn, Expression(), self))
hook(ClassDefContext(defn, FakeExpression(), self))

def update_metaclass(self, defn: ClassDef) -> None:
"""Lookup for special metaclass declarations, and update defn fields accordingly.
Expand Down
9 changes: 9 additions & 0 deletions mypy/nodes.py
Expand Up @@ -179,6 +179,15 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T:
raise RuntimeError('Not implemented')


class FakeExpression(Expression):
"""A dummy expression.
We need a dummy expression in one place, and can't instantiate Expression
because it is a trait and mypyc barfs.
"""
pass


# TODO:
# Lvalue = Union['NameExpr', 'MemberExpr', 'IndexExpr', 'SuperExpr', 'StarExpr'
# 'TupleExpr']; see #1783.
Expand Down
3 changes: 2 additions & 1 deletion mypy/semanal.py
Expand Up @@ -59,6 +59,7 @@
COVARIANT, CONTRAVARIANT, INVARIANT, UNBOUND_IMPORTED, nongen_builtins,
get_member_expr_fullname, REVEAL_TYPE, REVEAL_LOCALS, is_final_node,
RUNTIME_PROTOCOL_DECOS,
FakeExpression,
)
from mypy.tvar_scope import TypeVarScope
from mypy.typevars import fill_typevars
Expand Down Expand Up @@ -1260,7 +1261,7 @@ def calculate_class_mro(self, defn: ClassDef,
if defn.fullname:
hook = self.plugin.get_customize_class_mro_hook(defn.fullname)
if hook:
hook(ClassDefContext(defn, Expression(), self))
hook(ClassDefContext(defn, FakeExpression(), self))

def update_metaclass(self, defn: ClassDef) -> None:
"""Lookup for special metaclass declarations, and update defn fields accordingly.
Expand Down
7 changes: 7 additions & 0 deletions test-data/unit/check-custom-plugin.test
Expand Up @@ -597,3 +597,10 @@ plugins=<ROOT>/test-data/unit/plugins/callable_instance.py
[file mypy.ini]
[[mypy]
plugins=<ROOT>/test-data/unit/plugins/depshook.py

[case testCustomizeMroTrivial]
# flags: --config-file tmp/mypy.ini
class A: pass
[file mypy.ini]
[[mypy]
plugins=<ROOT>/test-data/unit/plugins/customize_mro.py
10 changes: 10 additions & 0 deletions test-data/unit/plugins/customize_mro.py
@@ -0,0 +1,10 @@
from mypy.plugin import Plugin

class DummyPlugin(Plugin):
def get_customize_class_mro_hook(self, fullname):
def analyze(classdef_ctx):
pass
return analyze

def plugin(version):
return DummyPlugin

0 comments on commit 262fe3d

Please sign in to comment.