[parser] Fix scope handling of Flow declared functions (#12735)
This commit is contained in:
@@ -5,26 +5,27 @@
|
||||
// Error messages are colocated with the plugin.
|
||||
/* eslint-disable @babel/development-internal/dry-error-messages */
|
||||
|
||||
import type Parser from "../parser";
|
||||
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||
import * as N from "../types";
|
||||
import type { Options } from "../options";
|
||||
import type { Pos, Position } from "../util/location";
|
||||
import type State from "../tokenizer/state";
|
||||
import { types as tc } from "../tokenizer/context";
|
||||
import type Parser from "../../parser";
|
||||
import { types as tt, type TokenType } from "../../tokenizer/types";
|
||||
import * as N from "../../types";
|
||||
import type { Pos, Position } from "../../util/location";
|
||||
import type State from "../../tokenizer/state";
|
||||
import { types as tc } from "../../tokenizer/context";
|
||||
import * as charCodes from "charcodes";
|
||||
import { isIteratorStart, isKeyword } from "../util/identifier";
|
||||
import { isIteratorStart, isKeyword } from "../../util/identifier";
|
||||
import FlowScopeHandler from "./scope";
|
||||
import {
|
||||
type BindingTypes,
|
||||
BIND_LEXICAL,
|
||||
BIND_VAR,
|
||||
BIND_FUNCTION,
|
||||
BIND_FLOW_DECLARE_FN,
|
||||
SCOPE_ARROW,
|
||||
SCOPE_FUNCTION,
|
||||
SCOPE_OTHER,
|
||||
} from "../util/scopeflags";
|
||||
import type { ExpressionErrors } from "../parser/util";
|
||||
import { Errors } from "../parser/error";
|
||||
} from "../../util/scopeflags";
|
||||
import type { ExpressionErrors } from "../../parser/util";
|
||||
import { Errors } from "../../parser/error";
|
||||
|
||||
const reservedTypes = new Set([
|
||||
"_",
|
||||
@@ -185,11 +186,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
// The value of the @flow/@noflow pragma. Initially undefined, transitions
|
||||
// to "@flow" or "@noflow" if we see a pragma. Transitions to null if we are
|
||||
// past the initial comment.
|
||||
flowPragma: void | null | "flow" | "noflow";
|
||||
flowPragma: void | null | "flow" | "noflow" = undefined;
|
||||
|
||||
constructor(options: ?Options, input: string) {
|
||||
super(options, input);
|
||||
this.flowPragma = undefined;
|
||||
getScopeHandler(): Class<FlowScopeHandler> {
|
||||
return FlowScopeHandler;
|
||||
}
|
||||
|
||||
shouldParseTypes(): boolean {
|
||||
@@ -327,6 +327,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
this.resetEndLocation(id);
|
||||
this.semicolon();
|
||||
|
||||
this.scope.declareName(node.id.name, BIND_FLOW_DECLARE_FN, node.id.start);
|
||||
|
||||
return this.finishNode(node, "DeclareFunction");
|
||||
}
|
||||
|
||||
56
packages/babel-parser/src/plugins/flow/scope.js
Normal file
56
packages/babel-parser/src/plugins/flow/scope.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// @flow
|
||||
|
||||
import ScopeHandler, { Scope } from "../../util/scope";
|
||||
import {
|
||||
BIND_FLAGS_FLOW_DECLARE_FN,
|
||||
type ScopeFlags,
|
||||
type BindingTypes,
|
||||
} from "../../util/scopeflags";
|
||||
import * as N from "../../types";
|
||||
|
||||
// Reference implementation: https://github.com/facebook/flow/blob/23aeb2a2ef6eb4241ce178fde5d8f17c5f747fb5/src/typing/env.ml#L536-L584
|
||||
class FlowScope extends Scope {
|
||||
// declare function foo(): type;
|
||||
declareFunctions: string[] = [];
|
||||
}
|
||||
|
||||
export default class FlowScopeHandler extends ScopeHandler<FlowScope> {
|
||||
createScope(flags: ScopeFlags): FlowScope {
|
||||
return new FlowScope(flags);
|
||||
}
|
||||
|
||||
declareName(name: string, bindingType: BindingTypes, pos: number) {
|
||||
const scope = this.currentScope();
|
||||
if (bindingType & BIND_FLAGS_FLOW_DECLARE_FN) {
|
||||
this.checkRedeclarationInScope(scope, name, bindingType, pos);
|
||||
this.maybeExportDefined(scope, name);
|
||||
scope.declareFunctions.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
super.declareName(...arguments);
|
||||
}
|
||||
|
||||
isRedeclaredInScope(
|
||||
scope: FlowScope,
|
||||
name: string,
|
||||
bindingType: BindingTypes,
|
||||
): boolean {
|
||||
if (super.isRedeclaredInScope(...arguments)) return true;
|
||||
|
||||
if (bindingType & BIND_FLAGS_FLOW_DECLARE_FN) {
|
||||
return (
|
||||
!scope.declareFunctions.includes(name) &&
|
||||
(scope.lexical.includes(name) || scope.functions.includes(name))
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkLocalExport(id: N.Identifier) {
|
||||
if (this.scopeStack[0].declareFunctions.indexOf(id.name) === -1) {
|
||||
super.checkLocalExport(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user