diff --git a/.flowconfig b/.flowconfig index 901d11353e..b9f63f8dba 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,3 +11,5 @@ suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe suppress_comment= \\(.\\|\n\\)*\\$FlowIssue suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore +suppress_type=$FlowFixMe +suppress_type=$FlowSubtype diff --git a/src/parser/expression.js b/src/parser/expression.js index f97f3f9f76..dc392e6d23 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -1401,21 +1401,17 @@ export default class ExpressionParser extends LValParser { } parsePropertyName( - prop: - | N.ObjectOrClassMember - | N.ClassPrivateProperty - | N.ClassPrivateMethod - | N.TsNamedTypeElementBase, + prop: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase, ): N.Expression | N.Identifier { if (this.eat(tt.bracketL)) { - prop.computed = true; + (prop: $FlowSubtype).computed = true; prop.key = this.parseMaybeAssign(); this.expect(tt.bracketR); } else { const oldInPropertyName = this.state.inPropertyName; this.state.inPropertyName = true; // We check if it's valid for it to be a private name when we push it. - prop.key = + (prop: $FlowFixMe).key = this.match(tt.num) || this.match(tt.string) ? this.parseExprAtom() : this.parseMaybePrivateName(); diff --git a/src/parser/statement.js b/src/parser/statement.js index fbbbe63c74..ac1a9f57d9 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -921,15 +921,12 @@ export default class StatementParser extends ExpressionParser { member: N.ClassMember, state: { hadConstructor: boolean }, ): void { - // Use the appropriate variable to represent `member` once a more specific type is known. - const memberAny: any = member; - const method: N.ClassMethod = memberAny; - const prop: N.ClassProperty = memberAny; - let isStatic = false; if (this.match(tt.name) && this.state.value === "static") { const key = this.parseIdentifier(true); // eats 'static' if (this.isClassMethod()) { + const method: N.ClassMethod = (member: any); + // a method named 'static' method.kind = "method"; method.computed = false; @@ -944,6 +941,8 @@ export default class StatementParser extends ExpressionParser { ); return; } else if (this.isClassProperty()) { + const prop: N.ClassProperty = (member: any); + // a property named 'static' prop.computed = false; prop.key = key; @@ -964,16 +963,15 @@ export default class StatementParser extends ExpressionParser { state: { hadConstructor: boolean }, isStatic: boolean, ) { - const memberAny: any = member; - const methodOrProp: - | N.ClassMethod - | N.ClassPrivateMethod - | N.ClassProperty - | N.ClassPrivateProperty = memberAny; - const method: N.ClassMethod | N.ClassPrivateMethod = memberAny; - const prop: N.ClassProperty | N.ClassPrivateProperty = memberAny; + const publicMethod: $FlowSubtype = member; + const privateMethod: $FlowSubtype = member; + const publicProp: $FlowSubtype = member; + const privateProp: $FlowSubtype = member; - methodOrProp.static = isStatic; + const method: typeof publicMethod | typeof privateMethod = publicMethod; + const publicMember: typeof publicMethod | typeof publicProp = publicMethod; + + member.static = isStatic; if (this.eat(tt.star)) { // a generator @@ -982,17 +980,17 @@ export default class StatementParser extends ExpressionParser { if (method.key.type === "PrivateName") { // Private generator method - this.pushClassPrivateMethod(classBody, method, true, false); + this.pushClassPrivateMethod(classBody, privateMethod, true, false); return; } - if (this.isNonstaticConstructor(method)) { - this.raise(method.key.start, "Constructor can't be a generator"); + if (this.isNonstaticConstructor(publicMethod)) { + this.raise(publicMethod.key.start, "Constructor can't be a generator"); } this.pushClassMethod( classBody, - method, + publicMethod, true, false, /* isConstructor */ false, @@ -1001,30 +999,30 @@ export default class StatementParser extends ExpressionParser { return; } - const key = this.parseClassPropertyName(methodOrProp); + const key = this.parseClassPropertyName(member); const isPrivate = key.type === "PrivateName"; // Check the key is not a computed expression or string literal. const isSimple = key.type === "Identifier"; - this.parsePostMemberNameModifiers(methodOrProp); + this.parsePostMemberNameModifiers(publicMember); if (this.isClassMethod()) { method.kind = "method"; if (isPrivate) { - this.pushClassPrivateMethod(classBody, method, false, false); + this.pushClassPrivateMethod(classBody, privateMethod, false, false); return; } // a normal method - const isConstructor = this.isNonstaticConstructor(method); + const isConstructor = this.isNonstaticConstructor(publicMethod); if (isConstructor) { - method.kind = "constructor"; + publicMethod.kind = "constructor"; - if (method.decorators) { + if (publicMethod.decorators) { this.raise( - method.start, + publicMethod.start, "You can't attach decorators to a class constructor", ); } @@ -1036,12 +1034,18 @@ export default class StatementParser extends ExpressionParser { state.hadConstructor = true; } - this.pushClassMethod(classBody, method, false, false, isConstructor); + this.pushClassMethod( + classBody, + publicMethod, + false, + false, + isConstructor, + ); } else if (this.isClassProperty()) { if (isPrivate) { - this.pushClassPrivateProperty(classBody, prop); + this.pushClassPrivateProperty(classBody, privateProp); } else { - this.pushClassProperty(classBody, prop); + this.pushClassProperty(classBody, publicProp); } } else if (isSimple && key.name === "async" && !this.isLineTerminator()) { // an async method @@ -1057,18 +1061,23 @@ export default class StatementParser extends ExpressionParser { if (method.key.type === "PrivateName") { // private async method - this.pushClassPrivateMethod(classBody, method, isGenerator, true); + this.pushClassPrivateMethod( + classBody, + privateMethod, + isGenerator, + true, + ); } else { - if (this.isNonstaticConstructor(method)) { + if (this.isNonstaticConstructor(publicMethod)) { this.raise( - method.key.start, + publicMethod.key.start, "Constructor can't be an async function", ); } this.pushClassMethod( classBody, - method, + publicMethod, isGenerator, true, /* isConstructor */ false, @@ -1083,53 +1092,48 @@ export default class StatementParser extends ExpressionParser { // a getter or setter method.kind = key.name; // The so-called parsed name would have been "get/set": get the real name. - this.parseClassPropertyName(method); + this.parseClassPropertyName(publicMethod); if (method.key.type === "PrivateName") { // private getter/setter - this.pushClassPrivateMethod(classBody, method, false, false); + this.pushClassPrivateMethod(classBody, privateMethod, false, false); } else { - if (this.isNonstaticConstructor(method)) { + if (this.isNonstaticConstructor(publicMethod)) { this.raise( - method.key.start, + publicMethod.key.start, "Constructor can't have get/set modifier", ); } this.pushClassMethod( classBody, - method, + publicMethod, false, false, /* isConstructor */ false, ); } - this.checkGetterSetterParamCount(method); + this.checkGetterSetterParamCount(publicMethod); } else if (this.isLineTerminator()) { // an uninitialized class property (due to ASI, since we don't otherwise recognize the next token) if (isPrivate) { - this.pushClassPrivateProperty(classBody, prop); + this.pushClassPrivateProperty(classBody, privateProp); } else { - this.pushClassProperty(classBody, prop); + this.pushClassProperty(classBody, publicProp); } } else { this.unexpected(); } } - parseClassPropertyName( - methodOrProp: - | N.ClassMethod - | N.ClassProperty - | N.ClassPrivateProperty - | N.ClassPrivateMethod, - ): N.Expression | N.Identifier { - const key = this.parsePropertyName(methodOrProp); + parseClassPropertyName(member: N.ClassMember): N.Expression | N.Identifier { + const key = this.parsePropertyName(member); if ( - !methodOrProp.computed && - methodOrProp.static && - (key.name === "prototype" || key.value === "prototype") + !member.computed && + member.static && + ((key: $FlowSubtype).name === "prototype" || + (key: $FlowSubtype).value === "prototype") ) { this.raise( key.start, @@ -1158,7 +1162,10 @@ export default class StatementParser extends ExpressionParser { classBody.body.push(this.parseClassProperty(prop)); } - pushClassPrivateProperty(classBody: N.ClassBody, prop: N.ClassProperty) { + pushClassPrivateProperty( + classBody: N.ClassBody, + prop: N.ClassPrivateProperty, + ) { this.expectPlugin("classPrivateProperties", prop.key.start); classBody.body.push(this.parseClassPrivateProperty(prop)); } @@ -1183,7 +1190,7 @@ export default class StatementParser extends ExpressionParser { pushClassPrivateMethod( classBody: N.ClassBody, - method: N.ClassMethod, + method: N.ClassPrivateMethod, isGenerator: boolean, isAsync: boolean, ): void { diff --git a/src/plugins/flow.js b/src/plugins/flow.js index d8b1d6db02..8cc8461198 100644 --- a/src/plugins/flow.js +++ b/src/plugins/flow.js @@ -1699,10 +1699,10 @@ export default (superClass: Class): Class => isAsync: boolean, isConstructor: boolean, ): void { - if (method.variance) { - this.unexpected(method.variance.start); + if ((method: $FlowFixMe).variance) { + this.unexpected((method: $FlowFixMe).variance.start); } - delete method.variance; + delete (method: $FlowFixMe).variance; if (this.isRelational("<")) { method.typeParameters = this.flowParseTypeParameterDeclaration(); } @@ -1722,10 +1722,10 @@ export default (superClass: Class): Class => isGenerator: boolean, isAsync: boolean, ): void { - if (method.variance) { - this.unexpected(method.variance.start); + if ((method: $FlowFixMe).variance) { + this.unexpected((method: $FlowFixMe).variance.start); } - delete method.variance; + delete (method: $FlowFixMe).variance; if (this.isRelational("<")) { method.typeParameters = this.flowParseTypeParameterDeclaration(); } @@ -1756,7 +1756,7 @@ export default (superClass: Class): Class => } parsePropertyName( - node: N.ObjectOrClassMember | N.TsNamedTypeElementBase, + node: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase, ): N.Identifier { const variance = this.flowParseVariance(); const key = super.parsePropertyName(node); @@ -1775,10 +1775,10 @@ export default (superClass: Class): Class => isPattern: boolean, refShorthandDefaultPos: ?Pos, ): void { - if (prop.variance) { - this.unexpected(prop.variance.start); + if ((prop: $FlowFixMe).variance) { + this.unexpected((prop: $FlowFixMe).variance.start); } - delete prop.variance; + delete (prop: $FlowFixMe).variance; let typeParameters; diff --git a/src/types.js b/src/types.js index b444606733..93839e88f8 100644 --- a/src/types.js +++ b/src/types.js @@ -621,7 +621,7 @@ export type ClassBase = HasDecorators & { export type ClassBody = NodeBase & { type: "ClassBody", - body: Array, // TODO: $ReadOnlyArray + body: Array, // TODO: $ReadOnlyArray }; export type ClassMemberBase = NodeBase & @@ -638,8 +638,7 @@ export type ClassMember = | ClassMethod | ClassPrivateMethod | ClassProperty - | ClassPrivateProperty - | TsIndexSignature; + | ClassPrivateProperty; export type MethodLike = | ObjectMethod @@ -655,7 +654,6 @@ export type MethodBase = FunctionBase & { export type MethodKind = "constructor" | "method" | "get" | "set"; export type ClassMethodOrDeclareMethodCommon = ClassMemberBase & { - type: "ClassMethod", key: Expression, kind: MethodKind, static: boolean, @@ -664,13 +662,16 @@ export type ClassMethodOrDeclareMethodCommon = ClassMemberBase & { export type ClassMethod = MethodBase & ClassMethodOrDeclareMethodCommon & { + type: "ClassMethod", variance?: ?FlowVariance, // TODO: Not in spec }; export type ClassPrivateMethod = NodeBase & - ClassMethodOrDeclareMethodCommon & { + ClassMethodOrDeclareMethodCommon & + MethodBase & { type: "ClassPrivateMethod", key: PrivateName, + computed: false, }; export type ClassProperty = ClassMemberBase & { @@ -690,6 +691,7 @@ export type ClassPrivateProperty = NodeBase & { key: PrivateName, value: ?Expression, // TODO: Not in spec that this is nullable. static: boolean, + computed: false, }; export type OptClassDeclaration = ClassBase &