diff --git a/packages/babel-traverse/src/path/inference/inferer-reference.js b/packages/babel-traverse/src/path/inference/inferer-reference.js index 28310f6134..4b1d8e58a9 100644 --- a/packages/babel-traverse/src/path/inference/inferer-reference.js +++ b/packages/babel-traverse/src/path/inference/inferer-reference.js @@ -48,6 +48,14 @@ function getTypeAnnotationBindingConstantViolations(path, name) { if (constantViolations.length) { // pick one constant from each scope which will represent the last possible // control flow path that it could've taken/been + /* This code is broken for the following problems: + * It thinks that assignments can only happen in scopes. + * What about conditionals, if statements without block, + * or guarded assignments. + * It also checks to see if one of the assignments is in the + * same scope and uses that as the only "violation". However, + * the binding is returned by `getConstantViolationsBefore` so we for + * sure always going to return that as the only "violation". let rawConstantViolations = constantViolations.reverse(); let visitedScopes = []; constantViolations = []; @@ -62,7 +70,7 @@ function getTypeAnnotationBindingConstantViolations(path, name) { constantViolations = [violation]; break; } - } + }*/ // add back on function constant violations since we can't track calls constantViolations = constantViolations.concat(functionConstantViolations); diff --git a/packages/babel-traverse/src/path/inference/inferers.js b/packages/babel-traverse/src/path/inference/inferers.js index 2dfaed2ab4..7a2c86f7da 100644 --- a/packages/babel-traverse/src/path/inference/inferers.js +++ b/packages/babel-traverse/src/path/inference/inferers.js @@ -112,7 +112,7 @@ export function BooleanLiteral() { } export function NullLiteral() { - return t.voidTypeAnnotation(); + return t.nullLiteralTypeAnnotation(); } export function RegExpLiteral() { diff --git a/packages/babel-traverse/test/inference.js b/packages/babel-traverse/test/inference.js new file mode 100644 index 0000000000..a8e8adc374 --- /dev/null +++ b/packages/babel-traverse/test/inference.js @@ -0,0 +1,56 @@ +var traverse = require("../lib").default; +var assert = require("assert"); +var parse = require("babylon").parse; + +function getPath(code) { + var ast = parse(code); + var path; + traverse(ast, { + Program: function (_path) { + path = _path; + _path.stop(); + } + }); + return path; +} + +suite("inference", function () { + suite("baseTypeStrictlyMatches", function () { + test("it should work with null", function () { + var path = getPath("var x = null; x === null").get("body")[1].get("expression"); + var left = path.get("left"); + var right = path.get("right"); + var strictMatch = left.baseTypeStrictlyMatches(right); + + assert.ok(strictMatch, "null should be equal to null"); + }); + + test("it should work with numbers", function () { + var path = getPath("var x = 1; x === 2").get("body")[1].get("expression"); + var left = path.get("left"); + var right = path.get("right"); + var strictMatch = left.baseTypeStrictlyMatches(right); + + assert.ok(strictMatch, "null should be equal to null"); + }); + + test("it should bail when type changes", function () { + var path = getPath("var x = 1; if (foo) x = null;else x = 3; x === 2").get("body")[2].get("expression"); + var left = path.get("left"); + var right = path.get("right"); + + var strictMatch = left.baseTypeStrictlyMatches(right); + + assert.ok(!strictMatch, "type might change in if statement"); + }); + + test("it should differentiate between null and undefined", function () { + var path = getPath("var x; x === null").get("body")[1].get("expression"); + var left = path.get("left"); + var right = path.get("right"); + var strictMatch = left.baseTypeStrictlyMatches(right); + + assert.ok(!strictMatch, "null should not match undefined"); + }); + }); +}); diff --git a/packages/babel-types/src/definitions/flow.js b/packages/babel-types/src/definitions/flow.js index d743b1c55c..367a2c50fd 100644 --- a/packages/babel-types/src/definitions/flow.js +++ b/packages/babel-types/src/definitions/flow.js @@ -30,7 +30,7 @@ defineType("BooleanLiteralTypeAnnotation", { }); defineType("NullLiteralTypeAnnotation", { - aliases: ["Flow"], + aliases: ["Flow", "FlowBaseAnnotation"], fields: {} });