From 65468ed352e0240d060e1a8fc0782b8fb9de2ff5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 11 May 2016 16:57:06 -0700 Subject: [PATCH 1/2] Include 'delete' operator in control flow analysis --- src/compiler/binder.ts | 10 ++++++++++ src/compiler/checker.ts | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 05dbd47006b..304e77271a7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -580,6 +580,9 @@ namespace ts { case SyntaxKind.BinaryExpression: bindBinaryExpressionFlow(node); break; + case SyntaxKind.DeleteExpression: + bindDeleteExpressionFlow(node); + break; case SyntaxKind.ConditionalExpression: bindConditionalExpressionFlow(node); break; @@ -1055,6 +1058,13 @@ namespace ts { } } + function bindDeleteExpressionFlow(node: DeleteExpression) { + forEachChild(node, bind); + if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { + bindAssignmentTargetFlow(node.expression); + } + } + function bindConditionalExpressionFlow(node: ConditionalExpression) { const trueLabel = createBranchLabel(); const falseLabel = createBranchLabel(); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa8004a5d91..f9b84e857dd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7563,6 +7563,8 @@ namespace ts { return checkRightHandSideOfForOf((parent).expression) || unknownType; case SyntaxKind.BinaryExpression: return getAssignedTypeOfBinaryExpression(parent); + case SyntaxKind.DeleteExpression: + return undefinedType; case SyntaxKind.ArrayLiteralExpression: return getAssignedTypeOfArrayLiteralElement(parent, node); case SyntaxKind.SpreadElementExpression: From fb2607c95c20549870a8424d98778e97adc16cfc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 11 May 2016 16:57:19 -0700 Subject: [PATCH 2/2] Adding test --- .../reference/controlFlowDeleteOperator.js | 36 +++++++++ .../controlFlowDeleteOperator.symbols | 70 ++++++++++++++++ .../reference/controlFlowDeleteOperator.types | 79 +++++++++++++++++++ .../controlFlow/controlFlowDeleteOperator.ts | 18 +++++ 4 files changed, 203 insertions(+) create mode 100644 tests/baselines/reference/controlFlowDeleteOperator.js create mode 100644 tests/baselines/reference/controlFlowDeleteOperator.symbols create mode 100644 tests/baselines/reference/controlFlowDeleteOperator.types create mode 100644 tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts diff --git a/tests/baselines/reference/controlFlowDeleteOperator.js b/tests/baselines/reference/controlFlowDeleteOperator.js new file mode 100644 index 00000000000..36ac88467d2 --- /dev/null +++ b/tests/baselines/reference/controlFlowDeleteOperator.js @@ -0,0 +1,36 @@ +//// [controlFlowDeleteOperator.ts] + +function f() { + let x: { a?: number | string, b: number | string } = { b: 1 }; + x.a; + x.b; + x.a = 1; + x.b = 1; + x.a; + x.b; + delete x.a; + delete x.b; + x.a; + x.b; + x; + delete x; // No effect + x; +} + +//// [controlFlowDeleteOperator.js] +function f() { + var x = { b: 1 }; + x.a; + x.b; + x.a = 1; + x.b = 1; + x.a; + x.b; + delete x.a; + delete x.b; + x.a; + x.b; + x; + delete x; // No effect + x; +} diff --git a/tests/baselines/reference/controlFlowDeleteOperator.symbols b/tests/baselines/reference/controlFlowDeleteOperator.symbols new file mode 100644 index 00000000000..029c9ddafcc --- /dev/null +++ b/tests/baselines/reference/controlFlowDeleteOperator.symbols @@ -0,0 +1,70 @@ +=== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts === + +function f() { +>f : Symbol(f, Decl(controlFlowDeleteOperator.ts, 0, 0)) + + let x: { a?: number | string, b: number | string } = { b: 1 }; +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 58)) + + x.a; +>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) + + x.b; +>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) + + x.a = 1; +>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) + + x.b = 1; +>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) + + x.a; +>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) + + x.b; +>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) + + delete x.a; +>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) + + delete x.b; +>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) + + x.a; +>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12)) + + x.b; +>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33)) + + x; +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) + + delete x; // No effect +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) + + x; +>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7)) +} diff --git a/tests/baselines/reference/controlFlowDeleteOperator.types b/tests/baselines/reference/controlFlowDeleteOperator.types new file mode 100644 index 00000000000..365174db058 --- /dev/null +++ b/tests/baselines/reference/controlFlowDeleteOperator.types @@ -0,0 +1,79 @@ +=== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts === + +function f() { +>f : () => void + + let x: { a?: number | string, b: number | string } = { b: 1 }; +>x : { a?: number | string | undefined; b: number | string; } +>a : number | string | undefined +>b : number | string +>{ b: 1 } : { b: number; } +>b : number +>1 : number + + x.a; +>x.a : number | string | undefined +>x : { a?: number | string | undefined; b: number | string; } +>a : number | string | undefined + + x.b; +>x.b : number | string +>x : { a?: number | string | undefined; b: number | string; } +>b : number | string + + x.a = 1; +>x.a = 1 : number +>x.a : number | string | undefined +>x : { a?: number | string | undefined; b: number | string; } +>a : number | string | undefined +>1 : number + + x.b = 1; +>x.b = 1 : number +>x.b : number | string +>x : { a?: number | string | undefined; b: number | string; } +>b : number | string +>1 : number + + x.a; +>x.a : number +>x : { a?: number | string | undefined; b: number | string; } +>a : number + + x.b; +>x.b : number +>x : { a?: number | string | undefined; b: number | string; } +>b : number + + delete x.a; +>delete x.a : boolean +>x.a : number +>x : { a?: number | string | undefined; b: number | string; } +>a : number + + delete x.b; +>delete x.b : boolean +>x.b : number +>x : { a?: number | string | undefined; b: number | string; } +>b : number + + x.a; +>x.a : undefined +>x : { a?: number | string | undefined; b: number | string; } +>a : undefined + + x.b; +>x.b : number | string +>x : { a?: number | string | undefined; b: number | string; } +>b : number | string + + x; +>x : { a?: number | string | undefined; b: number | string; } + + delete x; // No effect +>delete x : boolean +>x : { a?: number | string | undefined; b: number | string; } + + x; +>x : { a?: number | string | undefined; b: number | string; } +} diff --git a/tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts b/tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts new file mode 100644 index 00000000000..0f4b209bd45 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts @@ -0,0 +1,18 @@ +// @strictNullChecks: true + +function f() { + let x: { a?: number | string, b: number | string } = { b: 1 }; + x.a; + x.b; + x.a = 1; + x.b = 1; + x.a; + x.b; + delete x.a; + delete x.b; + x.a; + x.b; + x; + delete x; // No effect + x; +} \ No newline at end of file