From 0e1be3efa1ac49e72df9f488e6786273003cccc9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 18 Nov 2016 14:13:56 -0800 Subject: [PATCH] Always enable evolving types in Javascript files --- src/compiler/checker.ts | 4 +- .../reference/controlFlowJavascript.js | 203 ++++++++++++++ .../reference/controlFlowJavascript.symbols | 216 +++++++++++++++ .../reference/controlFlowJavascript.types | 252 ++++++++++++++++++ tests/cases/compiler/controlFlowJavascript.ts | 107 ++++++++ 5 files changed, 780 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/controlFlowJavascript.js create mode 100644 tests/baselines/reference/controlFlowJavascript.symbols create mode 100644 tests/baselines/reference/controlFlowJavascript.types create mode 100644 tests/cases/compiler/controlFlowJavascript.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 348b287f4f3..f09d622d742 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3239,10 +3239,10 @@ namespace ts { return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality); } - if (compilerOptions.noImplicitAny && + if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) && declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) { - // If --noImplicitAny is on, + // If --noImplicitAny is on or the declaration is in a Javascript file, // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no // initializer or a 'null' or 'undefined' initializer. if (!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) { diff --git a/tests/baselines/reference/controlFlowJavascript.js b/tests/baselines/reference/controlFlowJavascript.js new file mode 100644 index 00000000000..66518a6567a --- /dev/null +++ b/tests/baselines/reference/controlFlowJavascript.js @@ -0,0 +1,203 @@ +//// [controlFlowJavascript.js] + +let cond = true; + +// CFA for 'let' and no initializer +function f1() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'let' and 'undefined' initializer +function f2() { + let x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'let' and 'null' initializer +function f3() { + let x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | null +} + +// CFA for 'var' with no initializer +function f5() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'var' with 'undefined' initializer +function f6() { + var x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'var' with 'null' initializer +function f7() { + var x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | null +} + +// No CFA for captured outer variables +function f9() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined + function f() { + const z = x; // any + } +} + +// No CFA for captured outer variables +function f10() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined + const f = () => { + const z = x; // any + }; +} + + +//// [out.js] +var cond = true; +// CFA for 'let' and no initializer +function f1() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined +} +// CFA for 'let' and 'undefined' initializer +function f2() { + var x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined +} +// CFA for 'let' and 'null' initializer +function f3() { + var x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | null +} +// CFA for 'var' with no initializer +function f5() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined +} +// CFA for 'var' with 'undefined' initializer +function f6() { + var x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined +} +// CFA for 'var' with 'null' initializer +function f7() { + var x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | null +} +// No CFA for captured outer variables +function f9() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined + function f() { + var z = x; // any + } +} +// No CFA for captured outer variables +function f10() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + var y = x; // string | number | undefined + var f = function () { + var z = x; // any + }; +} diff --git a/tests/baselines/reference/controlFlowJavascript.symbols b/tests/baselines/reference/controlFlowJavascript.symbols new file mode 100644 index 00000000000..b3316de3b4e --- /dev/null +++ b/tests/baselines/reference/controlFlowJavascript.symbols @@ -0,0 +1,216 @@ +=== tests/cases/compiler/controlFlowJavascript.js === + +let cond = true; +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + +// CFA for 'let' and no initializer +function f1() { +>f1 : Symbol(f1, Decl(controlFlowJavascript.js, 1, 16)) + + let x; +>x : Symbol(x, Decl(controlFlowJavascript.js, 5, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 5, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 5, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 12, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 5, 7)) +} + +// CFA for 'let' and 'undefined' initializer +function f2() { +>f2 : Symbol(f2, Decl(controlFlowJavascript.js, 13, 1)) + + let x = undefined; +>x : Symbol(x, Decl(controlFlowJavascript.js, 17, 7)) +>undefined : Symbol(undefined) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 17, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 17, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 24, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 17, 7)) +} + +// CFA for 'let' and 'null' initializer +function f3() { +>f3 : Symbol(f3, Decl(controlFlowJavascript.js, 25, 1)) + + let x = null; +>x : Symbol(x, Decl(controlFlowJavascript.js, 29, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 29, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 29, 7)) + } + const y = x; // string | number | null +>y : Symbol(y, Decl(controlFlowJavascript.js, 36, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 29, 7)) +} + +// CFA for 'var' with no initializer +function f5() { +>f5 : Symbol(f5, Decl(controlFlowJavascript.js, 37, 1)) + + var x; +>x : Symbol(x, Decl(controlFlowJavascript.js, 41, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 41, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 41, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 48, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 41, 7)) +} + +// CFA for 'var' with 'undefined' initializer +function f6() { +>f6 : Symbol(f6, Decl(controlFlowJavascript.js, 49, 1)) + + var x = undefined; +>x : Symbol(x, Decl(controlFlowJavascript.js, 53, 7)) +>undefined : Symbol(undefined) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 53, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 53, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 60, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 53, 7)) +} + +// CFA for 'var' with 'null' initializer +function f7() { +>f7 : Symbol(f7, Decl(controlFlowJavascript.js, 61, 1)) + + var x = null; +>x : Symbol(x, Decl(controlFlowJavascript.js, 65, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 65, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 65, 7)) + } + const y = x; // string | number | null +>y : Symbol(y, Decl(controlFlowJavascript.js, 72, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 65, 7)) +} + +// No CFA for captured outer variables +function f9() { +>f9 : Symbol(f9, Decl(controlFlowJavascript.js, 73, 1)) + + let x; +>x : Symbol(x, Decl(controlFlowJavascript.js, 77, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 77, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 77, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 84, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 77, 7)) + + function f() { +>f : Symbol(f, Decl(controlFlowJavascript.js, 84, 16)) + + const z = x; // any +>z : Symbol(z, Decl(controlFlowJavascript.js, 86, 13)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 77, 7)) + } +} + +// No CFA for captured outer variables +function f10() { +>f10 : Symbol(f10, Decl(controlFlowJavascript.js, 88, 1)) + + let x; +>x : Symbol(x, Decl(controlFlowJavascript.js, 92, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = 1; +>x : Symbol(x, Decl(controlFlowJavascript.js, 92, 7)) + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowJavascript.js, 1, 3)) + + x = "hello"; +>x : Symbol(x, Decl(controlFlowJavascript.js, 92, 7)) + } + const y = x; // string | number | undefined +>y : Symbol(y, Decl(controlFlowJavascript.js, 99, 9)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 92, 7)) + + const f = () => { +>f : Symbol(f, Decl(controlFlowJavascript.js, 100, 9)) + + const z = x; // any +>z : Symbol(z, Decl(controlFlowJavascript.js, 101, 13)) +>x : Symbol(x, Decl(controlFlowJavascript.js, 92, 7)) + + }; +} + diff --git a/tests/baselines/reference/controlFlowJavascript.types b/tests/baselines/reference/controlFlowJavascript.types new file mode 100644 index 00000000000..0b88c62cb78 --- /dev/null +++ b/tests/baselines/reference/controlFlowJavascript.types @@ -0,0 +1,252 @@ +=== tests/cases/compiler/controlFlowJavascript.js === + +let cond = true; +>cond : boolean +>true : true + +// CFA for 'let' and no initializer +function f1() { +>f1 : () => void + + let x; +>x : any + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number +} + +// CFA for 'let' and 'undefined' initializer +function f2() { +>f2 : () => void + + let x = undefined; +>x : any +>undefined : undefined + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number +} + +// CFA for 'let' and 'null' initializer +function f3() { +>f3 : () => void + + let x = null; +>x : any +>null : null + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | null +>y : string | number +>x : string | number +} + +// CFA for 'var' with no initializer +function f5() { +>f5 : () => void + + var x; +>x : any + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number +} + +// CFA for 'var' with 'undefined' initializer +function f6() { +>f6 : () => void + + var x = undefined; +>x : any +>undefined : undefined + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number +} + +// CFA for 'var' with 'null' initializer +function f7() { +>f7 : () => void + + var x = null; +>x : any +>null : null + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | null +>y : string | number +>x : string | number +} + +// No CFA for captured outer variables +function f9() { +>f9 : () => void + + let x; +>x : any + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number + + function f() { +>f : () => void + + const z = x; // any +>z : any +>x : any + } +} + +// No CFA for captured outer variables +function f10() { +>f10 : () => void + + let x; +>x : any + + if (cond) { +>cond : boolean + + x = 1; +>x = 1 : 1 +>x : any +>1 : 1 + } + if (cond) { +>cond : boolean + + x = "hello"; +>x = "hello" : "hello" +>x : any +>"hello" : "hello" + } + const y = x; // string | number | undefined +>y : string | number +>x : string | number + + const f = () => { +>f : () => void +>() => { const z = x; // any } : () => void + + const z = x; // any +>z : any +>x : any + + }; +} + diff --git a/tests/cases/compiler/controlFlowJavascript.ts b/tests/cases/compiler/controlFlowJavascript.ts new file mode 100644 index 00000000000..b2886a2233a --- /dev/null +++ b/tests/cases/compiler/controlFlowJavascript.ts @@ -0,0 +1,107 @@ +// @allowJs: true +// @Filename: controlFlowJavascript.js +// @out: out.js + +let cond = true; + +// CFA for 'let' and no initializer +function f1() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'let' and 'undefined' initializer +function f2() { + let x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'let' and 'null' initializer +function f3() { + let x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | null +} + +// CFA for 'var' with no initializer +function f5() { + var x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'var' with 'undefined' initializer +function f6() { + var x = undefined; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined +} + +// CFA for 'var' with 'null' initializer +function f7() { + var x = null; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | null +} + +// No CFA for captured outer variables +function f9() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined + function f() { + const z = x; // any + } +} + +// No CFA for captured outer variables +function f10() { + let x; + if (cond) { + x = 1; + } + if (cond) { + x = "hello"; + } + const y = x; // string | number | undefined + const f = () => { + const z = x; // any + }; +}