Skip to content

Commit

Permalink
[mypyc] Produce unimplemented errors on unsupported async features
Browse files Browse the repository at this point in the history
And avoid triggering mypy assertion failures on errors.

Fixes #866.
Opened #868 to track the async feature work.
  • Loading branch information
msullivan committed Jun 8, 2021
1 parent 28718fa commit c901f31
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 1 deletion.
4 changes: 4 additions & 0 deletions mypyc/codegen/emitmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -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('<mypyc>', 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)

Expand Down
4 changes: 4 additions & 0 deletions mypyc/irbuild/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions mypyc/irbuild/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions mypyc/irbuild/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -143,6 +146,8 @@ def transform_yield_expr(builder: IRBuilder, expr: YieldExpr) -> Value:


def transform_yield_from_expr(builder: IRBuilder, o: YieldFromExpr) -> Value:
if builder.fn_info.is_coroutine:
builder.error('async generators are unimplemented', expr.line)
return handle_yield_from_and_await(builder, o)


Expand Down
6 changes: 6 additions & 0 deletions mypyc/irbuild/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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):
Expand Down
22 changes: 21 additions & 1 deletion mypyc/test-data/commandline.test
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

0 comments on commit c901f31

Please sign in to comment.