Skip to content

Commit e001258

Browse files
committed
Move non-local type parameter check to resolveName
1 parent 7616e37 commit e001258

File tree

1 file changed

+35
-34
lines changed

1 file changed

+35
-34
lines changed

src/compiler/checker.ts

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,11 @@ namespace ts {
865865
error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters);
866866
return undefined;
867867
}
868+
// Only perform additional check if error reporting was requested
869+
if (nameNotFoundMessage && !isTypeParameterSymbolDeclaredInContainer(result, location)) {
870+
error(errorLocation, Diagnostics.Type_parameter_0_cannot_be_referenced_outside_of_the_declaration_that_defines_it, symbolToString(result));
871+
return undefined;
872+
}
868873
break loop;
869874
}
870875
if (location.kind === SyntaxKind.ClassExpression && meaning & SymbolFlags.Class) {
@@ -1008,6 +1013,16 @@ namespace ts {
10081013
return result;
10091014
}
10101015

1016+
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
1017+
for (const decl of symbol.declarations) {
1018+
if (decl.kind === SyntaxKind.TypeParameter && decl.parent === container) {
1019+
return true;
1020+
}
1021+
}
1022+
1023+
return false;
1024+
}
1025+
10111026
function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean {
10121027
if ((errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(<Identifier>errorLocation)) || isInTypeQuery(errorLocation))) {
10131028
return false;
@@ -5226,18 +5241,11 @@ namespace ts {
52265241
// Map an unsatisfied type parameter with a default type.
52275242
// If a type parameter does not have a default type, or if the default type
52285243
// is a forward reference, the empty object type is used.
5229-
const mapper: TypeMapper = t => {
5230-
const i = indexOf(typeParameters, t);
5231-
if (i >= typeArguments.length) {
5232-
return emptyObjectType;
5233-
}
5234-
if (i >= 0) {
5235-
return typeArguments[i];
5236-
}
5237-
return t;
5238-
};
5239-
52405244
for (let i = numTypeArguments; i < numTypeParameters; i++) {
5245+
typeArguments[i] = emptyObjectType;
5246+
}
5247+
for (let i = numTypeArguments; i < numTypeParameters; i++) {
5248+
const mapper = createTypeMapper(typeParameters, typeArguments);
52415249
const defaultType = getDefaultFromTypeParameter(typeParameters[i]);
52425250
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : emptyObjectType;
52435251
}
@@ -6712,6 +6720,16 @@ namespace ts {
67126720
return createTypeMapper(sources, undefined);
67136721
}
67146722

6723+
/**
6724+
* Maps forward-references to later types parameters to the empty object type.
6725+
* This is used during inference when instantiating type parameter defaults.
6726+
*/
6727+
function createBackreferenceMapper(typeParameters: TypeParameter[], index: number) {
6728+
const mapper: TypeMapper = t => indexOf(typeParameters, t) >= index ? emptyObjectType : t;
6729+
mapper.mappedTypes = typeParameters;
6730+
return mapper;
6731+
}
6732+
67156733
function getInferenceMapper(context: InferenceContext): TypeMapper {
67166734
if (!context.mapper) {
67176735
const mapper: TypeMapper = t => {
@@ -9194,9 +9212,12 @@ namespace ts {
91949212
// candidates with no common supertype.
91959213
const defaultType = getDefaultFromTypeParameter(context.signature.typeParameters[index]);
91969214
if (defaultType) {
9197-
const backreferenceMapper: TypeMapper = t => indexOf(context.signature.typeParameters, t) >= index ? emptyObjectType : t;
9198-
const mapper = combineTypeMappers(backreferenceMapper, getInferenceMapper(context));
9199-
inferredType = instantiateType(defaultType, mapper);
9215+
// Instantiate the default type. Any forward reference to a type
9216+
// parameter should be instantiated to the empty object type.
9217+
inferredType = instantiateType(defaultType,
9218+
combineTypeMappers(
9219+
createBackreferenceMapper(context.signature.typeParameters, index),
9220+
getInferenceMapper(context)));
92009221
}
92019222
else {
92029223
inferredType = emptyObjectType;
@@ -16216,9 +16237,6 @@ namespace ts {
1621616237
checkTypeArgumentConstraints(typeParameters, node.typeArguments, minTypeArgumentCount);
1621716238
}
1621816239
}
16219-
if (type.flags & TypeFlags.TypeParameter && !(<TypeParameter>type).isThisType && type.symbol && !isTypeParameterInScope(<TypeParameter>type, node)) {
16220-
error(node, Diagnostics.Type_parameter_0_cannot_be_referenced_outside_of_the_declaration_that_defines_it, symbolToString(type.symbol));
16221-
}
1622216240
if (type.flags & TypeFlags.Enum && !(<EnumType>type).memberTypes && getNodeLinks(node).resolvedSymbol.flags & SymbolFlags.EnumMember) {
1622316241
error(node, Diagnostics.Enum_type_0_has_members_with_initializers_that_are_not_literals, typeToString(type));
1622416242
}
@@ -17657,23 +17675,6 @@ namespace ts {
1765717675
}
1765817676
}
1765917677

17660-
function isTypeParameterInScope(typeParameter: TypeParameter, node: Node) {
17661-
const parents = map(filter(typeParameter.symbol.declarations, isTypeParameter), node => node.parent);
17662-
while (node) {
17663-
if (isFunctionLike(node) ||
17664-
isClassLike(node) ||
17665-
node.kind === SyntaxKind.InterfaceDeclaration ||
17666-
node.kind === SyntaxKind.TypeAliasDeclaration ||
17667-
node.kind === SyntaxKind.MappedType) {
17668-
if (contains(parents, node)) {
17669-
return true;
17670-
}
17671-
}
17672-
node = node.parent;
17673-
}
17674-
return false;
17675-
}
17676-
1767717678
function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) {
1767817679
if ((left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) ||
1767917680
(left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter)) {

0 commit comments

Comments
 (0)