Introduce scope tracking in the parser (#9493)

* Introduce scope tracking

* Fix tests

* Add new tests

* Remove constructor-super check from transform as it is now in parser

* Correctly handle class properties and class scope

* Fix duplicate name check

* Convert scope identifier storage to array

* Enter a new scope in typescript module blocks

* Add test for duplicate declaration

* Rename error for duplicate exports

* Treat class declarations as lexical declaration

* Update whitelist

* Add tests

* Fix scope tracking for function declarations

* Migrate try-catch duplicate error

* Fix test

* More tests

* One more test

* Make scope a separate class and fix review comments

* Do not allow new.target in top scope arrow function

* Correctly enter new scope for declare module and treat type aliases as lexical declarations

* Tests for typescript scope tracking to not mark type aliases as duplicate

* Fix flow scope tracking

* Remove ident from test names as redundant

* Add test case for var and function

* Improve error messages

* Improve literal regex
This commit is contained in:
Daniel Tschinder
2019-02-25 11:04:52 -08:00
committed by GitHub
parent 918f149a63
commit a7391144b3
284 changed files with 5904 additions and 1842 deletions

View File

@@ -16,6 +16,7 @@ import type {
import type { Pos, Position } from "../util/location";
import { isStrictBindReservedWord } from "../util/identifier";
import { NodeUtils } from "./node";
import { type BindingTypes, BIND_NONE, BIND_OUTSIDE } from "../util/scopeflags";
export default class LValParser extends NodeUtils {
// Forward-declaration: defined in expression.js
@@ -262,7 +263,7 @@ export default class LValParser extends NodeUtils {
elts.push(this.parseAssignableListItemTypes(this.parseRest()));
this.checkCommaAfterRest(
close,
this.state.inFunction && this.state.inParameters
this.scope.inFunction && this.state.inParameters
? "parameter"
: "element",
);
@@ -325,7 +326,7 @@ export default class LValParser extends NodeUtils {
checkLVal(
expr: Expression,
isBinding: ?boolean,
bindingType: ?BindingTypes = BIND_NONE,
checkClashes: ?{ [key: string]: boolean },
contextDescription: string,
): void {
@@ -337,7 +338,7 @@ export default class LValParser extends NodeUtils {
) {
this.raise(
expr.start,
`${isBinding ? "Binding" : "Assigning to"} '${
`${bindingType === BIND_NONE ? "Assigning to" : "Binding"} '${
expr.name
}' in strict mode`,
);
@@ -358,15 +359,20 @@ export default class LValParser extends NodeUtils {
const key = `_${expr.name}`;
if (checkClashes[key]) {
this.raise(expr.start, "Argument name clash in strict mode");
this.raise(expr.start, "Argument name clash");
} else {
checkClashes[key] = true;
}
}
if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) {
this.scope.declareName(expr.name, bindingType, expr.start);
}
break;
case "MemberExpression":
if (isBinding) this.raise(expr.start, "Binding member expression");
if (bindingType !== BIND_NONE) {
this.raise(expr.start, "Binding member expression");
}
break;
case "ObjectPattern":
@@ -374,7 +380,7 @@ export default class LValParser extends NodeUtils {
if (prop.type === "ObjectProperty") prop = prop.value;
this.checkLVal(
prop,
isBinding,
bindingType,
checkClashes,
"object destructuring pattern",
);
@@ -386,7 +392,7 @@ export default class LValParser extends NodeUtils {
if (elem) {
this.checkLVal(
elem,
isBinding,
bindingType,
checkClashes,
"array destructuring pattern",
);
@@ -397,21 +403,26 @@ export default class LValParser extends NodeUtils {
case "AssignmentPattern":
this.checkLVal(
expr.left,
isBinding,
bindingType,
checkClashes,
"assignment pattern",
);
break;
case "RestElement":
this.checkLVal(expr.argument, isBinding, checkClashes, "rest element");
this.checkLVal(
expr.argument,
bindingType,
checkClashes,
"rest element",
);
break;
default: {
const message =
(isBinding
? /* istanbul ignore next */ "Binding invalid"
: "Invalid") +
(bindingType === BIND_NONE
? "Invalid"
: /* istanbul ignore next */ "Binding invalid") +
" left-hand side" +
(contextDescription
? " in " + contextDescription