Skip to content

Commit

Permalink
Change invalid-type-annotation to bad-yield-annotation error.
Browse files Browse the repository at this point in the history
This new error is used for functions that have return type annotations that are not compatible with `yield`.

PiperOrigin-RevId: 395319073
  • Loading branch information
Solumin authored and rchen152 committed Sep 7, 2021
1 parent d0097c0 commit b0e5198
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 7 deletions.
21 changes: 20 additions & 1 deletion docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ See [Silencing Errors][silencing-errors] for a more detailed example.
* [bad-return-type](#bad-return-type)
* [bad-slots](#bad-slots)
* [bad-unpacking](#bad-unpacking)
* [bad-yield-annotation](#bad-yield-annotation)
* [base-class-error](#base-class-error)
* [container-type-mismatch](#container-type-mismatch)
* [duplicate-keyword-argument](#duplicate-keyword-argument)
Expand Down Expand Up @@ -64,7 +65,7 @@ See [Silencing Errors][silencing-errors] for a more detailed example.
* [wrong-arg-types](#wrong-arg-types)
* [wrong-keyword-args](#wrong-keyword-args)

<!-- Added by: rechen, at: 2021-08-10T21:18-07:00 -->
<!-- Added by: tsudol, at: 2021-09-01T15:22-07:00 -->

<!--te-->

Expand Down Expand Up @@ -231,6 +232,24 @@ A tuple was unpacked into the wrong number of variables. Example:
a, b = (1, 2, 3) # bad-unpacking
```

## bad-yield-annotation

A generator function (a function with a `yield`) was not annotated with an
appropriate return type.

<!-- bad -->
```python
def gen() -> int: # bad-yield-annotation
yield 1
```

<!-- good -->
```python
def gen() -> Iterator[int]
# Could also use Generator or Iterable.
yield 1
```

## base-class-error

The class definition uses an illegal value for a base class. Example:
Expand Down
8 changes: 4 additions & 4 deletions pytype/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3398,12 +3398,12 @@ def make(cls, name, code, f_locals, f_globals, defaults, kw_defaults, closure,
ret_type = annotations["return"]
if code.has_generator():
if not abstract_utils.matches_generator(ret_type):
error = "Expected Generator, Iterable or Iterator"
vm.errorlog.invalid_annotation(vm.frames, ret_type, error)
vm.errorlog.bad_yield_annotation(
vm.frames, name, ret_type, is_async=False)
elif code.has_async_generator():
if not abstract_utils.matches_async_generator(ret_type):
error = "Expected AsyncGenerator, AsyncIterable or AsyncIterator"
vm.errorlog.invalid_annotation(vm.frames, ret_type, error)
vm.errorlog.bad_yield_annotation(
vm.frames, name, ret_type, is_async=True)
overloads = vm.frame.overloads[name]
key = (name, code,
abstract_utils.hash_all_dicts(
Expand Down
11 changes: 11 additions & 0 deletions pytype/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,17 @@ def bad_return_type(self, stack, node, formal, actual, bad):
details.extend(protocol_details + nis_details)
self.error(stack, message, "".join(details))

@_error_name("bad-yield-annotation")
def bad_yield_annotation(self, stack, name, annot, is_async):
func = ("async " if is_async else "") + f"generator function {name}"
actual = self._print_as_expected_type(annot)
message = f"Bad return type {actual!r} for {func}"
if is_async:
details = "Expected AsyncGenerator, AsyncIterable or AsyncIterator"
else:
details = "Expected Generator, Iterable or Iterator"
self.error(stack, message, details)

@_error_name("bad-concrete-type")
def bad_concrete_type(self, stack, node, formal, actual, bad):
expected, actual, _, protocol_details, nis_details = (
Expand Down
2 changes: 1 addition & 1 deletion pytype/tests/test_async_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async def gen2() -> AsyncIterator[bool]:
async def gen3() -> AsyncIterable[bool]:
yield 1 # bad-return-type[e3]
async def gen4() -> int: # invalid-annotation[e4]
async def gen4() -> int: # bad-yield-annotation[e4]
yield 1
async def fun():
Expand Down
2 changes: 1 addition & 1 deletion pytype/tests/test_errors2.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def g2(x: dct): # invalid-annotation[e4]

def test_move_union_inward(self):
_, errors = self.InferWithErrors("""
def f() -> str: # invalid-annotation[e]
def f() -> str: # bad-yield-annotation[e]
y = "hello" if __random__ else 42
yield y
""")
Expand Down

0 comments on commit b0e5198

Please sign in to comment.