Merge pull request #12352 from Microsoft/untyped_module_symbol

Use a symbol for untyped modules to distinguish from unknownSymbol
This commit is contained in:
Andy
2017-03-01 10:38:47 -08:00
committed by GitHub
7 changed files with 72 additions and 10 deletions

View File

@@ -197,6 +197,8 @@ namespace ts {
const evolvingArrayTypes: EvolvingArrayType[] = [];
const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown");
const untypedModuleSymbol = createSymbol(SymbolFlags.ValueModule, "<untyped>");
untypedModuleSymbol.exports = createMap<Symbol>();
const resolvingSymbol = createSymbol(0, "__resolving__");
const anyType = createIntrinsicType(TypeFlags.Any, "any");
@@ -1227,7 +1229,7 @@ namespace ts {
if (moduleSymbol) {
let exportDefaultSymbol: Symbol;
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
if (isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) {
exportDefaultSymbol = moduleSymbol;
}
else {
@@ -1307,7 +1309,7 @@ namespace ts {
if (targetSymbol) {
const name = specifier.propertyName || specifier.name;
if (name.text) {
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
if (isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) {
return moduleSymbol;
}
@@ -1560,15 +1562,19 @@ namespace ts {
if (isForAugmentation) {
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
return undefined;
}
else if (compilerOptions.noImplicitAny && moduleNotFoundError) {
error(errorNode,
Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type,
moduleReference,
resolvedModule.resolvedFileName);
return undefined;
}
// Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first.
return undefined;
// Unlike a failed import, an untyped module produces a dummy symbol.
// This is checked for by `isUntypedOrShorthandAmbientModuleSymbol`.
// This must be different than `unknownSymbol` because `getBaseConstructorTypeOfClass` won't fail for `unknownSymbol`.
return untypedModuleSymbol;
}
if (moduleNotFoundError) {
@@ -3753,7 +3759,7 @@ namespace ts {
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.type) {
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
if (symbol.flags & SymbolFlags.Module && isUntypedOrShorthandAmbientModuleSymbol(symbol)) {
links.type = anyType;
}
else {
@@ -21316,7 +21322,7 @@ namespace ts {
function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean {
let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression);
if (!moduleSymbol || isShorthandAmbientModuleSymbol(moduleSymbol)) {
if (!moduleSymbol || isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) {
// If the module is not found or is shorthand, assume that it may export a value.
return true;
}

View File

@@ -435,8 +435,8 @@ namespace ts {
}
/** Given a symbol for a module, checks that it is either an untyped import or a shorthand ambient module. */
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
export function isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
return !moduleSymbol.declarations || isShorthandAmbientModule(moduleSymbol.valueDeclaration);
}
function isShorthandAmbientModule(node: Node): boolean {

View File

@@ -133,7 +133,7 @@ namespace ts.FindAllReferences {
return { symbol };
}
if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
if (ts.isUntypedOrShorthandAmbientModuleSymbol(aliasedSymbol)) {
return { symbol, shorthandModuleSymbol: aliasedSymbol };
}

View File

@@ -0,0 +1,14 @@
/a.ts(2,17): error TS2507: Type 'any' is not a constructor function type.
==== /a.ts (1 errors) ====
import Foo from "foo";
class A extends Foo { }
~~~
!!! error TS2507: Type 'any' is not a constructor function type.
==== /node_modules/foo/index.js (0 errors) ====
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
This file is not read.

View File

@@ -0,0 +1,33 @@
//// [tests/cases/compiler/extendsUntypedModule.ts] ////
//// [index.js]
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
This file is not read.
//// [a.ts]
import Foo from "foo";
class A extends Foo { }
//// [a.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var foo_1 = require("foo");
var A = (function (_super) {
__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(foo_1["default"]));

View File

@@ -0,0 +1,9 @@
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
// @noImplicitReferences: true
// @Filename: /node_modules/foo/index.js
This file is not read.
// @Filename: /a.ts
import Foo from "foo";
class A extends Foo { }

View File

@@ -12,7 +12,7 @@ verify.numberOfErrorsInCurrentFile(0);
goTo.marker("fooModule");
verify.goToDefinitionIs([]);
verify.quickInfoIs("");
verify.quickInfoIs("module <untyped>");
verify.noReferences();
goTo.marker("foo");