Skip to content

Commit 2dbf621

Browse files
committed
merge with origin/master, add trace message with type of 'typings' field is not 'string'
2 parents bb9498f + 31f56fd commit 2dbf621

23 files changed

Lines changed: 308 additions & 54 deletions

src/compiler/checker.ts

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6148,14 +6148,25 @@ namespace ts {
61486148
function inferFromTypes(source: Type, target: Type) {
61496149
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
61506150
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
6151-
// Source and target are both unions or both intersections. To improve the quality of
6152-
// inferences we first reduce the types by removing constituents that are identically
6153-
// matched by a constituent in the other type. For example, when inferring from
6154-
// 'string | string[]' to 'string | T', we reduce the types to 'string[]' and 'T'.
6155-
const reducedSource = reduceUnionOrIntersectionType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target);
6156-
const reducedTarget = reduceUnionOrIntersectionType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source);
6157-
source = reducedSource;
6158-
target = reducedTarget;
6151+
// Source and target are both unions or both intersections. First, find each
6152+
// target constituent type that has an identically matching source constituent
6153+
// type, and for each such target constituent type infer from the type to itself.
6154+
// When inferring from a type to itself we effectively find all type parameter
6155+
// occurrences within that type and infer themselves as their type arguments.
6156+
let matchingTypes: Type[];
6157+
for (const t of (<UnionOrIntersectionType>target).types) {
6158+
if (typeIdenticalToSomeType(t, (<UnionOrIntersectionType>source).types)) {
6159+
(matchingTypes || (matchingTypes = [])).push(t);
6160+
inferFromTypes(t, t);
6161+
}
6162+
}
6163+
// Next, to improve the quality of inferences, reduce the source and target types by
6164+
// removing the identically matched constituents. For example, when inferring from
6165+
// 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'.
6166+
if (matchingTypes) {
6167+
source = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>source, matchingTypes);
6168+
target = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>target, matchingTypes);
6169+
}
61596170
}
61606171
if (target.flags & TypeFlags.TypeParameter) {
61616172
// If target is a type parameter, make an inference, unless the source type contains
@@ -6317,39 +6328,27 @@ namespace ts {
63176328
}
63186329
}
63196330

6320-
function typeIdenticalToSomeType(source: Type, target: UnionOrIntersectionType): boolean {
6321-
for (const t of target.types) {
6322-
if (isTypeIdenticalTo(source, t)) {
6331+
function typeIdenticalToSomeType(type: Type, types: Type[]): boolean {
6332+
for (const t of types) {
6333+
if (isTypeIdenticalTo(t, type)) {
63236334
return true;
63246335
}
63256336
}
63266337
return false;
63276338
}
63286339

63296340
/**
6330-
* Return the reduced form of the source type. This type is computed by by removing all source
6331-
* constituents that have an identical match in the target type.
6341+
* Return a new union or intersection type computed by removing a given set of types
6342+
* from a given union or intersection type.
63326343
*/
6333-
function reduceUnionOrIntersectionType(source: UnionOrIntersectionType, target: UnionOrIntersectionType) {
6334-
let sourceTypes = source.types;
6335-
let sourceIndex = 0;
6336-
let modified = false;
6337-
while (sourceIndex < sourceTypes.length) {
6338-
if (typeIdenticalToSomeType(sourceTypes[sourceIndex], target)) {
6339-
if (!modified) {
6340-
sourceTypes = sourceTypes.slice(0);
6341-
modified = true;
6342-
}
6343-
sourceTypes.splice(sourceIndex, 1);
6344-
}
6345-
else {
6346-
sourceIndex++;
6344+
function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) {
6345+
const reducedTypes: Type[] = [];
6346+
for (const t of type.types) {
6347+
if (!typeIdenticalToSomeType(t, typesToRemove)) {
6348+
reducedTypes.push(t);
63476349
}
63486350
}
6349-
if (modified) {
6350-
return source.flags & TypeFlags.Union ? getUnionType(sourceTypes, /*noSubtypeReduction*/ true) : getIntersectionType(sourceTypes);
6351-
}
6352-
return source;
6351+
return type.flags & TypeFlags.Union ? getUnionType(reducedTypes, /*noSubtypeReduction*/ true) : getIntersectionType(reducedTypes);
63536352
}
63546353

63556354
function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
@@ -15493,6 +15492,11 @@ namespace ts {
1549315492
let flags = 0;
1549415493
for (const modifier of node.modifiers) {
1549515494
switch (modifier.kind) {
15495+
case SyntaxKind.ConstKeyword:
15496+
if (node.kind !== SyntaxKind.EnumDeclaration && node.parent.kind === SyntaxKind.ClassDeclaration) {
15497+
return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword));
15498+
}
15499+
break;
1549615500
case SyntaxKind.PublicKeyword:
1549715501
case SyntaxKind.ProtectedKeyword:
1549815502
case SyntaxKind.PrivateKeyword:

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,10 @@
791791
"category": "Error",
792792
"code": 1247
793793
},
794-
794+
"A class member cannot have the '{0}' keyword.": {
795+
"category": "Error",
796+
"code": 1248
797+
},
795798
"'with' statements are not allowed in an async function block.": {
796799
"category": "Error",
797800
"code": 1300
@@ -2507,6 +2510,10 @@
25072510
"Checking if '{0}' is the longest matching prefix for '{1}' - '{2}'.": {
25082511
"category": "Message",
25092512
"code": 6112
2513+
},
2514+
"Expected type of 'typings' field in 'package.json' to be 'string', got '{0}'.": {
2515+
"category": "Message",
2516+
"code": 6113
25102517
},
25112518
"Variable '{0}' implicitly has an '{1}' type.": {
25122519
"category": "Error",

src/compiler/parser.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,14 @@ namespace ts {
11341134
return token === t && tryParse(nextTokenCanFollowModifier);
11351135
}
11361136

1137+
function nextTokenIsOnSameLineAndCanFollowModifier() {
1138+
nextToken();
1139+
if (scanner.hasPrecedingLineBreak()) {
1140+
return false;
1141+
}
1142+
return canFollowModifier();
1143+
}
1144+
11371145
function nextTokenCanFollowModifier() {
11381146
if (token === SyntaxKind.ConstKeyword) {
11391147
// 'const' is only a modifier if followed by 'enum'.
@@ -1154,11 +1162,7 @@ namespace ts {
11541162
return canFollowModifier();
11551163
}
11561164

1157-
nextToken();
1158-
if (scanner.hasPrecedingLineBreak()) {
1159-
return false;
1160-
}
1161-
return canFollowModifier();
1165+
return nextTokenIsOnSameLineAndCanFollowModifier();
11621166
}
11631167

11641168
function parseAnyContextualModifier(): boolean {
@@ -4923,15 +4927,31 @@ namespace ts {
49234927
return decorators;
49244928
}
49254929

4926-
function parseModifiers(): ModifiersArray {
4930+
/*
4931+
* There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member.
4932+
* In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect
4933+
* and turns it into a standalone declaration), then it is better to parse it and report an error later.
4934+
*
4935+
* In such situations, 'permitInvalidConstAsModifier' should be set to true.
4936+
*/
4937+
function parseModifiers(permitInvalidConstAsModifier?: boolean): ModifiersArray {
49274938
let flags = 0;
49284939
let modifiers: ModifiersArray;
49294940
while (true) {
49304941
const modifierStart = scanner.getStartPos();
49314942
const modifierKind = token;
49324943

4933-
if (!parseAnyContextualModifier()) {
4934-
break;
4944+
if (token === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) {
4945+
// We need to ensure that any subsequent modifiers appear on the same line
4946+
// so that when 'const' is a standalone declaration, we don't issue an error.
4947+
if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {
4948+
break;
4949+
}
4950+
}
4951+
else {
4952+
if (!parseAnyContextualModifier()) {
4953+
break;
4954+
}
49354955
}
49364956

49374957
if (!modifiers) {
@@ -4976,7 +4996,7 @@ namespace ts {
49764996

49774997
const fullStart = getNodePos();
49784998
const decorators = parseDecorators();
4979-
const modifiers = parseModifiers();
4999+
const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true);
49805000

49815001
const accessor = tryParseAccessorDeclaration(fullStart, decorators, modifiers);
49825002
if (accessor) {

src/compiler/program.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,18 @@ namespace ts {
429429
}
430430

431431
if (jsonContent.typings) {
432-
const typingsFile = normalizePath(combinePaths(candidate, jsonContent.typings));
433-
if (traceEnabled) {
434-
trace(host, Diagnostics.package_json_has_typings_field_0_that_references_1, jsonContent.typings, typingsFile);
432+
if (typeof jsonContent.typings === "string") {
433+
const typingsFile = normalizePath(combinePaths(candidate, jsonContent.typings));
434+
if (traceEnabled) {
435+
trace(host, Diagnostics.package_json_has_typings_field_0_that_references_1, jsonContent.typings, typingsFile);
436+
}
437+
const result = loadModuleFromFile(extensions, typingsFile, failedLookupLocation, host, traceEnabled);
438+
if (result) {
439+
return result;
440+
}
435441
}
436-
const result = loadModuleFromFile(extensions, typingsFile , failedLookupLocation, host, traceEnabled);
437-
if (result) {
438-
return result;
442+
else if (traceEnabled) {
443+
trace(host, Diagnostics.Expected_type_of_typings_field_in_package_json_to_be_string_got_0, typeof jsonContent.typings);
439444
}
440445
}
441446
else {
@@ -446,7 +451,7 @@ namespace ts {
446451
}
447452
else {
448453
if (traceEnabled) {
449-
trace(host, Diagnostics.package_json_does_not_have_typings_field);
454+
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
450455
}
451456
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
452457
failedLookupLocation.push(packageJsonPath);

src/lib/es6.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,7 @@ declare namespace Reflect {
12241224
function isExtensible(target: any): boolean;
12251225
function ownKeys(target: any): Array<PropertyKey>;
12261226
function preventExtensions(target: any): boolean;
1227-
function set(target: any, propertyKey: PropertyKey, value: any, receiver? :any): boolean;
1227+
function set(target: any, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
12281228
function setPrototypeOf(target: any, proto: any): boolean;
12291229
}
12301230

@@ -1272,7 +1272,16 @@ interface PromiseConstructor {
12721272
* @param values An array of Promises.
12731273
* @returns A new Promise.
12741274
*/
1275-
all<T>(values: Iterable<T | PromiseLike<T>>): Promise<T[]>;
1275+
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
1276+
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
1277+
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
1278+
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
1279+
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
1280+
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
1281+
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
1282+
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
1283+
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
1284+
all<TAll>(values: Iterable<TAll | PromiseLike<TAll>>): Promise<TAll[]>;
12761285

12771286
/**
12781287
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved

src/services/formatting/smartIndenter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ namespace ts.formatting {
461461
case SyntaxKind.ParenthesizedType:
462462
case SyntaxKind.TaggedTemplateExpression:
463463
case SyntaxKind.AwaitExpression:
464+
case SyntaxKind.NamedImports:
464465
return true;
465466
}
466467
return false;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/compiler/ClassDeclaration26.ts(2,22): error TS1005: ';' expected.
2+
tests/cases/compiler/ClassDeclaration26.ts(4,5): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected.
3+
tests/cases/compiler/ClassDeclaration26.ts(4,20): error TS1005: '=' expected.
4+
tests/cases/compiler/ClassDeclaration26.ts(4,23): error TS1005: '=>' expected.
5+
tests/cases/compiler/ClassDeclaration26.ts(5,1): error TS1128: Declaration or statement expected.
6+
7+
8+
==== tests/cases/compiler/ClassDeclaration26.ts (5 errors) ====
9+
class C {
10+
public const var export foo = 10;
11+
~~~~~~
12+
!!! error TS1005: ';' expected.
13+
14+
var constructor() { }
15+
~~~
16+
!!! error TS1068: Unexpected token. A constructor, method, accessor, or property was expected.
17+
~
18+
!!! error TS1005: '=' expected.
19+
~
20+
!!! error TS1005: '=>' expected.
21+
}
22+
~
23+
!!! error TS1128: Declaration or statement expected.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//// [ClassDeclaration26.ts]
2+
class C {
3+
public const var export foo = 10;
4+
5+
var constructor() { }
6+
}
7+
8+
//// [ClassDeclaration26.js]
9+
var C = (function () {
10+
function C() {
11+
this.foo = 10;
12+
}
13+
return C;
14+
})();
15+
var constructor = function () { };
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/compiler/ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts(2,3): error TS1248: A class member cannot have the 'const' keyword.
2+
3+
4+
==== tests/cases/compiler/ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts (1 errors) ====
5+
class AtomicNumbers {
6+
static const H = 1;
7+
~~~~~~~~~~~~~~~~~~~
8+
!!! error TS1248: A class member cannot have the 'const' keyword.
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts]
2+
class AtomicNumbers {
3+
static const H = 1;
4+
}
5+
6+
//// [ClassDeclarationWithInvalidConstOnPropertyDeclaration.js]
7+
var AtomicNumbers = (function () {
8+
function AtomicNumbers() {
9+
}
10+
AtomicNumbers.H = 1;
11+
return AtomicNumbers;
12+
})();

0 commit comments

Comments
 (0)