mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(parser): span ambient generator diagnostics (#24711)
## Summary
Make TS1221 underline the generator declaration consistently from the `*` token.
## Why
The previous diagnostic used the generic function span, but that span has different start points depending on how the function is parsed:
- A class method enters function parsing after its name, so `declare class C { *generator(): any; }` highlighted only `(): any;` (starting at column 15), omitting both the generator marker and its name.
- A function declaration starts its span at the `function` keyword, so `declare namespace M { function *generator(): any; }` highlighted the whole declaration (starting at column 5), including text that is not the invalid generator construct.
For example, the prior output treated these equivalent generator markers differently:
```ts
declare class C {
*generator(): any;
// ^^^^^^^^
}
declare namespace M {
function *generator(): any;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
```
The parser now carries the `*` token location as `Option<u32>` while parsing a function. TS1221 uses that location through the declaration end, so both cases consistently highlight the relevant generator declaration:
```ts
*generator(): any;
^^^^^^^^^^^^^^^^^^
```
The AST continues to store `generator` as a boolean; the location exists only while parsing diagnostics.
This commit is contained in:
1 parent
e750a8243a
commit
48b59f450d
6 files changed
+47
-43
No files matched your search
@@ -471,7 +471,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let (name, computed) = self.parse_class_element_name(modifiers);
|
||||
let value = self.parse_method(
|
||||
modifiers.contains(ModifierKind::Async),
|
||||
false,
|
||||
None,
|
||||
FunctionKind::ClassMethod,
|
||||
);
|
||||
let method_definition = MethodDefinition::boxed(
|
||||
@@ -512,7 +512,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
|
||||
let value = self.parse_method(
|
||||
modifiers.contains(ModifierKind::Async),
|
||||
false,
|
||||
None,
|
||||
FunctionKind::Constructor,
|
||||
);
|
||||
let method_definition = MethodDefinition::boxed(
|
||||
@@ -555,7 +555,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
modifiers: &Modifiers,
|
||||
decorators: ArenaVec<'a, Decorator<'a>>,
|
||||
) -> ClassElement<'a> {
|
||||
let generator = self.eat(Kind::Star);
|
||||
let generator = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let (name, computed) = self.parse_class_element_name(modifiers);
|
||||
|
||||
let cur_token = self.cur_token();
|
||||
@@ -567,7 +567,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
|
||||
let optional = optional_span.is_some();
|
||||
|
||||
if generator || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
|
||||
if generator.is_some() || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
|
||||
self.verify_modifiers(
|
||||
modifiers,
|
||||
ModifierKinds::all_except([ModifierKind::Declare, ModifierKind::Readonly]),
|
||||
@@ -636,7 +636,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
&mut self,
|
||||
span: u32,
|
||||
r#type: MethodDefinitionType,
|
||||
generator: bool,
|
||||
generator: Option<u32>,
|
||||
name: PropertyKey<'a>,
|
||||
computed: bool,
|
||||
optional: bool,
|
||||
|
||||
@@ -257,7 +257,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
span: u32,
|
||||
id: Option<BindingIdentifier<'a>>,
|
||||
r#async: bool,
|
||||
generator: bool,
|
||||
generator: Option<u32>,
|
||||
func_kind: FunctionKind,
|
||||
param_kind: FormalParameterKind,
|
||||
modifiers: &Modifiers,
|
||||
@@ -265,8 +265,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let ctx = self.ctx;
|
||||
// `new.target` is allowed in a function's parameters and body (but not arrow
|
||||
// functions, which are parsed via `parse_function_body` directly).
|
||||
self.ctx =
|
||||
self.ctx.and_in(true).and_await(r#async).and_yield(generator).and_new_target(true);
|
||||
self.ctx = self
|
||||
.ctx
|
||||
.and_in(true)
|
||||
.and_await(r#async)
|
||||
.and_yield(generator.is_some())
|
||||
.and_new_target(true);
|
||||
let type_parameters = self.parse_ts_type_parameters();
|
||||
let (this_param, params) = self.parse_formal_parameters(func_kind, param_kind);
|
||||
let return_type = if self.is_ts { self.parse_ts_return_type_annotation() } else { None };
|
||||
@@ -328,9 +332,9 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
self.error(diagnostics::implementation_in_ambient(Span::empty(body.span.start)));
|
||||
}
|
||||
|
||||
if generator {
|
||||
if let Some(generator) = generator {
|
||||
if ctx.has_ambient() {
|
||||
self.error(diagnostics::generator_in_ambient_context(self.end_span(span)));
|
||||
self.error(diagnostics::generator_in_ambient_context(self.end_span(generator)));
|
||||
} else if body.is_none() {
|
||||
self.error(diagnostics::overload_signature_generator(self.end_span(span)));
|
||||
}
|
||||
@@ -346,7 +350,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
self.end_span(span),
|
||||
function_type,
|
||||
id,
|
||||
generator,
|
||||
generator.is_some(),
|
||||
r#async,
|
||||
modifiers.contains_declare(),
|
||||
type_parameters,
|
||||
@@ -392,8 +396,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
func_kind: FunctionKind,
|
||||
) -> ArenaBox<'a, Function<'a>> {
|
||||
self.expect(Kind::Function);
|
||||
let generator = self.eat(Kind::Star);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator);
|
||||
let generator = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator.is_some());
|
||||
self.parse_function(
|
||||
span,
|
||||
id,
|
||||
@@ -415,8 +419,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
) -> ArenaBox<'a, Function<'a>> {
|
||||
let r#async = modifiers.contains(ModifierKind::Async);
|
||||
self.expect(Kind::Function);
|
||||
let generator = self.eat(Kind::Star);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator);
|
||||
let generator = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator.is_some());
|
||||
self.parse_function(
|
||||
start_span,
|
||||
id,
|
||||
@@ -433,8 +437,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let func_kind = FunctionKind::Expression;
|
||||
self.expect(Kind::Function);
|
||||
|
||||
let generator = self.eat(Kind::Star);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator);
|
||||
let generator = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator.is_some());
|
||||
let function = self.parse_function(
|
||||
span,
|
||||
id,
|
||||
@@ -458,7 +462,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
pub(crate) fn parse_method(
|
||||
&mut self,
|
||||
r#async: bool,
|
||||
generator: bool,
|
||||
generator: Option<u32>,
|
||||
func_kind: FunctionKind,
|
||||
) -> ArenaBox<'a, Function<'a>> {
|
||||
let span = self.start_span();
|
||||
|
||||
@@ -59,12 +59,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
return self.parse_method_getter_setter(span, PropertyKind::Set, &modifiers);
|
||||
}
|
||||
|
||||
let asterisk_token = self.eat(Kind::Star);
|
||||
let asterisk_token = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let token_is_identifier =
|
||||
self.cur_kind().is_identifier_reference(self.ctx.has_yield(), self.ctx.has_await());
|
||||
let (key, computed) = self.parse_property_name();
|
||||
|
||||
if asterisk_token || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
|
||||
if asterisk_token.is_some() || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
|
||||
self.verify_modifiers(
|
||||
&modifiers,
|
||||
ModifierKinds::new([ModifierKind::Async]),
|
||||
@@ -216,7 +216,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
modifiers: &Modifiers,
|
||||
) -> ArenaBox<'a, ObjectProperty<'a>> {
|
||||
let (key, computed) = self.parse_property_name();
|
||||
let function = self.parse_method(false, false, FunctionKind::ObjectMethod);
|
||||
let function = self.parse_method(false, None, FunctionKind::ObjectMethod);
|
||||
match kind {
|
||||
PropertyKind::Get => self.check_getter(&function),
|
||||
PropertyKind::Set => self.check_setter(&function),
|
||||
|
||||
@@ -691,9 +691,9 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
) -> ArenaBox<'a, Function<'a>> {
|
||||
let r#async = modifiers.contains(ModifierKind::Async);
|
||||
self.expect(Kind::Function);
|
||||
let generator = self.eat(Kind::Star);
|
||||
let generator = self.eat(Kind::Star).then_some(self.prev_token_end - 1);
|
||||
let func_kind = FunctionKind::TSDeclaration;
|
||||
let id = self.parse_function_id(func_kind, r#async, generator);
|
||||
let id = self.parse_function_id(func_kind, r#async, generator.is_some());
|
||||
self.parse_function(
|
||||
start_span,
|
||||
id,
|
||||
|
||||
@@ -12820,10 +12820,10 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/input.ts:7:13]
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/input.ts:7:11]
|
||||
6 │ readonly *e() {}
|
||||
7 │ declare *f() {}
|
||||
· ─────
|
||||
· ───────
|
||||
8 │ protected *g() {}
|
||||
╰────
|
||||
|
||||
@@ -13189,10 +13189,10 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/optional-generator-method-with-invalid-modifiers/input.ts:4:14]
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/optional-generator-method-with-invalid-modifiers/input.ts:4:11]
|
||||
3 │ readonly *e?() { }
|
||||
4 │ declare *f?() { }
|
||||
· ──────
|
||||
· ─────────
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
@@ -13231,10 +13231,10 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/optional-generator-method-with-invalid-modifiers/input.ts:10:19]
|
||||
╭─[babel/packages/babel-parser/test/fixtures/typescript/class/optional-generator-method-with-invalid-modifiers/input.ts:10:11]
|
||||
9 │ readonly *[e?.e]?() { }
|
||||
10 │ declare *[f?.f]?() { }
|
||||
· ──────
|
||||
· ──────────────
|
||||
11 │ }
|
||||
╰────
|
||||
|
||||
|
||||
@@ -20225,34 +20225,34 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext1.ts:2:15]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext1.ts:2:5]
|
||||
1 │ declare class C {
|
||||
2 │ *generator(): any;
|
||||
· ────────
|
||||
· ──────────────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext2.ts:2:5]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext2.ts:2:14]
|
||||
1 │ declare namespace M {
|
||||
2 │ function *generator(): any;
|
||||
· ───────────────────────────
|
||||
· ──────────────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext3.d.ts:2:15]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext3.d.ts:2:5]
|
||||
1 │ declare class C {
|
||||
2 │ *generator(): any;
|
||||
· ────────
|
||||
· ──────────────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext4.d.ts:2:5]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorInAmbientContext4.d.ts:2:14]
|
||||
1 │ declare namespace M {
|
||||
2 │ function *generator(): any;
|
||||
· ───────────────────────────
|
||||
· ──────────────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
@@ -20273,26 +20273,26 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:2:5]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:2:13]
|
||||
1 │ declare namespace M {
|
||||
2 │ function* f(s: string): Iterable<any>;
|
||||
· ──────────────────────────────────────
|
||||
· ──────────────────────────────
|
||||
3 │ function* f(s: number): Iterable<any>;
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:3:5]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:3:13]
|
||||
2 │ function* f(s: string): Iterable<any>;
|
||||
3 │ function* f(s: number): Iterable<any>;
|
||||
· ──────────────────────────────────────
|
||||
· ──────────────────────────────
|
||||
4 │ function* f(s: any): Iterable<any>;
|
||||
╰────
|
||||
|
||||
× TS(1221): Generators are not allowed in an ambient context.
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:4:5]
|
||||
╭─[typescript/tests/cases/conformance/es6/yieldExpressions/generatorOverloads2.ts:4:13]
|
||||
3 │ function* f(s: number): Iterable<any>;
|
||||
4 │ function* f(s: any): Iterable<any>;
|
||||
· ───────────────────────────────────
|
||||
· ───────────────────────────
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
|
||||
Reference in new issue
Block a user