From 262fe3dc4d5d14492c6fd4009d91c555c406ac04 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Wed, 26 Jun 2019 18:20:46 -0700 Subject: [PATCH] Fix mypyc crash with plugins using `get_customize_class_mro_hook` (#7075) The semanal code that invoked it created an `Expression` directly, which mypyc barfs on because it is a trait. Fixes #6706. --- mypy/newsemanal/semanal.py | 5 +++-- mypy/nodes.py | 9 +++++++++ mypy/semanal.py | 3 ++- test-data/unit/check-custom-plugin.test | 7 +++++++ test-data/unit/plugins/customize_mro.py | 10 ++++++++++ 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 test-data/unit/plugins/customize_mro.py diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py index 789d6df0f1fd..b5d391fd51a0 100644 --- a/mypy/newsemanal/semanal.py +++ b/mypy/newsemanal/semanal.py @@ -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 @@ -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. diff --git a/mypy/nodes.py b/mypy/nodes.py index 46928002ece1..de889c03113c 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -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. diff --git a/mypy/semanal.py b/mypy/semanal.py index dd8b84cddbb6..45ba9ca9d9ac 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -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 @@ -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. diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index 2b31c90a7110..158ec91f0b13 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -597,3 +597,10 @@ plugins=/test-data/unit/plugins/callable_instance.py [file mypy.ini] [[mypy] plugins=/test-data/unit/plugins/depshook.py + +[case testCustomizeMroTrivial] +# flags: --config-file tmp/mypy.ini +class A: pass +[file mypy.ini] +[[mypy] +plugins=/test-data/unit/plugins/customize_mro.py diff --git a/test-data/unit/plugins/customize_mro.py b/test-data/unit/plugins/customize_mro.py new file mode 100644 index 000000000000..0f2396d98965 --- /dev/null +++ b/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