Skip to content

Commit 138970f

Browse files
author
jbondc
committed
Fixes #2632 (invoking methods on numbers)
1 parent 25ecada commit 138970f

File tree

7 files changed

+93
-26
lines changed

7 files changed

+93
-26
lines changed

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,5 +569,6 @@ namespace ts {
569569
decorators_can_only_be_used_in_a_ts_file: { code: 8017, category: DiagnosticCategory.Error, key: "'decorators' can only be used in a .ts file." },
570570
Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." },
571571
class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." },
572+
Numeric_literal_0_cannot_be_followed_by_an_expression: { code: 9004, category: DiagnosticCategory.Error, key: "Numeric literal {0} cannot be followed by an expression." },
572573
};
573574
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,5 +2268,9 @@
22682268
"'class' expressions are not currently supported.": {
22692269
"category": "Error",
22702270
"code": 9003
2271+
},
2272+
"Numeric literal {0} cannot be followed by an expression.": {
2273+
"category": "Error",
2274+
"code": 9004
22712275
}
22722276
}

src/compiler/parser.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ namespace ts {
100100
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
101101
visitNode(cbNode, (<ArrowFunction>node).equalsGreaterThanToken) ||
102102
visitNode(cbNode, (<FunctionLikeDeclaration>node).body);
103+
case SyntaxKind.NumericLiteral:
104+
return visitNode(cbNode, (<LiteralExpression>node).invalidDotExpression);
103105
case SyntaxKind.TypeReference:
104106
return visitNode(cbNode, (<TypeReferenceNode>node).typeName) ||
105107
visitNodes(cbNodes, (<TypeReferenceNode>node).typeArguments);
@@ -1830,20 +1832,37 @@ namespace ts {
18301832
}
18311833

18321834
let tokenPos = scanner.getTokenPos();
1835+
let nextCharCode: number;
1836+
18331837
nextToken();
18341838
finishNode(node);
18351839

1836-
// Octal literals are not allowed in strict mode or ES5
1837-
// Note that theoretically the following condition would hold true literals like 009,
1838-
// which is not octal.But because of how the scanner separates the tokens, we would
1839-
// never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
1840-
// We also do not need to check for negatives because any prefix operator would be part of a
1841-
// parent unary expression.
1842-
if (node.kind === SyntaxKind.NumericLiteral
1843-
&& sourceText.charCodeAt(tokenPos) === CharacterCodes._0
1844-
&& isOctalDigit(sourceText.charCodeAt(tokenPos + 1))) {
1845-
1846-
node.flags |= NodeFlags.OctalLiteral;
1840+
if (node.kind === SyntaxKind.NumericLiteral) {
1841+
// Octal literals are not allowed in strict mode or ES5
1842+
// Note that theoretically the following condition would hold true literals like 009,
1843+
// which is not octal.But because of how the scanner separates the tokens, we would
1844+
// never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
1845+
// We also do not need to check for negatives because any prefix operator would be part of a
1846+
// parent unary expression.
1847+
if (sourceText.charCodeAt(tokenPos) === CharacterCodes._0 && isOctalDigit(sourceText.charCodeAt(tokenPos + 1))) {
1848+
node.flags |= NodeFlags.OctalLiteral;
1849+
}
1850+
else if (token === SyntaxKind.DotToken) {
1851+
// Issue #2632 Keep space for 3 .toString()
1852+
if (isWhiteSpace(sourceText.charCodeAt(node.end))) {
1853+
node.end++;
1854+
scanner.setTextPos(node.end + 1);
1855+
}
1856+
}
1857+
else if (token === SyntaxKind.Identifier && sourceText.charCodeAt(node.end-1) === CharacterCodes.dot) {
1858+
nextCharCode = sourceText.charCodeAt(node.end);
1859+
if (!isWhiteSpace(nextCharCode) && !isLineBreak(nextCharCode)) {
1860+
// Eat up an invalid expression following '1.' e.g. 1.something()
1861+
node.invalidDotExpression = parseLeftHandSideExpressionOrHigher();
1862+
parseErrorAtPosition(node.end, node.invalidDotExpression.end - node.end, Diagnostics.Numeric_literal_0_cannot_be_followed_by_an_expression, "'" + sourceText.substring(tokenPos, node.end) + "'");
1863+
node.end = node.invalidDotExpression.end;
1864+
}
1865+
}
18471866
}
18481867

18491868
return node;

src/compiler/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ namespace ts {
737737
text: string;
738738
isUnterminated?: boolean;
739739
hasExtendedUnicodeEscape?: boolean;
740+
invalidDotExpression?: LeftHandSideExpression; // 1.toString() we attach the node but never emit it
740741
}
741742

742743
export interface TemplateExpression extends PrimaryExpression {
@@ -1881,7 +1882,7 @@ namespace ts {
18811882
CarriageReturnLineFeed = 0,
18821883
LineFeed = 1,
18831884
}
1884-
1885+
18851886
export interface LineAndCharacter {
18861887
line: number;
18871888
/*
Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
tests/cases/compiler/numLit.ts(3,3): error TS1005: ';' expected.
2-
tests/cases/compiler/numLit.ts(3,3): error TS2304: Cannot find name 'toString'.
1+
tests/cases/compiler/numLit.ts(3,3): error TS9004: Numeric literal '1.' cannot be followed by an expression.
2+
tests/cases/compiler/numLit.ts(9,15): error TS9004: Numeric literal '2.' cannot be followed by an expression.
33

44

55
==== tests/cases/compiler/numLit.ts (2 errors) ====
66
1..toString();
77
1.0.toString();
8-
1.toString();
9-
~~~~~~~~
10-
!!! error TS1005: ';' expected.
11-
~~~~~~~~
12-
!!! error TS2304: Cannot find name 'toString'.
13-
1.+2.0 + 3. ;
8+
1.toString(); // error: Numeric literal '1.' cannot be followed by an expression.
9+
~~~~~~~~~~
10+
!!! error TS9004: Numeric literal '1.' cannot be followed by an expression.
11+
1.+2.0 + 3. ;
12+
13+
// Preserve whitespace where important for JS compatibility
14+
var i: number = 1;
15+
var test1 = i.toString();
16+
var test2 = 2.toString(); // error: Numeric literal '2.' cannot be followed by an expression.
17+
~~~~~~~~~~
18+
!!! error TS9004: Numeric literal '2.' cannot be followed by an expression.
19+
var test3 = 3 .toString(); // preserve whitepace
20+
var test4 = 3.['toString']();
21+
var test5 = 3
22+
.toString(); // preserve whitepace
23+
var test6 = new Number(4).toString();
24+
var test7 = 3. + 3.

tests/baselines/reference/numLit.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
//// [numLit.ts]
22
1..toString();
33
1.0.toString();
4-
1.toString();
5-
1.+2.0 + 3. ;
4+
1.toString(); // error: Numeric literal '1.' cannot be followed by an expression.
5+
1.+2.0 + 3. ;
6+
7+
// Preserve whitespace where important for JS compatibility
8+
var i: number = 1;
9+
var test1 = i.toString();
10+
var test2 = 2.toString(); // error: Numeric literal '2.' cannot be followed by an expression.
11+
var test3 = 3 .toString(); // preserve whitepace
12+
var test4 = 3.['toString']();
13+
var test5 = 3
14+
.toString(); // preserve whitepace
15+
var test6 = new Number(4).toString();
16+
var test7 = 3. + 3.
617

718
//// [numLit.js]
819
1..toString();
920
1.0.toString();
10-
1.;
11-
toString();
21+
1.toString(); // error: Numeric literal '1.' cannot be followed by an expression.
1222
1. + 2.0 + 3.;
23+
// Preserve whitespace where important for JS compatibility
24+
var i = 1;
25+
var test1 = i.toString();
26+
var test2 = 2.toString(); // error: Numeric literal '2.' cannot be followed by an expression.
27+
var test3 = 3 .toString(); // preserve whitepace
28+
var test4 = 3.['toString']();
29+
var test5 = 3
30+
.toString(); // preserve whitepace
31+
var test6 = new Number(4).toString();
32+
var test7 = 3. + 3.;

tests/cases/compiler/numLit.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
1..toString();
22
1.0.toString();
3-
1.toString();
4-
1.+2.0 + 3. ;
3+
1.toString(); // error: Numeric literal '1.' cannot be followed by an expression.
4+
1.+2.0 + 3. ;
5+
6+
// Preserve whitespace where important for JS compatibility
7+
var i: number = 1;
8+
var test1 = i.toString();
9+
var test2 = 2.toString(); // error: Numeric literal '2.' cannot be followed by an expression.
10+
var test3 = 3 .toString(); // preserve whitepace
11+
var test4 = 3.['toString']();
12+
var test5 = 3
13+
.toString(); // preserve whitepace
14+
var test6 = new Number(4).toString();
15+
var test7 = 3. + 3.

0 commit comments

Comments
 (0)