Duplicate __proto__ key should be allowed in object patterns (#10987)

* refactor: replace refShorthandDefaultPos by refExpressionErrors

* fix: duplicate __proto__ keys should be allowed in patterns

* docs: add comments for ExpressionErrors.doubleProto [ci-skip]

* test: add more test for coverage
This commit is contained in:
Huáng Jùnliàng 2020-01-14 22:53:45 -05:00 committed by GitHub
parent a0a9c64a47
commit 9df70b4505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 820 additions and 96 deletions

View File

@ -41,6 +41,7 @@ import {
SCOPE_PROGRAM,
SCOPE_ASYNC,
} from "../util/scopeflags";
import { ExpressionErrors } from "./util";
export default class ExpressionParser extends LValParser {
// Forward-declaration: defined in statement.js
@ -69,7 +70,8 @@ export default class ExpressionParser extends LValParser {
checkDuplicatedProto(
prop: N.ObjectMember | N.SpreadElement,
protoRef: { used: boolean, start?: number },
protoRef: { used: boolean },
refExpressionErrors: ?ExpressionErrors,
): void {
if (
prop.type === "SpreadElement" ||
@ -87,8 +89,12 @@ export default class ExpressionParser extends LValParser {
if (name === "__proto__") {
// Store the first redefinition's position
if (protoRef.used && !protoRef.start) {
protoRef.start = key.start;
if (protoRef.used) {
if (refExpressionErrors && refExpressionErrors.doubleProto === -1) {
refExpressionErrors.doubleProto = key.start;
} else {
this.raise(key.start, "Redefinition of __proto__ property");
}
}
protoRef.used = true;
@ -127,17 +133,18 @@ export default class ExpressionParser extends LValParser {
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
parseExpression(noIn?: boolean, refShorthandDefaultPos?: Pos): N.Expression {
parseExpression(
noIn?: boolean,
refExpressionErrors?: ExpressionErrors,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
const expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
const expr = this.parseMaybeAssign(noIn, refExpressionErrors);
if (this.match(tt.comma)) {
const node = this.startNodeAt(startPos, startLoc);
node.expressions = [expr];
while (this.eat(tt.comma)) {
node.expressions.push(
this.parseMaybeAssign(noIn, refShorthandDefaultPos),
);
node.expressions.push(this.parseMaybeAssign(noIn, refExpressionErrors));
}
this.toReferencedList(node.expressions);
return this.finishNode(node, "SequenceExpression");
@ -150,7 +157,7 @@ export default class ExpressionParser extends LValParser {
parseMaybeAssign(
noIn?: ?boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
): N.Expression {
@ -170,12 +177,12 @@ export default class ExpressionParser extends LValParser {
}
}
let failOnShorthandAssign;
if (refShorthandDefaultPos) {
failOnShorthandAssign = false;
let ownExpressionErrors;
if (refExpressionErrors) {
ownExpressionErrors = false;
} else {
refShorthandDefaultPos = { start: 0 };
failOnShorthandAssign = true;
refExpressionErrors = new ExpressionErrors();
ownExpressionErrors = true;
}
if (this.match(tt.parenL) || this.match(tt.name)) {
@ -184,7 +191,7 @@ export default class ExpressionParser extends LValParser {
let left = this.parseMaybeConditional(
noIn,
refShorthandDefaultPos,
refExpressionErrors,
refNeedsArrowPos,
);
if (afterLeftParse) {
@ -201,12 +208,15 @@ export default class ExpressionParser extends LValParser {
if (operator === "||=" || operator === "&&=") {
this.expectPlugin("logicalAssignment");
}
node.left = this.match(tt.eq)
? this.toAssignable(left, undefined, "assignment expression")
: left;
if (this.match(tt.eq)) {
node.left = this.toAssignable(left, undefined, "assignment expression");
refExpressionErrors.doubleProto = -1; // reset because double __proto__ is valid in assignment expression
} else {
node.left = left;
}
if (refShorthandDefaultPos.start >= node.left.start) {
refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly
if (refExpressionErrors.shorthandAssign >= node.left.start) {
refExpressionErrors.shorthandAssign = -1; // reset because shorthand default was used correctly
}
this.checkLVal(left, undefined, undefined, "assignment expression");
@ -214,8 +224,8 @@ export default class ExpressionParser extends LValParser {
this.next();
node.right = this.parseMaybeAssign(noIn);
return this.finishNode(node, "AssignmentExpression");
} else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
} else if (ownExpressionErrors) {
this.checkExpressionErrors(refExpressionErrors, true);
}
return left;
@ -225,13 +235,13 @@ export default class ExpressionParser extends LValParser {
parseMaybeConditional(
noIn: ?boolean,
refShorthandDefaultPos: Pos,
refExpressionErrors: ExpressionErrors,
refNeedsArrowPos?: ?Pos,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt;
const expr = this.parseExprOps(noIn, refShorthandDefaultPos);
const expr = this.parseExprOps(noIn, refExpressionErrors);
if (
expr.type === "ArrowFunctionExpression" &&
@ -239,7 +249,7 @@ export default class ExpressionParser extends LValParser {
) {
return expr;
}
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
if (this.checkExpressionErrors(refExpressionErrors, false)) return expr;
return this.parseConditional(
expr,
@ -272,11 +282,14 @@ export default class ExpressionParser extends LValParser {
// Start the precedence parser.
parseExprOps(noIn: ?boolean, refShorthandDefaultPos: Pos): N.Expression {
parseExprOps(
noIn: ?boolean,
refExpressionErrors: ExpressionErrors,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt;
const expr = this.parseMaybeUnary(refShorthandDefaultPos);
const expr = this.parseMaybeUnary(refExpressionErrors);
if (
expr.type === "ArrowFunctionExpression" &&
@ -284,7 +297,7 @@ export default class ExpressionParser extends LValParser {
) {
return expr;
}
if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
if (this.checkExpressionErrors(refExpressionErrors, false)) {
return expr;
}
@ -463,7 +476,7 @@ export default class ExpressionParser extends LValParser {
// Parse unary operators, both prefix and postfix.
parseMaybeUnary(refShorthandDefaultPos: ?Pos): N.Expression {
parseMaybeUnary(refExpressionErrors: ?ExpressionErrors): N.Expression {
if (this.isContextual("await") && this.isAwaitAllowed()) {
return this.parseAwait();
} else if (this.state.type.prefix) {
@ -479,9 +492,7 @@ export default class ExpressionParser extends LValParser {
node.argument = this.parseMaybeUnary();
if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
this.checkExpressionErrors(refExpressionErrors, true);
if (update) {
this.checkLVal(node.argument, undefined, undefined, "prefix operation");
@ -506,8 +517,8 @@ export default class ExpressionParser extends LValParser {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
let expr = this.parseExprSubscripts(refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
let expr = this.parseExprSubscripts(refExpressionErrors);
if (this.checkExpressionErrors(refExpressionErrors, false)) return expr;
while (this.state.type.postfix && !this.canInsertSemicolon()) {
const node = this.startNodeAt(startPos, startLoc);
node.operator = this.state.value;
@ -522,11 +533,11 @@ export default class ExpressionParser extends LValParser {
// Parse call, dot, and `[]`-subscript expressions.
parseExprSubscripts(refShorthandDefaultPos: ?Pos): N.Expression {
parseExprSubscripts(refExpressionErrors: ?ExpressionErrors): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt;
const expr = this.parseExprAtom(refShorthandDefaultPos);
const expr = this.parseExprAtom(refExpressionErrors);
if (
expr.type === "ArrowFunctionExpression" &&
@ -535,7 +546,7 @@ export default class ExpressionParser extends LValParser {
return expr;
}
if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
if (this.checkExpressionErrors(refExpressionErrors, false)) {
return expr;
}
@ -816,7 +827,7 @@ export default class ExpressionParser extends LValParser {
elts.push(
this.parseExprListItem(
false,
possibleAsyncArrow ? { start: 0 } : undefined,
possibleAsyncArrow ? new ExpressionErrors() : undefined,
possibleAsyncArrow ? { start: 0 } : undefined,
allowPlaceholder,
),
@ -864,7 +875,7 @@ export default class ExpressionParser extends LValParser {
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression {
parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression {
// If a division operator appears in an expression position, the
// tokenizer got confused, and we force it to read a regexp instead.
if (this.state.type === tt.slash) this.readRegexp();
@ -1038,7 +1049,7 @@ export default class ExpressionParser extends LValParser {
node.elements = this.parseExprList(
tt.bracketR,
true,
refShorthandDefaultPos,
refExpressionErrors,
node,
);
if (!this.state.maybeInArrowParameters) {
@ -1056,7 +1067,7 @@ export default class ExpressionParser extends LValParser {
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = false;
const ret = this.parseObj(false, refShorthandDefaultPos);
const ret = this.parseObj(false, refExpressionErrors);
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return ret;
}
@ -1263,7 +1274,7 @@ export default class ExpressionParser extends LValParser {
const innerStartPos = this.state.start;
const innerStartLoc = this.state.startLoc;
const exprList = [];
const refShorthandDefaultPos = { start: 0 };
const refExpressionErrors = new ExpressionErrors();
const refNeedsArrowPos = { start: 0 };
let first = true;
let spreadStart;
@ -1299,7 +1310,7 @@ export default class ExpressionParser extends LValParser {
exprList.push(
this.parseMaybeAssign(
false,
refShorthandDefaultPos,
refExpressionErrors,
this.parseParenItem,
refNeedsArrowPos,
),
@ -1343,9 +1354,7 @@ export default class ExpressionParser extends LValParser {
}
if (optionalCommaStart) this.unexpected(optionalCommaStart);
if (spreadStart) this.unexpected(spreadStart);
if (refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
this.checkExpressionErrors(refExpressionErrors, true);
if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start);
this.toReferencedListDeep(exprList, /* isParenthesizedExpr */ true);
@ -1490,7 +1499,7 @@ export default class ExpressionParser extends LValParser {
parseObj<T: N.ObjectPattern | N.ObjectExpression>(
isPattern: boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
): T {
const propHash: any = Object.create(null);
let first = true;
@ -1511,9 +1520,11 @@ export default class ExpressionParser extends LValParser {
}
}
const prop = this.parseObjectMember(isPattern, refShorthandDefaultPos);
// $FlowIgnore RestElement will never be returned if !isPattern
if (!isPattern) this.checkDuplicatedProto(prop, propHash);
const prop = this.parseObjectMember(isPattern, refExpressionErrors);
if (!isPattern) {
// $FlowIgnore RestElement will never be returned if !isPattern
this.checkDuplicatedProto(prop, propHash, refExpressionErrors);
}
// $FlowIgnore
if (prop.shorthand) {
@ -1523,10 +1534,6 @@ export default class ExpressionParser extends LValParser {
node.properties.push(prop);
}
if (!this.match(tt.eq) && propHash.start !== undefined) {
this.raise(propHash.start, "Redefinition of __proto__ property");
}
return this.finishNode(
node,
isPattern ? "ObjectPattern" : "ObjectExpression",
@ -1550,7 +1557,7 @@ export default class ExpressionParser extends LValParser {
parseObjectMember(
isPattern: boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
): N.ObjectMember | N.SpreadElement | N.RestElement {
let decorators = [];
if (this.match(tt.at)) {
@ -1594,7 +1601,7 @@ export default class ExpressionParser extends LValParser {
prop.method = false;
if (isPattern || refShorthandDefaultPos) {
if (isPattern || refExpressionErrors) {
startPos = this.state.start;
startLoc = this.state.startLoc;
}
@ -1621,7 +1628,7 @@ export default class ExpressionParser extends LValParser {
isGenerator,
isAsync,
isPattern,
refShorthandDefaultPos,
refExpressionErrors,
containsEsc,
);
@ -1715,14 +1722,14 @@ export default class ExpressionParser extends LValParser {
startPos: ?number,
startLoc: ?Position,
isPattern: boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors: ?ExpressionErrors,
): ?N.ObjectProperty {
prop.shorthand = false;
if (this.eat(tt.colon)) {
prop.value = isPattern
? this.parseMaybeDefault(this.state.start, this.state.startLoc)
: this.parseMaybeAssign(false, refShorthandDefaultPos);
: this.parseMaybeAssign(false, refExpressionErrors);
return this.finishNode(prop, "ObjectProperty");
}
@ -1736,9 +1743,9 @@ export default class ExpressionParser extends LValParser {
startLoc,
prop.key.__clone(),
);
} else if (this.match(tt.eq) && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start) {
refShorthandDefaultPos.start = this.state.start;
} else if (this.match(tt.eq) && refExpressionErrors) {
if (refExpressionErrors.shorthandAssign === -1) {
refExpressionErrors.shorthandAssign = this.state.start;
}
prop.value = this.parseMaybeDefault(
startPos,
@ -1761,7 +1768,7 @@ export default class ExpressionParser extends LValParser {
isGenerator: boolean,
isAsync: boolean,
isPattern: boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
containsEsc: boolean,
): void {
const node =
@ -1777,7 +1784,7 @@ export default class ExpressionParser extends LValParser {
startPos,
startLoc,
isPattern,
refShorthandDefaultPos,
refExpressionErrors,
);
if (!node) this.unexpected();
@ -2019,7 +2026,7 @@ export default class ExpressionParser extends LValParser {
parseExprList(
close: TokenType,
allowEmpty?: boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
nodeForExtra?: ?N.Node,
): $ReadOnlyArray<?N.Expression> {
const elts = [];
@ -2043,14 +2050,14 @@ export default class ExpressionParser extends LValParser {
}
}
elts.push(this.parseExprListItem(allowEmpty, refShorthandDefaultPos));
elts.push(this.parseExprListItem(allowEmpty, refExpressionErrors));
}
return elts;
}
parseExprListItem(
allowEmpty: ?boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
refNeedsArrowPos: ?Pos,
allowPlaceholder: ?boolean,
): ?N.Expression {
@ -2061,7 +2068,7 @@ export default class ExpressionParser extends LValParser {
const spreadNodeStartPos = this.state.start;
const spreadNodeStartLoc = this.state.startLoc;
elt = this.parseParenItem(
this.parseSpread(refShorthandDefaultPos, refNeedsArrowPos),
this.parseSpread(refExpressionErrors, refNeedsArrowPos),
spreadNodeStartPos,
spreadNodeStartLoc,
);
@ -2076,7 +2083,7 @@ export default class ExpressionParser extends LValParser {
} else {
elt = this.parseMaybeAssign(
false,
refShorthandDefaultPos,
refExpressionErrors,
this.parseParenItem,
refNeedsArrowPos,
);

View File

@ -21,6 +21,7 @@ import {
} from "../util/identifier";
import { NodeUtils } from "./node";
import { type BindingTypes, BIND_NONE } from "../util/scopeflags";
import { ExpressionErrors } from "./util";
const unwrapParenthesizedExpression = (node: Node) => {
return node.type === "ParenthesizedExpression"
@ -33,13 +34,13 @@ export default class LValParser extends NodeUtils {
+parseIdentifier: (liberal?: boolean) => Identifier;
+parseMaybeAssign: (
noIn?: ?boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
) => Expression;
+parseObj: <T: ObjectPattern | ObjectExpression>(
isPattern: boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
) => T;
// Forward-declaration: defined in statement.js
+parseDecorator: () => Decorator;
@ -241,14 +242,14 @@ export default class LValParser extends NodeUtils {
// Parses spread element.
parseSpread(
refShorthandDefaultPos: ?Pos,
refExpressionErrors: ?ExpressionErrors,
refNeedsArrowPos?: ?Pos,
): SpreadElement {
const node = this.startNode();
this.next();
node.argument = this.parseMaybeAssign(
false,
refShorthandDefaultPos,
refExpressionErrors,
undefined,
refNeedsArrowPos,
);

View File

@ -27,6 +27,7 @@ import {
CLASS_ELEMENT_STATIC_SETTER,
type BindingTypes,
} from "../util/scopeflags";
import { ExpressionErrors } from "./util";
const loopLabel = { kind: "loop" },
switchLabel = { kind: "switch" };
@ -533,8 +534,8 @@ export default class StatementParser extends ExpressionParser {
return this.parseFor(node, init);
}
const refShorthandDefaultPos = { start: 0 };
const init = this.parseExpression(true, refShorthandDefaultPos);
const refExpressionErrors = new ExpressionErrors();
const init = this.parseExpression(true, refExpressionErrors);
if (this.match(tt._in) || this.isContextual("of")) {
const description = this.isContextual("of")
? "for-of statement"
@ -542,8 +543,8 @@ export default class StatementParser extends ExpressionParser {
this.toAssignable(init, undefined, description);
this.checkLVal(init, undefined, undefined, description);
return this.parseForIn(node, init, awaitAt);
} else if (refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
} else {
this.checkExpressionErrors(refExpressionErrors, true);
}
if (awaitAt > -1) {
this.unexpected(awaitAt);

View File

@ -268,4 +268,35 @@ export default class UtilParser extends Tokenizer {
throw error;
}
}
checkExpressionErrors(
refExpressionErrors: ?ExpressionErrors,
andThrow: boolean,
) {
if (!refExpressionErrors) return false;
const { shorthandAssign, doubleProto } = refExpressionErrors;
if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0;
if (shorthandAssign >= 0) {
this.unexpected(shorthandAssign);
}
if (doubleProto >= 0) {
this.raise(doubleProto, "Redefinition of __proto__ property");
}
}
}
/**
* The ExpressionErrors is a context struct used to track
* - **shorthandAssign**: track initializer `=` position when parsing ambiguous
* patterns. When we are sure the parsed pattern is a RHS, which means it is
* not a pattern, we will throw on this position on invalid assign syntax,
* otherwise it will be reset to -1
* - **doubleProto**: track the duplicate `__proto__` key position when parsing
* ambiguous object patterns. When we are sure the parsed pattern is a RHS,
* which means it is an object literal, we will throw on this position for
* __proto__ redefinition, otherwise it will be reset to -1
*/
export class ExpressionErrors {
shorthandAssign = -1;
doubleProto = -1;
}

View File

@ -4,8 +4,9 @@
import { types as tt, TokenType } from "../tokenizer/types";
import type Parser from "../parser";
import type { ExpressionErrors } from "../parser/util";
import * as N from "../types";
import type { Pos, Position } from "../util/location";
import type { Position } from "../util/location";
import { type BindingTypes, BIND_NONE } from "../util/scopeflags";
function isSimpleProperty(node: N.Node): boolean {
@ -148,7 +149,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
checkDuplicatedProto(
prop: N.ObjectMember | N.SpreadElement,
protoRef: { used: boolean, start?: number },
protoRef: { used: boolean },
refExpressionErrors: ?ExpressionErrors,
): void {
if (
prop.type === "SpreadElement" ||
@ -166,8 +168,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (name === "__proto__" && prop.kind === "init") {
// Store the first redefinition's position
if (protoRef.used && !protoRef.start) {
protoRef.start = key.start;
if (protoRef.used) {
if (refExpressionErrors && refExpressionErrors.doubleProto === -1) {
refExpressionErrors.doubleProto = key.start;
} else {
this.raise(key.start, "Redefinition of __proto__ property");
}
}
protoRef.used = true;
@ -234,7 +240,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
classBody.body.push(method);
}
parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression {
parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression {
switch (this.state.type) {
case tt.num:
case tt.string:
@ -256,7 +262,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.estreeParseLiteral(false);
default:
return super.parseExprAtom(refShorthandDefaultPos);
return super.parseExprAtom(refExpressionErrors);
}
}
@ -340,14 +346,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
startPos: ?number,
startLoc: ?Position,
isPattern: boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors: ?ExpressionErrors,
): ?N.ObjectProperty {
const node: N.EstreeProperty = (super.parseObjectProperty(
prop,
startPos,
startLoc,
isPattern,
refShorthandDefaultPos,
refExpressionErrors,
): any);
if (node) {

View File

@ -21,6 +21,7 @@ import {
SCOPE_ARROW,
SCOPE_OTHER,
} from "../util/scopeflags";
import type { ExpressionErrors } from "../parser/util";
const reservedTypes = new Set([
"_",
@ -2283,7 +2284,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
isGenerator: boolean,
isAsync: boolean,
isPattern: boolean,
refShorthandDefaultPos: ?Pos,
refExpressionErrors: ?ExpressionErrors,
containsEsc: boolean,
): void {
if ((prop: $FlowFixMe).variance) {
@ -2306,7 +2307,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
isGenerator,
isAsync,
isPattern,
refShorthandDefaultPos,
refExpressionErrors,
containsEsc,
);
@ -2559,7 +2560,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// 3. This is neither. Just call the super method
parseMaybeAssign(
noIn?: ?boolean,
refShorthandDefaultPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
): N.Expression {
@ -2577,7 +2578,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
() =>
super.parseMaybeAssign(
noIn,
refShorthandDefaultPos,
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
@ -2611,7 +2612,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
() =>
super.parseMaybeAssign(
noIn,
refShorthandDefaultPos,
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
@ -2659,7 +2660,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return super.parseMaybeAssign(
noIn,
refShorthandDefaultPos,
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
);

View File

@ -4,11 +4,12 @@ import * as charCodes from "charcodes";
import XHTMLEntities from "./xhtml";
import type Parser from "../../parser";
import type { ExpressionErrors } from "../../parser/util";
import { TokenType, types as tt } from "../../tokenizer/types";
import { TokContext, types as tc } from "../../tokenizer/context";
import * as N from "../../types";
import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
import type { Pos, Position } from "../../util/location";
import type { Position } from "../../util/location";
import { isNewLine } from "../../util/whitespace";
const HEX_NUMBER = /^[\da-fA-F]+$/;
@ -510,7 +511,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Overrides
// ==================================
parseExprAtom(refShortHandDefaultPos: ?Pos): N.Expression {
parseExprAtom(refExpressionErrors: ?ExpressionErrors): N.Expression {
if (this.match(tt.jsxText)) {
return this.parseLiteral(this.state.value, "JSXText");
} else if (this.match(tt.jsxTagStart)) {
@ -524,7 +525,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.finishToken(tt.jsxTagStart);
return this.jsxParseElement();
} else {
return super.parseExprAtom(refShortHandDefaultPos);
return super.parseExprAtom(refExpressionErrors);
}
}

View File

@ -25,6 +25,7 @@ import {
} from "../../util/scopeflags";
import TypeScriptScopeHandler from "./scope";
import * as charCodes from "charcodes";
import type { ExpressionErrors } from "../../parser/util";
type TsModifier =
| "readonly"
@ -2340,11 +2341,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// Handle type assertions
parseMaybeUnary(refShorthandDefaultPos?: ?Pos): N.Expression {
parseMaybeUnary(refExpressionErrors?: ?ExpressionErrors): N.Expression {
if (!this.hasPlugin("jsx") && this.isRelational("<")) {
return this.tsParseTypeAssertion();
} else {
return super.parseMaybeUnary(refShorthandDefaultPos);
return super.parseMaybeUnary(refExpressionErrors);
}
}

View File

@ -0,0 +1 @@
([{ __proto__: x, __proto__: y }] = [{}]);

View File

@ -0,0 +1,241 @@
{
"type": "File",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"program": {
"type": "Program",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"expression": {
"type": "AssignmentExpression",
"start": 1,
"end": 40,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 40
}
},
"operator": "=",
"left": {
"type": "ArrayPattern",
"start": 1,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 33
}
},
"elements": [
{
"type": "ObjectPattern",
"start": 2,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 2
},
"end": {
"line": 1,
"column": 32
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 4,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 16
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 4,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 15,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 15
},
"end": {
"line": 1,
"column": 16
},
"identifierName": "x"
},
"name": "x"
}
},
{
"type": "ObjectProperty",
"start": 18,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 30
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 18,
"end": 27,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 27
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 29,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 29
},
"end": {
"line": 1,
"column": 30
},
"identifierName": "y"
},
"name": "y"
}
}
]
}
]
},
"right": {
"type": "ArrayExpression",
"start": 36,
"end": 40,
"loc": {
"start": {
"line": 1,
"column": 36
},
"end": {
"line": 1,
"column": 40
}
},
"elements": [
{
"type": "ObjectExpression",
"start": 37,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 37
},
"end": {
"line": 1,
"column": 39
}
},
"properties": []
}
]
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
({ __proto__: x, __proto__: y }) => {};

View File

@ -0,0 +1,208 @@
{
"type": "File",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 39
}
},
"program": {
"type": "Program",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 39
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 39
}
},
"expression": {
"type": "ArrowFunctionExpression",
"start": 0,
"end": 38,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 38
}
},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "ObjectPattern",
"start": 1,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 31
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 3,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 3
},
"end": {
"line": 1,
"column": 15
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 3,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 3
},
"end": {
"line": 1,
"column": 12
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "x"
},
"name": "x"
}
},
{
"type": "ObjectProperty",
"start": 17,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 29
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 17,
"end": 26,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 26
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 28,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 28
},
"end": {
"line": 1,
"column": 29
},
"identifierName": "y"
},
"name": "y"
}
}
]
}
],
"body": {
"type": "BlockStatement",
"start": 36,
"end": 38,
"loc": {
"start": {
"line": 1,
"column": 36
},
"end": {
"line": 1,
"column": 38
}
},
"body": [],
"directives": []
}
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
new {__proto__: Number, __proto__: Number}.__proto__;

View File

@ -0,0 +1,223 @@
{
"type": "File",
"start": 0,
"end": 53,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 53
}
},
"errors": [
"SyntaxError: Redefinition of __proto__ property (1:24)"
],
"program": {
"type": "Program",
"start": 0,
"end": 53,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 53
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 53,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 53
}
},
"expression": {
"type": "NewExpression",
"start": 0,
"end": 52,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 52
}
},
"callee": {
"type": "MemberExpression",
"start": 4,
"end": 52,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 52
}
},
"object": {
"type": "ObjectExpression",
"start": 4,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 42
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 5,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 22
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 5,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 14
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 16,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 22
},
"identifierName": "Number"
},
"name": "Number"
}
},
{
"type": "ObjectProperty",
"start": 24,
"end": 41,
"loc": {
"start": {
"line": 1,
"column": 24
},
"end": {
"line": 1,
"column": 41
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 24,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 24
},
"end": {
"line": 1,
"column": 33
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 35,
"end": 41,
"loc": {
"start": {
"line": 1,
"column": 35
},
"end": {
"line": 1,
"column": 41
},
"identifierName": "Number"
},
"name": "Number"
}
}
]
},
"property": {
"type": "Identifier",
"start": 43,
"end": 52,
"loc": {
"start": {
"line": 1,
"column": 43
},
"end": {
"line": 1,
"column": 52
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false
},
"arguments": []
}
}
],
"directives": []
}
}