Skip to content

🐛 Linter errors and suggests removing async when doing so would break a yield* call #8645

@lgarron

Description

@lgarron

Environment information

CLI:
  Version:                      2.3.9
  Color support:                true

Platform:
  CPU Architecture:             aarch64
  OS:                           macos

Environment:
  BIOME_LOG_PATH:               unset
  BIOME_LOG_PREFIX_NAME:        unset
  BIOME_CONFIG_PATH:            unset
  BIOME_THREADS:                unset
  NO_COLOR:                     unset
  TERM:                         xterm-256color
  JS_RUNTIME_VERSION:           v25.2.1
  JS_RUNTIME_NAME:              node
  NODE_PACKAGE_MANAGER:         bun/1.3.5

Biome Configuration:
  Status:                       Loaded successfully
  Path:                         biome.json
  Formatter enabled:            true
  Linter enabled:               true
  Assist enabled:               true
  VCS enabled:                  true
  HTML full support enabled:    unset

Workspace:
  Open Documents:               0

What happened?

Consider the following code:

async function* plus(iterable: AsyncIterable<number>, n: number) {
  for await (const v of iterable) {
    yield v + n;
  }
}

function* plusThreeEverythingAndThenPlusTwoEverything(
  iterable: AsyncIterable<number>,
) {
  yield* plus(iterable, 3);
  yield* plus(iterable, 2);
}

https://biomejs.dev/playground/?code=YQBzAHkAbgBjACAAZgB1AG4AYwB0AGkAbwBuACoAIABwAGwAdQBzACgAaQB0AGUAcgBhAGIAbABlADoAIABBAHMAeQBuAGMASQB0AGUAcgBhAGIAbABlADwAbgB1AG0AYgBlAHIAPgAsACAAbgA6ACAAbgB1AG0AYgBlAHIAKQAgAHsACgAgACAAZgBvAHIAIABhAHcAYQBpAHQAIAAoAGMAbwBuAHMAdAAgAHYAIABvAGYAIABpAHQAZQByAGEAYgBsAGUAKQAgAHsACgAgACAAIAAgAHkAaQBlAGwAZAAgAHYAIAArACAAbgA7AAoAIAAgAH0ACgB9AAoACgBmAHUAbgBjAHQAaQBvAG4AKgAgAHAAbAB1AHMAVABoAHIAZQBlAEUAdgBlAHIAeQB0AGgAaQBuAGcAQQBuAGQAVABoAGUAbgBQAGwAdQBzAFQAdwBvAEUAdgBlAHIAeQB0AGgAaQBuAGcAKAAKACAAIABpAHQAZQByAGEAYgBsAGUAOgAgAEEAcwB5AG4AYwBJAHQAZQByAGEAYgBsAGUAPABuAHUAbQBiAGUAcgA%2BACwACgApACAAewAKACAAIAB5AGkAZQBsAGQAKgAgAHAAbAB1AHMAKABpAHQAZQByAGEAYgBsAGUALAAgADMAKQA7AAoAIAAgAHkAaQBlAGwAZAAqACAAcABsAHUAcwAoAGkAdABlAHIAYQBiAGwAZQAsACAAMgApADsACgB9AAoA

EDIT: the code above is a bit silly because the second plus(…) call doesn't do anything — the iterator is already consumed. See below for an example that can't be trivially rewritten.

Biome errors and tells me that the async keyword is unnecessary:

Remove this async modifier, or add an await expression in the function. Async functions without await expressions may not need to be declared async.

However, removing the async would cause the code to break, because we are yielding to an async iterable.

Expected result

No error.

I'm not sure exactly what the best course of action here is. The simplest would be to count yield* similar to an await call in an async function — that's probably what I would do to eliminate false positives. But yield* … can also be used to yield to sync generators (even from inside async functions), so this would allow false negatives.1

However, the code is concise and idiomatic for combinators of iterables. It doesn't feel right to rewrite it or to add a permanent comment for Biome to ignore it.

Code of Conduct

  • I agree to follow Biome's Code of Conduct

Footnotes

  1. Conceptually, using yield* exclusively on known-sync generators in an async function feels similar to awaiting a non-thenable, but TypeScript tends to warn in that case. To report proper diagnostics, Biome would have to know the types of all the iterables that await* is used on.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LinterArea: linterL-JavaScriptLanguage: JavaScript and super languagesS-Bug-confirmedStatus: report has been confirmed as a valid bug

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions