Fix a few type inferences (#5835)

This commit is contained in:
Justin Ridgewell
2017-07-20 11:38:12 -04:00
committed by Henry Zhu
parent 78544417fc
commit 8a98141b60
6 changed files with 165 additions and 84 deletions

View File

@@ -11,7 +11,11 @@ export default function(node: Object) {
if (binding.identifier.typeAnnotation) {
return binding.identifier.typeAnnotation;
} else {
return getTypeAnnotationBindingConstantViolations(this, node.name);
return getTypeAnnotationBindingConstantViolations(
binding,
this,
node.name,
);
}
}
@@ -25,11 +29,8 @@ export default function(node: Object) {
}
}
function getTypeAnnotationBindingConstantViolations(path, name) {
const binding = path.scope.getBinding(name);
function getTypeAnnotationBindingConstantViolations(binding, path, name) {
const types = [];
path.typeAnnotation = t.unionTypeAnnotation(types);
const functionConstantViolations = [];
let constantViolations = getConstantViolationsBefore(
@@ -38,7 +39,7 @@ function getTypeAnnotationBindingConstantViolations(path, name) {
functionConstantViolations,
);
const testType = getConditionalAnnotation(path, name);
const testType = getConditionalAnnotation(binding, path, name);
if (testType) {
const testConstantViolations = getConstantViolationsBefore(
binding,
@@ -118,18 +119,20 @@ function inferAnnotationFromBinaryExpression(name, path) {
} else if (right.isIdentifier({ name })) {
target = left;
}
if (target) {
if (operator === "===") {
return target.getTypeAnnotation();
} else if (t.BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else {
return;
}
} else {
if (operator !== "===") return;
if (t.BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
}
return;
}
if (operator !== "===" && operator !== "==") return;
//
let typeofPath;
let typePath;
@@ -140,7 +143,10 @@ function inferAnnotationFromBinaryExpression(name, path) {
typeofPath = right;
typePath = left;
}
if (!typePath && !typeofPath) return;
if (!typeofPath) return;
// and that the argument of the typeof path references us!
if (!typeofPath.get("argument").isIdentifier({ name })) return;
// ensure that the type path is a Literal
typePath = typePath.resolve();
@@ -150,56 +156,56 @@ function inferAnnotationFromBinaryExpression(name, path) {
const typeValue = typePath.node.value;
if (typeof typeValue !== "string") return;
// and that the argument of the typeof path references us!
if (!typeofPath.get("argument").isIdentifier({ name })) return;
// turn type value into a type annotation
return t.createTypeAnnotationBasedOnTypeof(typePath.node.value);
return t.createTypeAnnotationBasedOnTypeof(typeValue);
}
function getParentConditionalPath(path) {
function getParentConditionalPath(binding, path, name) {
let parentPath;
while ((parentPath = path.parentPath)) {
if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) {
if (path.key === "test") {
return;
} else {
return parentPath;
}
} else {
path = parentPath;
return parentPath;
}
if (parentPath.isFunction()) {
if (parentPath.parentPath.scope.getBinding(name) !== binding) return;
}
path = parentPath;
}
}
function getConditionalAnnotation(path, name) {
const ifStatement = getParentConditionalPath(path);
function getConditionalAnnotation(binding, path, name) {
const ifStatement = getParentConditionalPath(binding, path, name);
if (!ifStatement) return;
const test = ifStatement.get("test");
const paths = [test];
const types = [];
do {
const path = paths.shift().resolve();
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
if (path.isLogicalExpression()) {
paths.push(path.get("left"));
paths.push(path.get("right"));
}
if (path.isBinaryExpression()) {
if (path.node.operator === "&&") {
paths.push(path.get("left"));
paths.push(path.get("right"));
}
} else if (path.isBinaryExpression()) {
const type = inferAnnotationFromBinaryExpression(name, path);
if (type) types.push(type);
}
} while (paths.length);
}
if (types.length) {
return {
typeAnnotation: t.createUnionTypeAnnotation(types),
ifStatement,
};
} else {
return getConditionalAnnotation(ifStatement, name);
}
return getConditionalAnnotation(ifStatement, name);
}