@@ -5104,10 +5104,14 @@ namespace ts {
5104
5104
}
5105
5105
}
5106
5106
5107
- // Returns true if the interface given by the symbol is free of "this" references. Specifically, the result is
5108
- // true if the interface itself contains no references to "this" in its body, if all base types are interfaces,
5109
- // and if none of the base interfaces have a "this" type.
5110
- function isIndependentInterface(symbol: Symbol): boolean {
5107
+ /**
5108
+ * Returns true if the interface given by the symbol is free of "this" references.
5109
+ *
5110
+ * Specifically, the result is true if the interface itself contains no references
5111
+ * to "this" in its body, if all base types are interfaces,
5112
+ * and if none of the base interfaces have a "this" type.
5113
+ */
5114
+ function isThislessInterface(symbol: Symbol): boolean {
5111
5115
for (const declaration of symbol.declarations) {
5112
5116
if (declaration.kind === SyntaxKind.InterfaceDeclaration) {
5113
5117
if (declaration.flags & NodeFlags.ContainsThis) {
@@ -5141,7 +5145,7 @@ namespace ts {
5141
5145
// property types inferred from initializers and method return types inferred from return statements are very hard
5142
5146
// to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of
5143
5147
// "this" references.
5144
- if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isIndependentInterface (symbol)) {
5148
+ if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface (symbol)) {
5145
5149
type.objectFlags |= ObjectFlags.Reference;
5146
5150
type.typeParameters = concatenate(outerTypeParameters, localTypeParameters);
5147
5151
type.outerTypeParameters = outerTypeParameters;
@@ -5323,22 +5327,12 @@ namespace ts {
5323
5327
return undefined;
5324
5328
}
5325
5329
5326
- // A type reference is considered independent if each type argument is considered independent.
5327
- function isIndependentTypeReference(node: TypeReferenceNode): boolean {
5328
- if (node.typeArguments) {
5329
- for (const typeNode of node.typeArguments) {
5330
- if (!isIndependentType(typeNode)) {
5331
- return false;
5332
- }
5333
- }
5334
- }
5335
- return true;
5336
- }
5337
-
5338
- // A type is considered independent if it the any, string, number, boolean, symbol, or void keyword, a string
5339
- // literal type, an array with an element type that is considered independent, or a type reference that is
5340
- // considered independent.
5341
- function isIndependentType(node: TypeNode): boolean {
5330
+ /**
5331
+ * A type is free of this references if it's the any, string, number, boolean, symbol, or void keyword, a string
5332
+ * literal type, an array with an element type that is free of this references, or a type reference that is
5333
+ * free of this references.
5334
+ */
5335
+ function isThislessType(node: TypeNode): boolean {
5342
5336
switch (node.kind) {
5343
5337
case SyntaxKind.AnyKeyword:
5344
5338
case SyntaxKind.StringKeyword:
@@ -5353,54 +5347,58 @@ namespace ts {
5353
5347
case SyntaxKind.LiteralType:
5354
5348
return true;
5355
5349
case SyntaxKind.ArrayType:
5356
- return isIndependentType ((<ArrayTypeNode>node).elementType);
5350
+ return isThislessType ((<ArrayTypeNode>node).elementType);
5357
5351
case SyntaxKind.TypeReference:
5358
- return isIndependentTypeReference(< TypeReferenceNode> node);
5352
+ return !(node as TypeReferenceNode).typeArguments || ( node as TypeReferenceNode).typeArguments.every(isThislessType );
5359
5353
}
5360
5354
return false;
5361
5355
}
5362
5356
5363
- // A variable-like declaration is considered independent (free of this references) if it has a type annotation
5364
- // that specifies an independent type, or if it has no type annotation and no initializer (and thus of type any).
5365
- function isIndependentVariableLikeDeclaration(node: VariableLikeDeclaration): boolean {
5357
+ /** A type parameter is thisless if its contraint is thisless, or if it has no constraint. */
5358
+ function isThislessTypeParameter(node: TypeParameterDeclaration) {
5359
+ return !node.constraint || isThislessType(node.constraint);
5360
+ }
5361
+
5362
+ /**
5363
+ * A variable-like declaration is free of this references if it has a type annotation
5364
+ * that is thisless, or if it has no type annotation and no initializer (and is thus of type any).
5365
+ */
5366
+ function isThislessVariableLikeDeclaration(node: VariableLikeDeclaration): boolean {
5366
5367
const typeNode = getEffectiveTypeAnnotationNode(node);
5367
- return typeNode ? isIndependentType (typeNode) : !node.initializer;
5368
+ return typeNode ? isThislessType (typeNode) : !node.initializer;
5368
5369
}
5369
5370
5370
- // A function-like declaration is considered independent (free of this references) if it has a return type
5371
- // annotation that is considered independent and if each parameter is considered independent.
5372
- function isIndependentFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
5373
- if (node.kind !== SyntaxKind.Constructor) {
5374
- const typeNode = getEffectiveReturnTypeNode(node);
5375
- if (!typeNode || !isIndependentType(typeNode)) {
5376
- return false;
5377
- }
5378
- }
5379
- for (const parameter of node.parameters) {
5380
- if (!isIndependentVariableLikeDeclaration(parameter)) {
5381
- return false;
5382
- }
5383
- }
5384
- return true;
5371
+ /**
5372
+ * A function-like declaration is considered free of `this` references if it has a return type
5373
+ * annotation that is free of this references and if each parameter is thisless and if
5374
+ * each type parameter (if present) is thisless.
5375
+ */
5376
+ function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
5377
+ const returnType = getEffectiveReturnTypeNode(node);
5378
+ return (node.kind === SyntaxKind.Constructor || (returnType && isThislessType(returnType))) &&
5379
+ node.parameters.every(isThislessVariableLikeDeclaration) &&
5380
+ (!node.typeParameters || node.typeParameters.every(isThislessTypeParameter));
5385
5381
}
5386
5382
5387
- // Returns true if the class or interface member given by the symbol is free of "this" references. The
5388
- // function may return false for symbols that are actually free of "this" references because it is not
5389
- // feasible to perform a complete analysis in all cases. In particular, property members with types
5390
- // inferred from their initializers and function members with inferred return types are conservatively
5391
- // assumed not to be free of "this" references.
5392
- function isIndependentMember(symbol: Symbol): boolean {
5383
+ /**
5384
+ * Returns true if the class or interface member given by the symbol is free of "this" references. The
5385
+ * function may return false for symbols that are actually free of "this" references because it is not
5386
+ * feasible to perform a complete analysis in all cases. In particular, property members with types
5387
+ * inferred from their initializers and function members with inferred return types are conservatively
5388
+ * assumed not to be free of "this" references.
5389
+ */
5390
+ function isThisless(symbol: Symbol): boolean {
5393
5391
if (symbol.declarations && symbol.declarations.length === 1) {
5394
5392
const declaration = symbol.declarations[0];
5395
5393
if (declaration) {
5396
5394
switch (declaration.kind) {
5397
5395
case SyntaxKind.PropertyDeclaration:
5398
5396
case SyntaxKind.PropertySignature:
5399
- return isIndependentVariableLikeDeclaration (<VariableLikeDeclaration>declaration);
5397
+ return isThislessVariableLikeDeclaration (<VariableLikeDeclaration>declaration);
5400
5398
case SyntaxKind.MethodDeclaration:
5401
5399
case SyntaxKind.MethodSignature:
5402
5400
case SyntaxKind.Constructor:
5403
- return isIndependentFunctionLikeDeclaration (<FunctionLikeDeclaration>declaration);
5401
+ return isThislessFunctionLikeDeclaration (<FunctionLikeDeclaration>declaration);
5404
5402
}
5405
5403
}
5406
5404
}
@@ -5412,7 +5410,7 @@ namespace ts {
5412
5410
function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable {
5413
5411
const result = createSymbolTable();
5414
5412
for (const symbol of symbols) {
5415
- result.set(symbol.escapedName, mappingThisOnly && isIndependentMember (symbol) ? symbol : instantiateSymbol(symbol, mapper));
5413
+ result.set(symbol.escapedName, mappingThisOnly && isThisless (symbol) ? symbol : instantiateSymbol(symbol, mapper));
5416
5414
}
5417
5415
return result;
5418
5416
}
0 commit comments