Skip to content

Commit da09e08

Browse files
committed
[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.
1 parent 28718fa commit da09e08

File tree

6 files changed

+50
-1
lines changed

6 files changed

+50
-1
lines changed

mypyc/codegen/emitmodule.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ def compile_modules_to_c(
407407
group_map = {source.module: lib_name for group, lib_name in groups for source in group}
408408
mapper = Mapper(group_map)
409409

410+
# Sometimes when we call back into mypy, there might be errors.
411+
# We don't want to crash when that happens.
412+
result.manager.errors.set_file('<mypyc>', module=None, scope=None)
413+
410414
modules = compile_modules_to_ir(result, mapper, compiler_options, errors)
411415
ctext = compile_ir_to_c(groups, modules, result, mapper, compiler_options)
412416

mypyc/irbuild/context.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def namespaced_name(self) -> str:
5757
def is_generator(self) -> bool:
5858
return self.fitem.is_generator or self.fitem.is_coroutine
5959

60+
@property
61+
def is_coroutine(self) -> bool:
62+
return self.fitem.is_coroutine
63+
6064
@property
6165
def callable_class(self) -> 'ImplicitClass':
6266
assert self._callable_class is not None

mypyc/irbuild/expression.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,14 +659,21 @@ def _visit_display(builder: IRBuilder,
659659

660660

661661
def transform_list_comprehension(builder: IRBuilder, o: ListComprehension) -> Value:
662+
if any(o.generator.is_async):
663+
builder.error('async comprehensions are unimplemented', o.line)
662664
return translate_list_comprehension(builder, o.generator)
663665

664666

665667
def transform_set_comprehension(builder: IRBuilder, o: SetComprehension) -> Value:
668+
if any(o.generator.is_async):
669+
builder.error('async comprehensions are unimplemented', o.line)
666670
return translate_set_comprehension(builder, o.generator)
667671

668672

669673
def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehension) -> Value:
674+
if any(o.is_async):
675+
builder.error('async comprehensions are unimplemented', o.line)
676+
670677
d = builder.call_c(dict_new_op, [], o.line)
671678
loop_params = list(zip(o.indices, o.sequences, o.condlists))
672679

@@ -696,6 +703,9 @@ def get_arg(arg: Optional[Expression]) -> Value:
696703

697704

698705
def transform_generator_expr(builder: IRBuilder, o: GeneratorExpr) -> Value:
706+
if any(o.is_async):
707+
builder.error('async comprehensions are unimplemented', o.line)
708+
699709
builder.warning('Treating generator comprehension as list', o.line)
700710
return builder.call_c(
701711
iter_op, [translate_list_comprehension(builder, o)], o.line

mypyc/irbuild/function.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ def transform_lambda_expr(builder: IRBuilder, expr: LambdaExpr) -> Value:
135135

136136

137137
def transform_yield_expr(builder: IRBuilder, expr: YieldExpr) -> Value:
138+
if builder.fn_info.is_coroutine:
139+
builder.error('async generators are unimplemented', expr.line)
140+
138141
if expr.expr:
139142
retval = builder.accept(expr.expr)
140143
else:
@@ -143,6 +146,8 @@ def transform_yield_expr(builder: IRBuilder, expr: YieldExpr) -> Value:
143146

144147

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

148153

mypyc/irbuild/statement.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ def transform_while_stmt(builder: IRBuilder, s: WhileStmt) -> None:
242242

243243

244244
def transform_for_stmt(builder: IRBuilder, s: ForStmt) -> None:
245+
if s.is_async:
246+
builder.error('async for is unimplemented', s.line)
247+
245248
def body() -> None:
246249
builder.accept(s.body)
247250

@@ -610,6 +613,9 @@ def finally_body() -> None:
610613

611614

612615
def transform_with_stmt(builder: IRBuilder, o: WithStmt) -> None:
616+
if o.is_async:
617+
builder.error('async with is unimplemented', o.line)
618+
613619
# Generate separate logic for each expr in it, left to right
614620
def generate(i: int) -> None:
615621
if i >= len(o.expr):

mypyc/test-data/commandline.test

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def f(x: int) -> int:
9898
# cmd: test.py
9999

100100
[file test.py]
101-
from typing import List, Any
101+
from typing import List, Any, AsyncIterable
102102
from typing_extensions import Final
103103
from mypy_extensions import trait, mypyc_attr
104104

@@ -192,3 +192,23 @@ class AllowInterp1(Concrete1): # E: Base class "test.Concrete1" does not allow
192192
@mypyc_attr(allow_interpreted_subclasses=True)
193193
class AllowInterp2(PureTrait): # E: Base class "test.PureTrait" does not allow interpreted subclasses
194194
pass
195+
196+
async def async_for(xs: AsyncIterable[int]) -> None:
197+
async for x in xs: # E: async for is unimplemented
198+
print(x)
199+
200+
[x async for x in xs] # E: async comprehensions are unimplemented
201+
(x async for x in xs) # E: async comprehensions are unimplemented # W: Treating generator comprehension as list
202+
{x async for x in xs} # E: async comprehensions are unimplemented
203+
{x: x async for x in xs} # E: async comprehensions are unimplemented
204+
205+
class async_ctx:
206+
async def __aenter__(self) -> int: pass
207+
async def __aexit__(self, x, y, z) -> None: pass
208+
209+
async def async_with() -> None:
210+
async with async_ctx() as x: # E: async with is unimplemented
211+
print(x)
212+
213+
async def async_generators() -> AsyncIterable[int]:
214+
yield 1 # E: async generators are unimplemented

0 commit comments

Comments
 (0)