Skip to content

Commit

Permalink
Make strict
Browse files Browse the repository at this point in the history
  • Loading branch information
jakebailey committed Apr 20, 2022
1 parent 2398762 commit f5ecb51
Show file tree
Hide file tree
Showing 21 changed files with 116 additions and 67 deletions.
56 changes: 24 additions & 32 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4452,7 +4452,7 @@ namespace ts {
}

function tryParseParenthesizedArrowFunctionExpression(disallowReturnTypeInArrowFunction: boolean): Expression | undefined {
const triState = isParenthesizedArrowFunctionExpression();
const triState = isParenthesizedArrowFunctionExpression(disallowReturnTypeInArrowFunction);
if (triState === Tristate.False) {
// It's definitely not a parenthesized arrow function expression.
return undefined;
Expand All @@ -4463,17 +4463,17 @@ namespace ts {
// it out, but don't allow any ambiguity, and return 'undefined' if this could be an
// expression instead.
return triState === Tristate.True ?
parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*disallowReturnTypeInArrowFunction*/ false) :
parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, disallowReturnTypeInArrowFunction) :
tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(disallowReturnTypeInArrowFunction));
}

// True -> We definitely expect a parenthesized arrow function here.
// False -> There *cannot* be a parenthesized arrow function here.
// Unknown -> There *might* be a parenthesized arrow function here.
// Speculatively look ahead to be sure, and rollback if not.
function isParenthesizedArrowFunctionExpression(): Tristate {
function isParenthesizedArrowFunctionExpression(disallowReturnTypeInArrowFunction: boolean): Tristate {
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) {
return lookAhead(isParenthesizedArrowFunctionExpressionWorker);
return lookAhead(() => isParenthesizedArrowFunctionExpressionWorker(disallowReturnTypeInArrowFunction));
}

if (token() === SyntaxKind.EqualsGreaterThanToken) {
Expand All @@ -4486,7 +4486,7 @@ namespace ts {
return Tristate.False;
}

function isParenthesizedArrowFunctionExpressionWorker() {
function isParenthesizedArrowFunctionExpressionWorker(disallowReturnTypeInArrowFunction: boolean) {
if (token() === SyntaxKind.AsyncKeyword) {
nextToken();
if (scanner.hasPrecedingLineBreak()) {
Expand All @@ -4508,8 +4508,13 @@ namespace ts {
// but this is probably what the user intended.
const third = nextToken();
switch (third) {
case SyntaxKind.EqualsGreaterThanToken:
case SyntaxKind.ColonToken:
if (disallowReturnTypeInArrowFunction) {
// "a ? () : ..."
return Tristate.False;
}
return Tristate.True;
case SyntaxKind.EqualsGreaterThanToken:
case SyntaxKind.OpenBraceToken:
return Tristate.True;
default:
Expand Down Expand Up @@ -4695,7 +4700,19 @@ namespace ts {
}
}

const hasReturnColon = token() === SyntaxKind.ColonToken;
// Given:
// x ? y => ({ y }) : z => ({ z })
// We try to parse the body of the first arrow function by looking at:
// ({ y }) : z => ({ z })
// This is a valid arrow function with "z" as the return type.
//
// But, if we're in the true side of a conditional expression, this colon
// terminates the expression, so we cannot allow a return type, even if we aren't
// certain whether or not the preceding text was parsed as a parameter list.
if (disallowReturnTypeInArrowFunction && token() === SyntaxKind.ColonToken) {
return undefined;
}

const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) {
return undefined;
Expand Down Expand Up @@ -4731,31 +4748,6 @@ namespace ts {
? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), disallowReturnTypeInArrowFunction)
: parseIdentifier();

// Given:
// x ? y => ({ y }) : z => ({ z })
// We try to parse the body of the first arrow function by looking at:
// ({ y }) : z => ({ z })
// This is a valid arrow function with "z" as the return type.
//
// But, if we're in the true side of a conditional expression, this colon
// terminates the expression, so we cannot allow a return type if we aren't
// certain whether or not the preceding text was parsed as a parameter list.
//
// For example,
// a() ? (b: number, c?: string): void => d() : e
// is determined by isParenthesizedArrowFunctionExpression to unambiguously
// be an arrow expression, so we allow a return type.
if (disallowReturnTypeInArrowFunction && hasReturnColon) {
// However, if the arrow function we were able to parse is followed by another colon
// as in:
// a ? (x): string => x : null
// Then allow the arrow function, and treat the second colon as terminating
// the conditional expression.
if (token() !== SyntaxKind.ColonToken) {
return undefined;
}
}

const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body);
return withJSDoc(finishNode(node, pos), hasJSDoc);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,1): error TS2304: Cannot find name 'a'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,11): error TS2304: Cannot find name 'c'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,6): error TS2304: Cannot find name 'b'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,17): error TS2304: Cannot find name 'd'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,20): error TS1005: ';' expected.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts(1,27): error TS2304: Cannot find name 'f'.


==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts (4 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts (5 errors) ====
a ? (b) : c => (d) : e => f
~
!!! error TS2304: Cannot find name 'a'.
~
!!! error TS2304: Cannot find name 'c'.
~
!!! error TS2304: Cannot find name 'b'.
~
!!! error TS2304: Cannot find name 'd'.
~
!!! error TS1005: ';' expected.
~
!!! error TS2304: Cannot find name 'f'.

3 changes: 2 additions & 1 deletion tests/baselines/reference/parserArrowFunctionExpression10.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ a ? (b) : c => (d) : e => f


//// [parserArrowFunctionExpression10.js]
a ? function (b) { return (d); } : function (e) { return f; };
a ? (b) : function (c) { return (d); };
(function (e) { return f; });
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts ===
a ? (b) : c => (d) : e => f
>b : Symbol(b, Decl(parserArrowFunctionExpression10.ts, 0, 5))
>c : Symbol(c)
>c : Symbol(c, Decl(parserArrowFunctionExpression10.ts, 0, 9))
>e : Symbol(e, Decl(parserArrowFunctionExpression10.ts, 0, 20))

Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression10.ts ===
a ? (b) : c => (d) : e => f
>a ? (b) : c => (d) : e => f : (b: any) => c
>a ? (b) : c => (d) : any
>a : any
>(b) : c => (d) : (b: any) => c
>(b) : any
>b : any
>c => (d) : (c: any) => any
>c : any
>(d) : any
>d : any
>e => f : (e: any) => any
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts(1,1): error TS2304: Cannot find name 'a'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts(1,11): error TS2304: Cannot find name 'a'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts(1,18): error TS1109: Expression expected.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts(1,19): error TS1005: ';' expected.


==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts (2 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts (4 errors) ====
a ? () => a() : (): any => null;
~
!!! error TS2304: Cannot find name 'a'.
~
!!! error TS2304: Cannot find name 'a'.
~
!!! error TS1109: Expression expected.
~
!!! error TS1005: ';' expected.

3 changes: 2 additions & 1 deletion tests/baselines/reference/parserArrowFunctionExpression13.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ a ? () => a() : (): any => null;


//// [parserArrowFunctionExpression13.js]
a ? function () { return a(); } : function () { return null; };
a ? function () { return a(); } : ();
(function (any) { return null; });
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts ===
a ? () => a() : (): any => null;
No type information for this code.
No type information for this code.
>any : Symbol(any, Decl(parserArrowFunctionExpression13.ts, 0, 19))
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression13.ts ===
a ? () => a() : (): any => null;
>a ? () => a() : (): any => null : () => any
>a ? () => a() : () : any
>a : any
>() => a() : () => any
>a() : any
>a : any
>(): any => null : () => any
>() : any
> : any
>any => null : (any: any) => any
>any : any
>null : null

Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,1): error TS2304: Cannot find name 'a'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,30): error TS1109: Expression expected.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,37): error TS1109: Expression expected.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,40): error TS2304: Cannot find name 'd'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,44): error TS1005: ';' expected.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts(1,46): error TS2304: Cannot find name 'e'.


==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts (3 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts (6 errors) ====
a() ? (b: number, c?: string): void => d() : e;
~
!!! error TS2304: Cannot find name 'a'.
~
!!! error TS1109: Expression expected.
~~
!!! error TS1109: Expression expected.
~
!!! error TS2304: Cannot find name 'd'.
~
!!! error TS1005: ';' expected.
~
!!! error TS2304: Cannot find name 'e'.

4 changes: 3 additions & 1 deletion tests/baselines/reference/parserArrowFunctionExpression14.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ a() ? (b: number, c?: string): void => d() : e;


//// [parserArrowFunctionExpression14.js]
a() ? function (b, c) { return d(); } : e;
a() ? : void ;
d();
e;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts ===
a() ? (b: number, c?: string): void => d() : e;
>b : Symbol(b, Decl(parserArrowFunctionExpression14.ts, 0, 7))
>c : Symbol(c, Decl(parserArrowFunctionExpression14.ts, 0, 17))

No type information for this code.
No type information for this code.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression14.ts ===
a() ? (b: number, c?: string): void => d() : e;
>a() ? (b: number, c?: string): void => d() : e : any
>a() ? (b: number, c?: string): void : any
>a() : any
>a : any
>(b: number, c?: string): void => d() : (b: number, c?: string) => void
>b : number
>c : string
> : any
>void : undefined
> : any
>d() : any
>d : any
>e : any
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts(1,10): error TS2304: Cannot find name 'param'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts(1,28): error TS2304: Cannot find name 'param'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts(1,34): error TS1005: ';' expected.


==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts (3 errors) ====
false ? (param): string => param : null
~~~~~
!!! error TS2304: Cannot find name 'param'.
~~~~~
!!! error TS2304: Cannot find name 'param'.
~
!!! error TS1005: ';' expected.

3 changes: 2 additions & 1 deletion tests/baselines/reference/parserArrowFunctionExpression15.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ false ? (param): string => param : null


//// [parserArrowFunctionExpression15.js]
false ? function (param) { return param; } : null;
false ? (param) : function (string) { return param; };
null;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts ===
false ? (param): string => param : null
>param : Symbol(param, Decl(parserArrowFunctionExpression15.ts, 0, 9))
>param : Symbol(param, Decl(parserArrowFunctionExpression15.ts, 0, 9))
>string : Symbol(string, Decl(parserArrowFunctionExpression15.ts, 0, 16))

Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression15.ts ===
false ? (param): string => param : null
>false ? (param): string => param : null : (param: any) => string
>false ? (param): string => param : any
>false : false
>(param): string => param : (param: any) => string
>(param) : any
>param : any
>string => param : (string: any) => any
>string : any
>param : any
>null : null

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts(1,17): error TS2304: Cannot find name 'param'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts(1,35): error TS2304: Cannot find name 'param'.
tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts(1,48): error TS1005: ';' expected.


==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts (3 errors) ====
true ? false ? (param): string => param : null : null
~~~~~
!!! error TS2304: Cannot find name 'param'.
~~~~~
!!! error TS2304: Cannot find name 'param'.
~
!!! error TS1005: ';' expected.

3 changes: 2 additions & 1 deletion tests/baselines/reference/parserArrowFunctionExpression16.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ true ? false ? (param): string => param : null : null


//// [parserArrowFunctionExpression16.js]
true ? false ? function (param) { return param; } : null : null;
true ? false ? (param) : function (string) { return param; } : null;
null;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts ===
true ? false ? (param): string => param : null : null
>param : Symbol(param, Decl(parserArrowFunctionExpression16.ts, 0, 16))
>param : Symbol(param, Decl(parserArrowFunctionExpression16.ts, 0, 16))
>string : Symbol(string, Decl(parserArrowFunctionExpression16.ts, 0, 23))

Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression16.ts ===
true ? false ? (param): string => param : null : null
>true ? false ? (param): string => param : null : null : (param: any) => string
>true ? false ? (param): string => param : null : any
>true : true
>false ? (param): string => param : null : (param: any) => string
>false ? (param): string => param : any
>false : false
>(param): string => param : (param: any) => string
>(param) : any
>param : any
>string => param : (string: any) => any
>string : any
>param : any
>null : null
>null : null
Expand Down

0 comments on commit f5ecb51

Please sign in to comment.