Skip to content

Commit

Permalink
Fix shadowed import detection with simple arrow function params (#366)
Browse files Browse the repository at this point in the history
We had code to mark parameters as function-scoped declaration identfiers, but
this wasn't working for arrow functions and async arrow functions that omit the
parens around their only parameter, so shadowed imports weren't being respected
properly. In addition to fixing, I consolidated the identifier role assignment
into one place, which will be useful for a future change.
  • Loading branch information
alangpierce authored Dec 24, 2018
1 parent 76f5b8d commit e476734
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 11 deletions.
16 changes: 12 additions & 4 deletions src/parser/traverser/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ import {ContextualKeyword} from "../tokenizer/keywords";
import {Scope} from "../tokenizer/state";
import {TokenType, TokenType as tt} from "../tokenizer/types";
import {getNextContextId, isFlowEnabled, isJSXEnabled, isTypeScriptEnabled, state} from "./base";
import {parseMaybeDefault, parseRest, parseSpread} from "./lval";
import {
markPriorBindingIdentifier,
parseBindingIdentifier,
parseMaybeDefault,
parseRest,
parseSpread,
} from "./lval";
import {
parseBlock,
parseClass,
Expand Down Expand Up @@ -446,14 +452,16 @@ export function parseExprAtom(): boolean {
contextualKeyword === ContextualKeyword._async &&
match(tt.name)
) {
parseIdentifier();
parseBindingIdentifier(false);
expect(tt.arrow);
// let foo = bar => {};
// let foo = async bar => {};
parseArrowExpression(functionStart, startTokenIndex);
return true;
}

if (canBeArrow && !canInsertSemicolon() && eat(tt.arrow)) {
if (canBeArrow && !canInsertSemicolon() && match(tt.arrow)) {
markPriorBindingIdentifier(false);
expect(tt.arrow);
parseArrowExpression(functionStart, startTokenIndex);
return true;
}
Expand Down
14 changes: 9 additions & 5 deletions src/parser/traverser/lval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ export function parseRest(isBlockScope: boolean): void {
parseBindingAtom(isBlockScope);
}

export function parseBindingIdentifier(): void {
export function parseBindingIdentifier(isBlockScope: boolean): void {
parseIdentifier();
markPriorBindingIdentifier(isBlockScope);
}

export function markPriorBindingIdentifier(isBlockScope: boolean): void {
state.tokens[state.tokens.length - 1].identifierRole = isBlockScope
? IdentifierRole.BlockScopedDeclaration
: IdentifierRole.FunctionScopedDeclaration;
}

// Parses lvalue (assignable) atom.
Expand All @@ -46,10 +53,7 @@ export function parseBindingAtom(isBlockScope: boolean): void {
case tt._yield:
case tt.name: {
state.type = tt.name;
parseBindingIdentifier();
state.tokens[state.tokens.length - 1].identifierRole = isBlockScope
? IdentifierRole.BlockScopedDeclaration
: IdentifierRole.FunctionScopedDeclaration;
parseBindingIdentifier(isBlockScope);
return;
}

Expand Down
3 changes: 1 addition & 2 deletions src/parser/traverser/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,7 @@ export function parseFunction(
if (!isStatement) {
nameScopeStartTokenIndex = state.tokens.length;
}
parseBindingIdentifier();
state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.FunctionScopedDeclaration;
parseBindingIdentifier(false);
}

const startTokenIndex = state.tokens.length;
Expand Down
36 changes: 36 additions & 0 deletions test/imports-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1125,4 +1125,40 @@ module.exports = exports.default;
{transforms: ["imports", "typescript"]},
);
});

it("properly handles shadowing for simple arrow functions", () => {
assertResult(
`
import a from 'a';
const f = a => {
a();
};
`,
`"use strict";${IMPORT_DEFAULT_PREFIX}
const f = a => {
a();
};
`,
{transforms: ["imports", "typescript"]},
);
});

it("properly handles shadowing for simple async arrow functions", () => {
assertResult(
`
import a from 'a';
const f = async a => {
a();
};
`,
`"use strict";${IMPORT_DEFAULT_PREFIX}
const f = async a => {
a();
};
`,
{transforms: ["imports", "typescript"]},
);
});
});

0 comments on commit e476734

Please sign in to comment.