mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-14 22:29:17 +00:00
fix(parser): remove type-dependent tuple rest diagnostics (#27234)
TS1265 and TS1266 depend on the resolved types of tuple rest elements. The parser cannot reliably distinguish concrete arrays from tuple aliases or variadic type parameters. Its spelling-based `Array` check rejects valid code such as: ```ts // Array shadows the built-in name and is a variadic type parameter. // Both are valid, but the parser incorrectly reported TS1265 / TS1266. type X<Array extends unknown[]> = [...Array, ...Array]; type Y<Array extends unknown[]> = [...Array, number?]; ``` ```ts type Pair = [string, number]; type Items = string[]; // Valid: spreading Pair contributes two fixed elements, then an optional one. type Fixed = [...Pair, boolean?]; // Invalid: Items is an unbounded array rest, but the parser cannot resolve it. type OptionalAfterArray = [...Items, boolean?]; // TS1266 // Invalid: two unbounded array rests; also requires resolving the alias. type TwoArrays = [...Items, ...Items]; // TS1265 ``` ```ts // Invalid: the unconstrained type parameter might not be an array. // TypeScript reports TS2574, but the parser incorrectly reported TS1265. type Unconstrained<Array> = [...Array, ...Array]; // Invalid: the built-in Array requires a type argument. // TypeScript reports TS2314, but the parser incorrectly reported TS1265. type MissingArguments = [...Array, ...Array]; ``` Remove both diagnostics and their parser checks rather than retaining partial syntax-based reporting. Resolving aliases, checking generic constraints, and validating rest types belong in a type checker, which can also select the correct diagnostic for invalid rests or missing type arguments.
This commit is contained in:
1 parent
7c61ebe1be
commit
d0b9372b8b
6 files changed
+3
-154
No files matched your search
@@ -428,20 +428,6 @@ parser_diagnostics! {
|
||||
])
|
||||
};
|
||||
|
||||
// A rest element cannot follow another rest element. ts(1265)
|
||||
rest_element_cannot_follow_another_rest_element(seen_span: Span, span: Span) => {
|
||||
ts_error("1265", "A rest element cannot follow another rest element.")
|
||||
.with_labels([span.label("Second rest element here"), seen_span.label("First seen here")])
|
||||
};
|
||||
|
||||
// An optional element cannot follow a rest element. ts(1266)
|
||||
optional_element_cannot_follow_rest_element(span: Span, rest_span: Span) => {
|
||||
ts_error("1266", "An optional element cannot follow a rest element.").with_labels([
|
||||
span.label("Optional element here"),
|
||||
rest_span.label("Rest element seen here"),
|
||||
])
|
||||
};
|
||||
|
||||
// A type-only import can specify a default import or named bindings, but not both. ts(1363)
|
||||
type_only_import_default_and_named(specifier_span: Span) => {
|
||||
ts_error(
|
||||
|
||||
@@ -969,39 +969,10 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let opening_span = self.cur_token().span();
|
||||
self.expect(Kind::LBrack);
|
||||
|
||||
let mut seen_rest_span: Option<Span> = None;
|
||||
let mut seen_optional_span: Option<Span> = None;
|
||||
let (elements, _) =
|
||||
self.parse_delimited_list(Kind::RBrack, Kind::Comma, opening_span, |me| {
|
||||
let tuple = me.parse_tuple_element();
|
||||
// check for array type, because unknown types can be destructed, example of valid code:
|
||||
// type C<T extends unknown[]> = [...string[], ...T];
|
||||
// example of invalid code:
|
||||
// type C<T extends unknown[]> = [...string[], ...T[]];
|
||||
if let TSTupleElement::TSRestType(rest) = &tuple
|
||||
&& let Some(rest_type) = (match &rest.type_annotation {
|
||||
TSType::TSNamedTupleMember(named) => named.element_type.as_ts_type(),
|
||||
ty => Some(ty),
|
||||
})
|
||||
&& match rest_type {
|
||||
TSType::TSArrayType(_) => true,
|
||||
// Check for `Array<...>` type
|
||||
TSType::TSTypeReference(ts_ref) => match &ts_ref.type_name {
|
||||
TSTypeName::IdentifierReference(id_ref) => id_ref.name == "Array",
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
if let Some(seen_span) = seen_rest_span {
|
||||
me.error(diagnostics::rest_element_cannot_follow_another_rest_element(
|
||||
seen_span,
|
||||
tuple.span(),
|
||||
));
|
||||
}
|
||||
seen_rest_span = Some(tuple.span());
|
||||
}
|
||||
|
||||
if !match &tuple {
|
||||
TSTupleElement::TSOptionalType(_) | TSTupleElement::TSRestType(_) => true,
|
||||
TSTupleElement::TSNamedTupleMember(named) => named.optional,
|
||||
@@ -1019,12 +990,6 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
TSTupleElement::TSNamedTupleMember(named) => named.optional,
|
||||
_ => false,
|
||||
} {
|
||||
if let Some(seen_rest_span) = seen_rest_span {
|
||||
me.error(diagnostics::optional_element_cannot_follow_rest_element(
|
||||
tuple.span(),
|
||||
seen_rest_span,
|
||||
));
|
||||
}
|
||||
seen_optional_span = Some(tuple.span());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
type OptionalAfterRest = [...a: string[], b?: number];
|
||||
type RestAfterRest = [...a: string[], ...b: number[]];
|
||||
type NamedRestAfterUnnamedRest = [...string[], ...b: number[]];
|
||||
type UnnamedRestAfterNamedRest = [...a: string[], ...number[]];
|
||||
@@ -1,3 +1,3 @@
|
||||
lexer_misc Summary:
|
||||
AST Parsed : 354/354 (100.00%)
|
||||
Positive Passed: 354/354 (100.00%)
|
||||
AST Parsed : 353/353 (100.00%)
|
||||
Positive Passed: 353/353 (100.00%)
|
||||
@@ -1,7 +1,7 @@
|
||||
parser_misc Summary:
|
||||
AST Parsed : 112/112 (100.00%)
|
||||
Positive Passed: 112/112 (100.00%)
|
||||
Negative Passed: 244/244 (100.00%)
|
||||
Negative Passed: 243/243 (100.00%)
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-abstract-method.ts:1:29]
|
||||
@@ -5142,44 +5142,6 @@ Negative Passed: 244/244 (100.00%)
|
||||
╰────
|
||||
help: Try inserting a semicolon here
|
||||
|
||||
× TS(1266): An optional element cannot follow a rest element.
|
||||
╭─[misc/fail/tuple-named-rest.ts:1:27]
|
||||
1 │ type OptionalAfterRest = [...a: string[], b?: number];
|
||||
· ───────┬────── ─────┬────
|
||||
· │ ╰── Optional element here
|
||||
· ╰── Rest element seen here
|
||||
2 │ type RestAfterRest = [...a: string[], ...b: number[]];
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[misc/fail/tuple-named-rest.ts:2:23]
|
||||
1 │ type OptionalAfterRest = [...a: string[], b?: number];
|
||||
2 │ type RestAfterRest = [...a: string[], ...b: number[]];
|
||||
· ───────┬────── ───────┬──────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
3 │ type NamedRestAfterUnnamedRest = [...string[], ...b: number[]];
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[misc/fail/tuple-named-rest.ts:3:35]
|
||||
2 │ type RestAfterRest = [...a: string[], ...b: number[]];
|
||||
3 │ type NamedRestAfterUnnamedRest = [...string[], ...b: number[]];
|
||||
· ─────┬───── ───────┬──────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
4 │ type UnnamedRestAfterNamedRest = [...a: string[], ...number[]];
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[misc/fail/tuple-named-rest.ts:4:35]
|
||||
3 │ type NamedRestAfterUnnamedRest = [...string[], ...b: number[]];
|
||||
4 │ type UnnamedRestAfterNamedRest = [...a: string[], ...number[]];
|
||||
· ───────┬────── ─────┬─────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
╰────
|
||||
|
||||
× TS(8011): Type arguments can only be used in TypeScript files.
|
||||
╭─[misc/fail/type-arguments-in-js.js:1:18]
|
||||
1 │ class A extends B<C> {}
|
||||
|
||||
@@ -32064,26 +32064,6 @@ Expect to Parse: tasks/coverage/typescript/tsc/testdata/tests/cases/conformance/
|
||||
4 │ type T03 = [...string[]];
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:7:21]
|
||||
6 │
|
||||
7 │ type V10 = [number, ...string[], ...boolean[]]; // Error
|
||||
· ─────┬───── ──────┬─────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
8 │ type V11 = [number, ...string[], boolean?]; // Error
|
||||
╰────
|
||||
|
||||
× TS(1266): An optional element cannot follow a rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:8:21]
|
||||
7 │ type V10 = [number, ...string[], ...boolean[]]; // Error
|
||||
8 │ type V11 = [number, ...string[], boolean?]; // Error
|
||||
· ─────┬───── ────┬───
|
||||
· │ ╰── Optional element here
|
||||
· ╰── Rest element seen here
|
||||
9 │ type V12 = [number, string?, boolean]; // Error
|
||||
╰────
|
||||
|
||||
× TS(1257): A required element cannot follow an optional element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:9:21]
|
||||
8 │ type V11 = [number, ...string[], boolean?]; // Error
|
||||
@@ -32094,46 +32074,6 @@ Expect to Parse: tasks/coverage/typescript/tsc/testdata/tests/cases/conformance/
|
||||
10 │
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:11:13]
|
||||
10 │
|
||||
11 │ type V15 = [...string[], ...number[]]; // Error
|
||||
· ─────┬───── ─────┬─────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
12 │ type V16 = [...string[], ...Array<number>]; // Error
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:12:13]
|
||||
11 │ type V15 = [...string[], ...number[]]; // Error
|
||||
12 │ type V16 = [...string[], ...Array<number>]; // Error
|
||||
· ─────┬───── ────────┬───────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
13 │ type V17 = [...Array<string>, ...number[]]; // Error
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:13:13]
|
||||
12 │ type V16 = [...string[], ...Array<number>]; // Error
|
||||
13 │ type V17 = [...Array<string>, ...number[]]; // Error
|
||||
· ────────┬─────── ─────┬─────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
14 │ type V18 = [...Array<string>, ...Array<number>]; // Error
|
||||
╰────
|
||||
|
||||
× TS(1265): A rest element cannot follow another rest element.
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/tuple/variadicTuples2.ts:14:13]
|
||||
13 │ type V17 = [...Array<string>, ...number[]]; // Error
|
||||
14 │ type V18 = [...Array<string>, ...Array<number>]; // Error
|
||||
· ────────┬─────── ────────┬───────
|
||||
· │ ╰── Second rest element here
|
||||
· ╰── First seen here
|
||||
15 │
|
||||
╰────
|
||||
|
||||
× TS(2457): Type alias name cannot be 'any'
|
||||
╭─[typescript/tsc/testdata/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts:2:6]
|
||||
1 │ interface I {}
|
||||
|
||||
Reference in new issue
Block a user