Skip to content

Commit

Permalink
Add check for delete expression must be optional (#37921)
Browse files Browse the repository at this point in the history
* Add check for delete expression must be optional

* Add more tests
  • Loading branch information
Kingwl committed Apr 22, 2020
1 parent 052d3f9 commit 39beb1d
Show file tree
Hide file tree
Showing 14 changed files with 856 additions and 4 deletions.
15 changes: 13 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27583,12 +27583,23 @@ namespace ts {
}
const links = getNodeLinks(expr);
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
if (symbol && isReadonlySymbol(symbol)) {
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
if (symbol) {
if (isReadonlySymbol(symbol)) {
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
}

checkDeleteExpressionMustBeOptional(expr, getTypeOfSymbol(symbol));
}
return booleanType;
}

function checkDeleteExpressionMustBeOptional(expr: AccessExpression, type: Type) {
const AnyOrUnknownOrNeverFlags = TypeFlags.AnyOrUnknown | TypeFlags.Never;
if (strictNullChecks && !(type.flags & AnyOrUnknownOrNeverFlags) && !(getFalsyFlags(type) & TypeFlags.Undefined)) {
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional);
}
}

function checkTypeOfExpression(node: TypeOfExpression): Type {
checkExpression(node.expression);
return typeofType;
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2963,6 +2963,10 @@
"category": "Error",
"code": 2789
},
"The operand of a 'delete' operator must be optional.": {
"category": "Error",
"code": 2790
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(10,12): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error TS2703: The operand of a 'delete' operator must be a property reference.


==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (1 errors) ====
==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (2 errors) ====
function f() {
let x: { a?: number | string, b: number | string } = { b: 1 };
x.a;
Expand All @@ -12,6 +13,8 @@ tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error T
x.b;
delete x.a;
delete x.b;
~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
x.a;
x.b;
x;
Expand Down
66 changes: 66 additions & 0 deletions tests/baselines/reference/deleteChain.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(2,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(3,9): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(6,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(7,9): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(10,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(11,9): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(14,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(15,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(16,9): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(19,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(20,9): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(23,8): error TS2790: The operand of a 'delete' operator must be optional.
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(24,9): error TS2790: The operand of a 'delete' operator must be optional.


==== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts (13 errors) ====
declare const o1: undefined | { b: string };
delete o1?.b;
~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o1?.b);
~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.

declare const o2: undefined | { b: { c: string } };
delete o2?.b.c;
~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o2?.b.c);
~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.

declare const o3: { b: undefined | { c: string } };
delete o3.b?.c;
~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o3.b?.c);
~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.

declare const o4: { b?: { c: { d?: { e: string } } } };
delete o4.b?.c.d?.e;
~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o4.b?.c.d)?.e;
~~~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o4.b?.c.d?.e);
~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.

declare const o5: { b?(): { c: { d?: { e: string } } } };
delete o5.b?.().c.d?.e;
~~~~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o5.b?.().c.d?.e);
~~~~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.

declare const o6: { b?: { c: { d?: { e: string } } } };
delete o6.b?.['c'].d?.['e'];
~~~~~~~~~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
delete (o6.b?.['c'].d?.['e']);
~~~~~~~~~~~~~~~~~~~~
!!! error TS2790: The operand of a 'delete' operator must be optional.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'.


==== tests/cases/compiler/deleteExpressionMustBeOptional.ts (1 errors) ====
interface Foo {
a: number
b: number | undefined
c: number | null
d?: number
e: number | undefined | null
f?: number | undefined | null
g: unknown
h: any
i: never
}

interface AA {
[s: string]: number
}

type BB = {
[P in keyof any]: number
}

declare const f: Foo
declare const a: AA
declare const b: BB

delete f.a
delete f.b
delete f.c
delete f.d
delete f.e
delete f.f
delete f.g
delete f.h
delete f.i
delete f.j
~
!!! error TS2339: Property 'j' does not exist on type 'Foo'.

delete a.a
delete a.b

delete b.a
delete b.b
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//// [deleteExpressionMustBeOptional.ts]
interface Foo {
a: number
b: number | undefined
c: number | null
d?: number
e: number | undefined | null
f?: number | undefined | null
g: unknown
h: any
i: never
}

interface AA {
[s: string]: number
}

type BB = {
[P in keyof any]: number
}

declare const f: Foo
declare const a: AA
declare const b: BB

delete f.a
delete f.b
delete f.c
delete f.d
delete f.e
delete f.f
delete f.g
delete f.h
delete f.i
delete f.j

delete a.a
delete a.b

delete b.a
delete b.b

//// [deleteExpressionMustBeOptional.js]
delete f.a;
delete f.b;
delete f.c;
delete f.d;
delete f.e;
delete f.f;
delete f.g;
delete f.h;
delete f.i;
delete f.j;
delete a.a;
delete a.b;
delete b.a;
delete b.b;
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
=== tests/cases/compiler/deleteExpressionMustBeOptional.ts ===
interface Foo {
>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0))

a: number
>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))

b: number | undefined
>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))

c: number | null
>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))

d?: number
>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))

e: number | undefined | null
>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))

f?: number | undefined | null
>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))

g: unknown
>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))

h: any
>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))

i: never
>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))
}

interface AA {
>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1))

[s: string]: number
>s : Symbol(s, Decl(deleteExpressionMustBeOptional.ts, 13, 5))
}

type BB = {
>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1))

[P in keyof any]: number
>P : Symbol(P, Decl(deleteExpressionMustBeOptional.ts, 17, 5))
}

declare const f: Foo
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0))

declare const a: AA
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1))

declare const b: BB
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1))

delete f.a
>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))

delete f.b
>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))

delete f.c
>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))

delete f.d
>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))

delete f.e
>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))

delete f.f
>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))

delete f.g
>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))

delete f.h
>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))

delete f.i
>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))

delete f.j
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))

delete a.a
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))

delete a.b
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))

delete b.a
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))

delete b.b
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))

Loading

0 comments on commit 39beb1d

Please sign in to comment.