Skip to content

Commit ce5876d

Browse files
committed
fix(parser): validate inner expression of type assertions in assignment targets (#12614)
fixes #12612
1 parent 2117ca6 commit ce5876d

File tree

13 files changed

+105
-29
lines changed

13 files changed

+105
-29
lines changed

crates/oxc_linter/src/rules/typescript/no_confusing_non_null_assertion.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ fn test() {
155155
"a! != b;",
156156
"a! !== b;",
157157
];
158+
158159
let fail = vec![
159160
"a! == b;",
160161
"a! === b;",
@@ -163,8 +164,8 @@ fn test() {
163164
"(a==b)! ==c;",
164165
"a! = b;",
165166
"(obj = new new OuterObj().InnerObj).Name! = c;",
166-
"(a=b)! =c;",
167167
];
168+
168169
// let fix = vec![
169170
// // source, expected, rule_config?
170171
// // ("f = 1 + d! == 2", "f = (1 + d!) == 2", None), TODO: Add suggest or the weird ;() fix

crates/oxc_linter/src/snapshots/typescript_no_confusing_non_null_assertion.snap

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,3 @@ source: crates/oxc_linter/src/tester.rs
4949
· ─────────────────────────────────────────────
5050
╰────
5151
help: Remove the "!", or wrap the left-hand side in parentheses.
52-
53-
typescript-eslint(no-confusing-non-null-assertion): Confusing combinations of non-null assertion and assignment like "a! = b", which looks very similar to not equal "a != b".
54-
╭─[no_confusing_non_null_assertion.tsx:1:1]
55-
1 │ (a=b)! =c;
56-
· ─────────
57-
╰────
58-
help: Remove the "!", or wrap the left-hand side in parentheses.

crates/oxc_parser/src/js/grammar.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,44 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> {
4444
expr => SimpleAssignmentTarget::cover(expr, p),
4545
}
4646
}
47-
Expression::TSAsExpression(expr) => SimpleAssignmentTarget::TSAsExpression(expr),
47+
Expression::TSAsExpression(expr) => match expr.expression.get_inner_expression() {
48+
Expression::Identifier(_)
49+
| Expression::StaticMemberExpression(_)
50+
| Expression::ComputedMemberExpression(_)
51+
| Expression::PrivateFieldExpression(_) => {
52+
SimpleAssignmentTarget::TSAsExpression(expr)
53+
}
54+
_ => p.fatal_error(diagnostics::invalid_assignment(expr.span())),
55+
},
4856
Expression::TSSatisfiesExpression(expr) => {
49-
SimpleAssignmentTarget::TSSatisfiesExpression(expr)
50-
}
51-
Expression::TSNonNullExpression(expr) => {
52-
SimpleAssignmentTarget::TSNonNullExpression(expr)
57+
match expr.expression.get_inner_expression() {
58+
Expression::Identifier(_)
59+
| Expression::StaticMemberExpression(_)
60+
| Expression::ComputedMemberExpression(_)
61+
| Expression::PrivateFieldExpression(_) => {
62+
SimpleAssignmentTarget::TSSatisfiesExpression(expr)
63+
}
64+
_ => p.fatal_error(diagnostics::invalid_assignment(expr.span())),
65+
}
5366
}
54-
Expression::TSTypeAssertion(expr) => SimpleAssignmentTarget::TSTypeAssertion(expr),
67+
Expression::TSNonNullExpression(expr) => match expr.expression.get_inner_expression() {
68+
Expression::Identifier(_)
69+
| Expression::StaticMemberExpression(_)
70+
| Expression::ComputedMemberExpression(_)
71+
| Expression::PrivateFieldExpression(_) => {
72+
SimpleAssignmentTarget::TSNonNullExpression(expr)
73+
}
74+
_ => p.fatal_error(diagnostics::invalid_assignment(expr.span())),
75+
},
76+
Expression::TSTypeAssertion(expr) => match expr.expression.get_inner_expression() {
77+
Expression::Identifier(_)
78+
| Expression::StaticMemberExpression(_)
79+
| Expression::ComputedMemberExpression(_)
80+
| Expression::PrivateFieldExpression(_) => {
81+
SimpleAssignmentTarget::TSTypeAssertion(expr)
82+
}
83+
_ => p.fatal_error(diagnostics::invalid_assignment(expr.span())),
84+
},
5585
Expression::TSInstantiationExpression(expr) => {
5686
p.fatal_error(diagnostics::invalid_lhs_assignment(expr.span()))
5787
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(foo() as bar) = 123;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(<any>foo()) = 123;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(foo() satisfies any) = 123;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(foo() as number as any) = 123;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Type assertions with valid assignment targets should parse successfully
2+
// https://github.com/oxc-project/oxc/issues/12612
3+
4+
let a = 1;
5+
let obj = { foo: 1 };
6+
7+
// Simple type assertions with identifiers
8+
(a as any) = 42;
9+
(<any>a) = 42;
10+
(a satisfies number) = 42;
11+
12+
// Type assertions with member expressions
13+
(obj.foo as any) = 42;
14+
(<any>obj.foo) = 42;
15+
(obj.foo satisfies number) = 42;
16+
17+
// Nested type assertions should work when the inner expression is assignable
18+
(a as number as any) = 42;
19+
(a satisfies number as any) = 42;
20+
(<any>(a as number)) = 42;
21+
(<number>(<any>a)) = 42;
22+
23+
// Mixed type assertions
24+
(a! as any) = 42;
25+
((a as any)!) = 42;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
codegen_misc Summary:
2-
AST Parsed : 44/44 (100.00%)
3-
Positive Passed: 44/44 (100.00%)
2+
AST Parsed : 45/45 (100.00%)
3+
Positive Passed: 45/45 (100.00%)

tasks/coverage/snapshots/parser_babel.snap

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11788,12 +11788,11 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
1178811788
2 │ [...[] as T] = b;
1178911789
╰────
1179011790

11791-
× Invalid rest operator's argument.
11792-
╭─[babel/packages/babel-parser/test/fixtures/typescript/cast/destructuring-assignent-rest-invalid/input.ts:4:9]
11793-
3 │
11794-
4 │ 0, { ...({} as T)} = b;
11795-
· ─────────
11796-
5 │ [...([] as T)] = b;
11791+
× Cannot assign to this expression
11792+
╭─[babel/packages/babel-parser/test/fixtures/typescript/cast/destructuring-assignent-rest-invalid/input.ts:1:9]
11793+
1 │ 0, { ...{} as T} = b;
11794+
· ───────
11795+
2 │ [...[] as T] = b;
1179711796
╰────
1179811797

1179911798
× Expected `=>` but found `;`

0 commit comments

Comments
 (0)