From 3b4ec0857f240d1001fe691241e6463d26642cc6 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Tue, 8 Jun 2021 11:16:11 -0700 Subject: [PATCH] [mypyc] Produce unimplemented errors on unsupported async features And avoid triggering mypy assertion failures on errors. Fixes mypyc/mypyc#866. Opened mypyc/mypyc#868 to track the async feature work. --- mypyc/codegen/emitmodule.py | 4 ++++ mypyc/irbuild/context.py | 4 ++++ mypyc/irbuild/expression.py | 10 ++++++++++ mypyc/irbuild/function.py | 3 +++ mypyc/irbuild/statement.py | 6 ++++++ mypyc/test-data/commandline.test | 22 +++++++++++++++++++++- 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mypyc/codegen/emitmodule.py b/mypyc/codegen/emitmodule.py index ec89aa767ca1..a057f361e168 100644 --- a/mypyc/codegen/emitmodule.py +++ b/mypyc/codegen/emitmodule.py @@ -407,6 +407,10 @@ def compile_modules_to_c( group_map = {source.module: lib_name for group, lib_name in groups for source in group} mapper = Mapper(group_map) + # Sometimes when we call back into mypy, there might be errors. + # We don't want to crash when that happens. + result.manager.errors.set_file('', module=None, scope=None) + modules = compile_modules_to_ir(result, mapper, compiler_options, errors) ctext = compile_ir_to_c(groups, modules, result, mapper, compiler_options) diff --git a/mypyc/irbuild/context.py b/mypyc/irbuild/context.py index 77976da9235e..9424913591c4 100644 --- a/mypyc/irbuild/context.py +++ b/mypyc/irbuild/context.py @@ -57,6 +57,10 @@ def namespaced_name(self) -> str: def is_generator(self) -> bool: return self.fitem.is_generator or self.fitem.is_coroutine + @property + def is_coroutine(self) -> bool: + return self.fitem.is_coroutine + @property def callable_class(self) -> 'ImplicitClass': assert self._callable_class is not None diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index b49170bdf2c7..645b2eeb0e0d 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -659,14 +659,21 @@ def _visit_display(builder: IRBuilder, def transform_list_comprehension(builder: IRBuilder, o: ListComprehension) -> Value: + if any(o.generator.is_async): + builder.error('async comprehensions are unimplemented', o.line) return translate_list_comprehension(builder, o.generator) def transform_set_comprehension(builder: IRBuilder, o: SetComprehension) -> Value: + if any(o.generator.is_async): + builder.error('async comprehensions are unimplemented', o.line) return translate_set_comprehension(builder, o.generator) def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehension) -> Value: + if any(o.is_async): + builder.error('async comprehensions are unimplemented', o.line) + d = builder.call_c(dict_new_op, [], o.line) loop_params = list(zip(o.indices, o.sequences, o.condlists)) @@ -696,6 +703,9 @@ def get_arg(arg: Optional[Expression]) -> Value: def transform_generator_expr(builder: IRBuilder, o: GeneratorExpr) -> Value: + if any(o.is_async): + builder.error('async comprehensions are unimplemented', o.line) + builder.warning('Treating generator comprehension as list', o.line) return builder.call_c( iter_op, [translate_list_comprehension(builder, o)], o.line diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index 1b7319823b20..dcfc71c9cc28 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -135,6 +135,9 @@ def transform_lambda_expr(builder: IRBuilder, expr: LambdaExpr) -> Value: def transform_yield_expr(builder: IRBuilder, expr: YieldExpr) -> Value: + if builder.fn_info.is_coroutine: + builder.error('async generators are unimplemented', expr.line) + if expr.expr: retval = builder.accept(expr.expr) else: diff --git a/mypyc/irbuild/statement.py b/mypyc/irbuild/statement.py index d6e85c61007b..9b0a0c8750bb 100644 --- a/mypyc/irbuild/statement.py +++ b/mypyc/irbuild/statement.py @@ -242,6 +242,9 @@ def transform_while_stmt(builder: IRBuilder, s: WhileStmt) -> None: def transform_for_stmt(builder: IRBuilder, s: ForStmt) -> None: + if s.is_async: + builder.error('async for is unimplemented', s.line) + def body() -> None: builder.accept(s.body) @@ -610,6 +613,9 @@ def finally_body() -> None: def transform_with_stmt(builder: IRBuilder, o: WithStmt) -> None: + if o.is_async: + builder.error('async with is unimplemented', o.line) + # Generate separate logic for each expr in it, left to right def generate(i: int) -> None: if i >= len(o.expr): diff --git a/mypyc/test-data/commandline.test b/mypyc/test-data/commandline.test index 8ff21a37089d..6d2d1539aead 100644 --- a/mypyc/test-data/commandline.test +++ b/mypyc/test-data/commandline.test @@ -98,7 +98,7 @@ def f(x: int) -> int: # cmd: test.py [file test.py] -from typing import List, Any +from typing import List, Any, AsyncIterable from typing_extensions import Final from mypy_extensions import trait, mypyc_attr @@ -192,3 +192,23 @@ class AllowInterp1(Concrete1): # E: Base class "test.Concrete1" does not allow @mypyc_attr(allow_interpreted_subclasses=True) class AllowInterp2(PureTrait): # E: Base class "test.PureTrait" does not allow interpreted subclasses pass + +async def async_for(xs: AsyncIterable[int]) -> None: + async for x in xs: # E: async for is unimplemented + print(x) + + [x async for x in xs] # E: async comprehensions are unimplemented + (x async for x in xs) # E: async comprehensions are unimplemented # W: Treating generator comprehension as list + {x async for x in xs} # E: async comprehensions are unimplemented + {x: x async for x in xs} # E: async comprehensions are unimplemented + +class async_ctx: + async def __aenter__(self) -> int: pass + async def __aexit__(self, x, y, z) -> None: pass + +async def async_with() -> None: + async with async_ctx() as x: # E: async with is unimplemented + print(x) + +async def async_generators() -> AsyncIterable[int]: + yield 1 # E: async generators are unimplemented