add support for flow declarations in scope tracking

This commit is contained in:
Sebastian McKenzie 2015-06-08 00:04:17 +01:00
parent 4596ae48b8
commit c91baee4d5
5 changed files with 31 additions and 9 deletions

View File

@ -7,8 +7,6 @@ export const MESSAGES = {
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead", classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
classesIllegalConstructorKind: "Illegal kind for constructor method", classesIllegalConstructorKind: "Illegal kind for constructor method",
scopeDuplicateDeclaration: "Duplicate declaration $1", scopeDuplicateDeclaration: "Duplicate declaration $1",
undeclaredVariable: "Reference to undeclared variable $1",
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
settersInvalidParamLength: "Setters must have exactly one parameter", settersInvalidParamLength: "Setters must have exactly one parameter",
settersNoRest: "Setters aren't allowed to have a rest", settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head", noAssignmentsInForHead: "No assignments allowed in for-in/of head",
@ -24,6 +22,10 @@ export const MESSAGES = {
illegalMethodName: "Illegal method name $1", illegalMethodName: "Illegal method name $1",
lostTrackNodePath: "We lost track of this nodes position, likely because the AST was directly manipulated", lostTrackNodePath: "We lost track of this nodes position, likely because the AST was directly manipulated",
undeclaredVariable: "Reference to undeclared variable $1",
undeclaredVariableType: "Referencing a type alias outside of a type annotation",
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node", traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node",
traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?", traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2", traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",

View File

@ -6,6 +6,11 @@ export var metadata = {
}; };
export function ReferencedIdentifier(node, parent, scope, file) { export function ReferencedIdentifier(node, parent, scope, file) {
var binding = scope.getBinding(node.name);
if (binding && binding.kind === "type" && !this.parentPath.isFlow()) {
throw this.errorWithNode(messages.get("undeclaredVariableType", node.name), ReferenceError);
}
if (scope.hasBinding(node.name)) return; if (scope.hasBinding(node.name)) return;
// get the closest declaration to offer as a suggestion // get the closest declaration to offer as a suggestion
@ -34,5 +39,5 @@ export function ReferencedIdentifier(node, parent, scope, file) {
// //
throw file.errorWithNode(node, msg, ReferenceError); throw this.errorWithNode(msg, ReferenceError);
} }

View File

@ -447,6 +447,8 @@ export default class Scope {
this.registerBinding("let", path); this.registerBinding("let", path);
} else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) { } else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) {
this.registerBinding("module", path); this.registerBinding("module", path);
} else if (t.isFlowDeclaration()) {
this.registerBinding("type", path);
} else { } else {
this.registerBinding("unknown", path); this.registerBinding("unknown", path);
} }
@ -494,7 +496,13 @@ export default class Scope {
var local = this.getOwnBindingInfo(name); var local = this.getOwnBindingInfo(name);
if (local) { if (local) {
// don't ever let a type alias shadow a local binding
if (kind === "type") continue;
// same identifier so continue safely as we're likely trying to register it
// multiple times
if (local.identifier === id) continue; if (local.identifier === id) continue;
this.checkBlockScopedCollisions(local, kind, name, id); this.checkBlockScopedCollisions(local, kind, name, id);
} }

View File

@ -83,15 +83,15 @@
"ArrayTypeAnnotation": ["Flow"], "ArrayTypeAnnotation": ["Flow"],
"BooleanTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "BooleanTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"ClassImplements": ["Flow"], "ClassImplements": ["Flow"],
"DeclareClass": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], "DeclareClass": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"DeclareFunction": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], "DeclareFunction": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"DeclareModule": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], "DeclareModule": ["Flow", "FlowDeclaration", "Statement"],
"DeclareVariable": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], "DeclareVariable": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"FunctionTypeAnnotation": ["Flow"], "FunctionTypeAnnotation": ["Flow"],
"FunctionTypeParam": ["Flow"], "FunctionTypeParam": ["Flow"],
"GenericTypeAnnotation": ["Flow"], "GenericTypeAnnotation": ["Flow"],
"InterfaceExtends": ["Flow"], "InterfaceExtends": ["Flow"],
"InterfaceDeclaration": ["Flow", "FlowStatement", "Statement", "Declaration"], "InterfaceDeclaration": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"IntersectionTypeAnnotation": ["Flow"], "IntersectionTypeAnnotation": ["Flow"],
"MixedTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "MixedTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"NullableTypeAnnotation": ["Flow"], "NullableTypeAnnotation": ["Flow"],
@ -100,7 +100,7 @@
"StringTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "StringTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"TupleTypeAnnotation": ["Flow"], "TupleTypeAnnotation": ["Flow"],
"TypeofTypeAnnotation": ["Flow"], "TypeofTypeAnnotation": ["Flow"],
"TypeAlias": ["Flow", "FlowStatement", "Statement"], "TypeAlias": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"TypeAnnotation": ["Flow"], "TypeAnnotation": ["Flow"],
"TypeCastExpression": ["Flow"], "TypeCastExpression": ["Flow"],
"TypeParameterDeclaration": ["Flow"], "TypeParameterDeclaration": ["Flow"],

View File

@ -30,6 +30,13 @@ export function getBindingIdentifiers(node: Object): Object {
} }
getBindingIdentifiers.keys = { getBindingIdentifiers.keys = {
DeclareClass: "id",
DeclareFunction: "id",
DeclareModule: "id",
DeclareVariable: "id",
InterfaceDeclaration: "id",
TypeAlias: "id",
ComprehensionExpression: "blocks", ComprehensionExpression: "blocks",
ComprehensionBlock: "left", ComprehensionBlock: "left",