Skip to content

Commit 7b6846d

Browse files
authored
Merge master to release-2.0 on 08/19 (#10444)
* Add test case for #8229 * Do not report errors during contextual typecheck Fixes #8229 * Handle the scenario when let [a=undefined]=[] * Don't allow `.ts` to appear in an import * Add specific error message for unwanted '.ts' extension * Allow `await` in a simple unary expression * More tests * Forbid `await await` * Allow `await await` * Improve error message * Don't allow ".d.ts" extension in an import either. * Rename 'find' functions * Move supportedTypescriptExtensionsWithDtsFirst next to supportedTypeScriptExtensions and rename * Fix comment * Treat special property access symbol differently ... when retriving documentation * Fix tests * Update shim version to be 2.1 (#10424) * Check return code paths on getters (#10102) * Check return paths on getters * Remove TODO comment * Remove extraneous arguments from harness's runBaseline (#10419) * Remove extraneous arguments from runBaseline * Address comments from @yuit * Remove needless call to basename * Refactor baseliners out of compiler runner (#10440) * CR feedback * fix broken tests * Pass in baselineOpts into types baselines so that RWC baselines can be written to internal folder (#10443)
1 parent 78f2593 commit 7b6846d

File tree

57 files changed

+1181
-569
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1181
-569
lines changed

Jakefile.js

Lines changed: 164 additions & 153 deletions
Large diffs are not rendered by default.

src/compiler/checker.ts

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ namespace ts {
10241024
}
10251025

10261026
function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration {
1027-
return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
1027+
return findMap(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
10281028
}
10291029

10301030
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
@@ -1361,7 +1361,14 @@ namespace ts {
13611361

13621362
if (moduleNotFoundError) {
13631363
// report errors only if it was requested
1364-
error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
1364+
const tsExtension = tryExtractTypeScriptExtension(moduleName);
1365+
if (tsExtension) {
1366+
const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead;
1367+
error(moduleReferenceLiteral, diag, tsExtension, removeExtension(moduleName, tsExtension));
1368+
}
1369+
else {
1370+
error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
1371+
}
13651372
}
13661373
return undefined;
13671374
}
@@ -3083,7 +3090,7 @@ namespace ts {
30833090

30843091
// If the declaration specifies a binding pattern, use the type implied by the binding pattern
30853092
if (isBindingPattern(declaration.name)) {
3086-
return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ false);
3093+
return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true);
30873094
}
30883095

30893096
// No type specified and nothing can be inferred
@@ -3093,23 +3100,21 @@ namespace ts {
30933100
// Return the type implied by a binding pattern element. This is the type of the initializer of the element if
30943101
// one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
30953102
// pattern. Otherwise, it is the type any.
3096-
function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean): Type {
3103+
function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type {
30973104
if (element.initializer) {
3098-
const type = checkExpressionCached(element.initializer);
3099-
reportErrorsFromWidening(element, type);
3100-
return getWidenedType(type);
3105+
return checkExpressionCached(element.initializer);
31013106
}
31023107
if (isBindingPattern(element.name)) {
3103-
return getTypeFromBindingPattern(<BindingPattern>element.name, includePatternInType);
3108+
return getTypeFromBindingPattern(<BindingPattern>element.name, includePatternInType, reportErrors);
31043109
}
3105-
if (compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) {
3110+
if (reportErrors && compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) {
31063111
reportImplicitAnyError(element, anyType);
31073112
}
31083113
return anyType;
31093114
}
31103115

31113116
// Return the type implied by an object binding pattern
3112-
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
3117+
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
31133118
const members = createMap<Symbol>();
31143119
let hasComputedProperties = false;
31153120
forEach(pattern.elements, e => {
@@ -3123,7 +3128,7 @@ namespace ts {
31233128
const text = getTextOfPropertyName(name);
31243129
const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
31253130
const symbol = <TransientSymbol>createSymbol(flags, text);
3126-
symbol.type = getTypeFromBindingElement(e, includePatternInType);
3131+
symbol.type = getTypeFromBindingElement(e, includePatternInType, reportErrors);
31273132
symbol.bindingElement = e;
31283133
members[symbol.name] = symbol;
31293134
});
@@ -3138,13 +3143,13 @@ namespace ts {
31383143
}
31393144

31403145
// Return the type implied by an array binding pattern
3141-
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
3146+
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
31423147
const elements = pattern.elements;
31433148
if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) {
31443149
return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType;
31453150
}
31463151
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
3147-
const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType));
3152+
const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
31483153
if (includePatternInType) {
31493154
const result = createNewTupleType(elementTypes);
31503155
result.pattern = pattern;
@@ -3160,10 +3165,10 @@ namespace ts {
31603165
// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
31613166
// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
31623167
// the parameter.
3163-
function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean): Type {
3168+
function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type {
31643169
return pattern.kind === SyntaxKind.ObjectBindingPattern
3165-
? getTypeFromObjectBindingPattern(pattern, includePatternInType)
3166-
: getTypeFromArrayBindingPattern(pattern, includePatternInType);
3170+
? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors)
3171+
: getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors);
31673172
}
31683173

31693174
// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
@@ -9414,7 +9419,7 @@ namespace ts {
94149419
}
94159420
}
94169421
if (isBindingPattern(declaration.name)) {
9417-
return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ true);
9422+
return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false);
94189423
}
94199424
if (isBindingPattern(declaration.parent)) {
94209425
const parentDeclaration = declaration.parent.parent;
@@ -14121,12 +14126,7 @@ namespace ts {
1412114126
checkSignatureDeclaration(node);
1412214127
if (node.kind === SyntaxKind.GetAccessor) {
1412314128
if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) {
14124-
if (node.flags & NodeFlags.HasExplicitReturn) {
14125-
if (compilerOptions.noImplicitReturns) {
14126-
error(node.name, Diagnostics.Not_all_code_paths_return_a_value);
14127-
}
14128-
}
14129-
else {
14129+
if (!(node.flags & NodeFlags.HasExplicitReturn)) {
1413014130
error(node.name, Diagnostics.A_get_accessor_must_return_a_value);
1413114131
}
1413214132
}
@@ -14156,7 +14156,10 @@ namespace ts {
1415614156
checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
1415714157
}
1415814158
}
14159-
getTypeOfAccessors(getSymbolOfNode(node));
14159+
const returnType = getTypeOfAccessors(getSymbolOfNode(node));
14160+
if (node.kind === SyntaxKind.GetAccessor) {
14161+
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType);
14162+
}
1416014163
}
1416114164
if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) {
1416214165
checkSourceElement(node.body);

src/compiler/core.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,22 @@ namespace ts {
113113
return undefined;
114114
}
115115

116-
/** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */
117-
export function find<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
116+
/** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */
117+
export function find<T>(array: T[], predicate: (element: T, index: number) => boolean): T | undefined {
118+
for (let i = 0, len = array.length; i < len; i++) {
119+
const value = array[i];
120+
if (predicate(value, i)) {
121+
return value;
122+
}
123+
}
124+
return undefined;
125+
}
126+
127+
/**
128+
* Returns the first truthy result of `callback`, or else fails.
129+
* This is like `forEach`, but never returns undefined.
130+
*/
131+
export function findMap<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
118132
for (let i = 0, len = array.length; i < len; i++) {
119133
const result = callback(array[i], i);
120134
if (result) {
@@ -1315,6 +1329,8 @@ namespace ts {
13151329
* List of supported extensions in order of file resolution precedence.
13161330
*/
13171331
export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"];
1332+
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
1333+
export const supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"];
13181334
export const supportedJavascriptExtensions = [".js", ".jsx"];
13191335
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
13201336

@@ -1397,8 +1413,12 @@ namespace ts {
13971413
return path;
13981414
}
13991415

1400-
export function tryRemoveExtension(path: string, extension: string): string {
1401-
return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined;
1416+
export function tryRemoveExtension(path: string, extension: string): string | undefined {
1417+
return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined;
1418+
}
1419+
1420+
export function removeExtension(path: string, extension: string): string {
1421+
return path.substring(0, path.length - extension.length);
14021422
}
14031423

14041424
export function isJsxOrTsxExtension(ext: string): boolean {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,6 +1951,10 @@
19511951
"category": "Error",
19521952
"code": 2690
19531953
},
1954+
"An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.": {
1955+
"category": "Error",
1956+
"code": 2691
1957+
},
19541958
"Import declaration '{0}' is using private name '{1}'.": {
19551959
"category": "Error",
19561960
"code": 4000

src/compiler/parser.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3417,6 +3417,7 @@ namespace ts {
34173417
* 6) - UnaryExpression[?yield]
34183418
* 7) ~ UnaryExpression[?yield]
34193419
* 8) ! UnaryExpression[?yield]
3420+
* 9) [+Await] await UnaryExpression[?yield]
34203421
*/
34213422
function parseSimpleUnaryExpression(): UnaryExpression {
34223423
switch (token()) {
@@ -3431,6 +3432,8 @@ namespace ts {
34313432
return parseTypeOfExpression();
34323433
case SyntaxKind.VoidKeyword:
34333434
return parseVoidExpression();
3435+
case SyntaxKind.AwaitKeyword:
3436+
return parseAwaitExpression();
34343437
case SyntaxKind.LessThanToken:
34353438
// This is modified UnaryExpression grammar in TypeScript
34363439
// UnaryExpression (modified):

src/compiler/program.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -662,51 +662,52 @@ namespace ts {
662662
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
663663
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
664664
*/
665-
function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
666-
// First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts"
667-
const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
668-
if (resolvedByAddingOrKeepingExtension) {
669-
return resolvedByAddingOrKeepingExtension;
665+
function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
666+
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
667+
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
668+
if (resolvedByAddingExtension) {
669+
return resolvedByAddingExtension;
670670
}
671-
// Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
671+
672+
// If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
673+
// e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
672674
if (hasJavaScriptFileExtension(candidate)) {
673675
const extensionless = removeFileExtension(candidate);
674676
if (state.traceEnabled) {
675677
const extension = candidate.substring(extensionless.length);
676678
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
677679
}
678-
return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
680+
return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
679681
}
680682
}
681683

682-
function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
684+
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
685+
function tryAddingExtensions(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
683686
if (!onlyRecordFailures) {
684687
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
685688
const directory = getDirectoryPath(candidate);
686689
if (directory) {
687690
onlyRecordFailures = !directoryProbablyExists(directory, state.host);
688691
}
689692
}
690-
return forEach(extensions, tryLoad);
693+
return forEach(extensions, ext =>
694+
!(state.skipTsx && isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state));
695+
}
691696

692-
function tryLoad(ext: string): string {
693-
if (state.skipTsx && isJsxOrTsxExtension(ext)) {
694-
return undefined;
695-
}
696-
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
697-
if (!onlyRecordFailures && state.host.fileExists(fileName)) {
698-
if (state.traceEnabled) {
699-
trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName);
700-
}
701-
return fileName;
697+
/** Return the file if it exists. */
698+
function tryFile(fileName: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
699+
if (!onlyRecordFailures && state.host.fileExists(fileName)) {
700+
if (state.traceEnabled) {
701+
trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName);
702702
}
703-
else {
704-
if (state.traceEnabled) {
705-
trace(state.host, Diagnostics.File_0_does_not_exist, fileName);
706-
}
707-
failedLookupLocation.push(fileName);
708-
return undefined;
703+
return fileName;
704+
}
705+
else {
706+
if (state.traceEnabled) {
707+
trace(state.host, Diagnostics.File_0_does_not_exist, fileName);
709708
}
709+
failedLookupLocation.push(fileName);
710+
return undefined;
710711
}
711712
}
712713

@@ -719,7 +720,9 @@ namespace ts {
719720
}
720721
const typesFile = tryReadTypesSection(packageJsonPath, candidate, state);
721722
if (typesFile) {
722-
const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state);
723+
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host);
724+
// The package.json "typings" property must specify the file with extension, so just try that exact filename.
725+
const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state);
723726
if (result) {
724727
return result;
725728
}

src/compiler/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2694,6 +2694,11 @@ namespace ts {
26942694
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
26952695
}
26962696

2697+
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
2698+
export function tryExtractTypeScriptExtension(fileName: string): string | undefined {
2699+
return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
2700+
}
2701+
26972702
/**
26982703
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
26992704
* representing the UTF-8 encoding of the character, and return the expanded char code list.

0 commit comments

Comments
 (0)