Skip to content

Fix missing 'infer T' in declaration files #22764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 21, 2018
33 changes: 16 additions & 17 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ namespace ts {
HasLocals = 1 << 5,
IsInterface = 1 << 6,
IsObjectLiteralOrClassExpressionMethod = 1 << 7,
IsInferenceContainer = 1 << 8,
}

const binder = createBinder();
Expand All @@ -121,7 +120,6 @@ namespace ts {
let container: Node;
let containerContainer: Node; // Container one level up
let blockScopeContainer: Node;
let inferenceContainer: Node;
let lastContainer: Node;
let seenThisKeyword: boolean;

Expand Down Expand Up @@ -190,7 +188,6 @@ namespace ts {
container = undefined;
containerContainer = undefined;
blockScopeContainer = undefined;
inferenceContainer = undefined;
lastContainer = undefined;
seenThisKeyword = false;
currentFlow = undefined;
Expand Down Expand Up @@ -569,13 +566,6 @@ namespace ts {
bindChildren(node);
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
}
else if (containerFlags & ContainerFlags.IsInferenceContainer) {
const saveInferenceContainer = inferenceContainer;
inferenceContainer = node;
node.locals = undefined;
bindChildren(node);
inferenceContainer = saveInferenceContainer;
}
else {
bindChildren(node);
}
Expand Down Expand Up @@ -1434,9 +1424,6 @@ namespace ts {
case SyntaxKind.MappedType:
return ContainerFlags.IsContainer | ContainerFlags.HasLocals;

case SyntaxKind.ConditionalType:
return ContainerFlags.IsInferenceContainer;

case SyntaxKind.SourceFile:
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;

Expand Down Expand Up @@ -2638,13 +2625,25 @@ namespace ts {
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
}

function getInferTypeContainer(node: Node): ConditionalTypeNode {
while (node) {
const parent = node.parent;
if (parent && parent.kind === SyntaxKind.ConditionalType && (<ConditionalTypeNode>parent).extendsType === node) {
return <ConditionalTypeNode>parent;
}
node = parent;
}
return undefined;
}

function bindTypeParameter(node: TypeParameterDeclaration) {
if (node.parent.kind === SyntaxKind.InferType) {
if (inferenceContainer) {
if (!inferenceContainer.locals) {
inferenceContainer.locals = createSymbolTable();
const container = getInferTypeContainer(node.parent);
if (container) {
if (!container.locals) {
container.locals = createSymbolTable();
}
declareSymbol(inferenceContainer.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
}
else {
bindAnonymousDeclaration(node, SymbolFlags.TypeParameter, getDeclarationName(node));
Expand Down
10 changes: 9 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2895,7 +2895,8 @@ namespace ts {
flags,
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: noop },
encounteredError: false,
symbolStack: undefined
symbolStack: undefined,
inferTypeParameters: undefined
};
}

Expand Down Expand Up @@ -2987,6 +2988,9 @@ namespace ts {
return typeReferenceToTypeNode(<TypeReference>type);
}
if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) {
if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) {
return createInferTypeNode(createTypeParameterDeclaration(getNameOfSymbolAsWritten(type.symbol)));
}
const name = type.symbol ? symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false) : createIdentifier("?");
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
Expand Down Expand Up @@ -3027,7 +3031,10 @@ namespace ts {
}
if (type.flags & TypeFlags.Conditional) {
const checkTypeNode = typeToTypeNodeHelper((<ConditionalType>type).checkType, context);
const saveInferTypeParameters = context.inferTypeParameters;
context.inferTypeParameters = (<ConditionalType>type).root.inferTypeParameters;
const extendsTypeNode = typeToTypeNodeHelper((<ConditionalType>type).extendsType, context);
context.inferTypeParameters = saveInferTypeParameters;
const trueTypeNode = typeToTypeNodeHelper(getTrueTypeFromConditionalType(<ConditionalType>type), context);
const falseTypeNode = typeToTypeNodeHelper(getFalseTypeFromConditionalType(<ConditionalType>type), context);
return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode);
Expand Down Expand Up @@ -3692,6 +3699,7 @@ namespace ts {
// State
encounteredError: boolean;
symbolStack: Symbol[] | undefined;
inferTypeParameters: TypeParameter[] | undefined;
}

function isDefaultBindingContext(location: Node) {
Expand Down
5 changes: 3 additions & 2 deletions tests/baselines/reference/inferTypes1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(75,15): error TS2304: C
tests/cases/conformance/types/conditional/inferTypes1.ts(75,15): error TS4081: Exported type alias 'T62' has or is using private name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(75,43): error TS2304: Cannot find name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(75,43): error TS4081: Exported type alias 'T62' has or is using private name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(81,44): error TS2344: Type 'U' does not satisfy the constraint 'string'.
tests/cases/conformance/types/conditional/inferTypes1.ts(82,44): error TS2344: Type 'U' does not satisfy the constraint 'string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/conditional/inferTypes1.ts(143,40): error TS2322: Type 'T' is not assignable to type 'string'.
tests/cases/conformance/types/conditional/inferTypes1.ts(144,40): error TS2322: Type 'T' is not assignable to type 'string'.


==== tests/cases/conformance/types/conditional/inferTypes1.ts (16 errors) ====
Expand Down Expand Up @@ -127,6 +127,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(143,40): error TS2322:
!!! error TS2304: Cannot find name 'U'.
~
!!! error TS4081: Exported type alias 'T62' has or is using private name 'U'.
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;

type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/inferTypes1.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number
type T60 = infer U; // Error
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T62<T> = U extends (infer U)[] ? U : U; // Error
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;

type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
Expand Down
Loading