From 4e83303fd91f98dce71acba4da29404b5eb41f98 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 6 Sep 2019 16:09:43 +0200 Subject: [PATCH 1/3] Fix type missing diagnostic on function signatures --- src/parser.ts | 21 +++++++++++++++++++-- tests/parser/function-type.ts | 4 ++++ tests/parser/function-type.ts.fixture.ts | 5 +++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/parser/function-type.ts create mode 100644 tests/parser/function-type.ts.fixture.ts diff --git a/src/parser.ts b/src/parser.ts index df000ba564..a2697d0692 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -459,7 +459,7 @@ export class Parser extends DiagnosticEmitter { if (!suppressErrors) { this.error( DiagnosticCode._0_expected, - tn.range(tn.pos), "}" + tn.range(tn.pos), ")" ); } return null; @@ -684,11 +684,28 @@ export class Parser extends DiagnosticEmitter { if (!parameters) parameters = [ param ]; else parameters.push(param); } else { + if (!isSignature) { + let next = tn.peek(); + if (next == Token.COMMA || next == Token.CLOSEPAREN) { + isSignature = true; + tn.discard(state); + } + } if (isSignature) { + let param = new ParameterNode(); + param.parameterKind = kind; + param.name = name; + param.type = Node.createOmittedType(tn.range().atEnd); + if (!parameters) parameters = [ param ]; + else parameters.push(param); this.error( DiagnosticCode.Type_expected, - tn.range() + param.type.range ); // recoverable + } else { + tn.reset(state); + this.tryParseSignatureIsSignature = false; + return null; } } } else { diff --git a/tests/parser/function-type.ts b/tests/parser/function-type.ts new file mode 100644 index 0000000000..39f741eaf4 --- /dev/null +++ b/tests/parser/function-type.ts @@ -0,0 +1,4 @@ +var a: () => void; +var b: (a: i32, b: i32) => void; +var c: (a: i32, b: i32) => (a: i32, b: i32) => void; +var d: (a) => void; // TS1110 diff --git a/tests/parser/function-type.ts.fixture.ts b/tests/parser/function-type.ts.fixture.ts new file mode 100644 index 0000000000..a0d1e6892d --- /dev/null +++ b/tests/parser/function-type.ts.fixture.ts @@ -0,0 +1,5 @@ +var a: () => void; +var b: (a: i32, b: i32) => void; +var c: (a: i32, b: i32) => (a: i32, b: i32) => void; +var d: (a) => void; +// ERROR 1110: "Type expected." in function-type.ts:4:9 From e1d80abec0f6d17b71a941906669062be627cf77 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 6 Sep 2019 16:59:59 +0200 Subject: [PATCH 2/3] ')' is still ambiguous --- src/parser.ts | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index a2697d0692..c1861423ed 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -620,6 +620,8 @@ export class Parser extends DiagnosticEmitter { var parameters: ParameterNode[] | null = null; var thisType: NamedTypeNode | null = null; var isSignature: bool = false; + var firstParamNameNoType: IdentifierExpression | null = null; + var firstParamKind: ParameterKind = ParameterKind.DEFAULT; if (tn.skip(Token.CLOSEPAREN)) { isSignature = true; @@ -685,8 +687,7 @@ export class Parser extends DiagnosticEmitter { else parameters.push(param); } else { if (!isSignature) { - let next = tn.peek(); - if (next == Token.COMMA || next == Token.CLOSEPAREN) { + if (tn.peek() == Token.COMMA) { isSignature = true; tn.discard(state); } @@ -702,10 +703,12 @@ export class Parser extends DiagnosticEmitter { DiagnosticCode.Type_expected, param.type.range ); // recoverable - } else { - tn.reset(state); - this.tryParseSignatureIsSignature = false; - return null; + } else if (!parameters) { + // on '(' Identifier ^',' we don't yet know whether this is a + // parenthesized or a function type, hence we have to delay the + // respective diagnostic until we know for sure. + firstParamNameNoType = name; + firstParamKind = kind; } } } else { @@ -737,8 +740,22 @@ export class Parser extends DiagnosticEmitter { var returnType: TypeNode | null; if (tn.skip(Token.EQUALS_GREATERTHAN)) { - isSignature = true; - tn.discard(state); + if (!isSignature) { + isSignature = true; + tn.discard(state); + if (firstParamNameNoType) { // now we know + this.error( + DiagnosticCode.Type_expected, + firstParamNameNoType.range.atEnd + ); // recoverable + let param = new ParameterNode(); + param.parameterKind = firstParamKind; + param.name = firstParamNameNoType; + param.type = Node.createOmittedType(firstParamNameNoType.range.atEnd); + if (!parameters) parameters = [ param ]; + else parameters.push(param); + } + } returnType = this.parseType(tn); if (!returnType) { this.tryParseSignatureIsSignature = isSignature; From 22326f3d1afa340905c58813c6e386b3c62af097 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 6 Sep 2019 17:11:21 +0200 Subject: [PATCH 3/3] unify --- src/parser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index c1861423ed..b3e2387270 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -744,16 +744,16 @@ export class Parser extends DiagnosticEmitter { isSignature = true; tn.discard(state); if (firstParamNameNoType) { // now we know - this.error( - DiagnosticCode.Type_expected, - firstParamNameNoType.range.atEnd - ); // recoverable let param = new ParameterNode(); param.parameterKind = firstParamKind; param.name = firstParamNameNoType; param.type = Node.createOmittedType(firstParamNameNoType.range.atEnd); if (!parameters) parameters = [ param ]; else parameters.push(param); + this.error( + DiagnosticCode.Type_expected, + param.type.range + ); // recoverable } } returnType = this.parseType(tn);