Skip to content

Port #25913 #25936

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 8 commits into from
Jul 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 40 additions & 58 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ namespace ts {
getTypeOfSymbol,
getResolvedSymbol,
getIndexTypeOfStructuredType,
getConstraintFromTypeParameter,
getConstraintOfTypeParameter,
getFirstIdentifier,
),
getAmbientModules,
Expand Down Expand Up @@ -3715,7 +3715,7 @@ namespace ts {
return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
}

function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintFromTypeParameter(type)): TypeParameterDeclaration {
function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintOfTypeParameter(type)): TypeParameterDeclaration {
const constraintNode = constraint && typeToTypeNodeHelper(constraint, context);
return typeParameterToDeclarationWithConstraint(type, context, constraintNode);
}
Expand Down Expand Up @@ -4363,29 +4363,23 @@ namespace ts {
return i;
}
}

return -1;
}

function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
if (propertyName === TypeSystemPropertyName.Type) {
return !!getSymbolLinks(<Symbol>target).type;
}
if (propertyName === TypeSystemPropertyName.DeclaredType) {
return !!getSymbolLinks(<Symbol>target).declaredType;
}
if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
return !!(<InterfaceType>target).resolvedBaseConstructorType;
switch (propertyName) {
case TypeSystemPropertyName.Type:
return !!getSymbolLinks(<Symbol>target).type;
case TypeSystemPropertyName.DeclaredType:
return !!getSymbolLinks(<Symbol>target).declaredType;
case TypeSystemPropertyName.ResolvedBaseConstructorType:
return !!(<InterfaceType>target).resolvedBaseConstructorType;
case TypeSystemPropertyName.ResolvedReturnType:
return !!(<Signature>target).resolvedReturnType;
case TypeSystemPropertyName.ImmediateBaseConstraint:
return !!(<Type>target).immediateBaseConstraint;
}
if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
return !!(<Signature>target).resolvedReturnType;
}
if (propertyName === TypeSystemPropertyName.ImmediateBaseConstraint) {
const bc = (<Type>target).immediateBaseConstraint;
return !!bc && bc !== circularConstraintType;
}

return Debug.fail("Unhandled TypeSystemPropertyName " + propertyName);
return Debug.assertNever(propertyName);
}

// Pop an entry from the type resolution stack and return its associated result value. The result value will
Expand Down Expand Up @@ -6936,21 +6930,12 @@ namespace ts {
return undefined;
}

function getBaseConstraintOfInstantiableNonPrimitiveUnionOrIntersection(type: Type) {
function getBaseConstraintOfType(type: Type): Type | undefined {
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) {
const constraint = getResolvedBaseConstraint(<InstantiableType | UnionOrIntersectionType>type);
if (constraint !== noConstraintType && constraint !== circularConstraintType) {
return constraint;
}
}
}

function getBaseConstraintOfType(type: Type): Type | undefined {
const constraint = getBaseConstraintOfInstantiableNonPrimitiveUnionOrIntersection(type);
if (!constraint && type.flags & TypeFlags.Index) {
return keyofConstraintType;
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
}
return constraint;
return type.flags & TypeFlags.Index ? keyofConstraintType : undefined;
}

/**
Expand All @@ -6971,30 +6956,26 @@ namespace ts {
* circularly references the type variable.
*/
function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type {
let circular: boolean | undefined;
if (!type.resolvedBaseConstraint) {
const constraint = getBaseConstraint(type);
type.resolvedBaseConstraint = circular ? circularConstraintType : getTypeWithThisArgument(constraint || noConstraintType, type);
return type.resolvedBaseConstraint ||
(type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type));

function getImmediateBaseConstraint(t: Type): Type {
if (!t.immediateBaseConstraint) {
if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) {
return circularConstraintType;
}
let result = computeBaseConstraint(getSimplifiedType(t));
if (!popTypeResolution()) {
result = circularConstraintType;
}
t.immediateBaseConstraint = result || noConstraintType;
}
return t.immediateBaseConstraint;
}
return type.resolvedBaseConstraint;

function getBaseConstraint(t: Type): Type | undefined {
if (t.immediateBaseConstraint) {
return t.immediateBaseConstraint === noConstraintType ? undefined : t.immediateBaseConstraint;
}
if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) {
circular = true;
t.immediateBaseConstraint = circularConstraintType;
return undefined;
}
const result = computeBaseConstraint(getSimplifiedType(t));
if (!popTypeResolution()) {
circular = true;
t.immediateBaseConstraint = circularConstraintType;
return undefined;
}
t.immediateBaseConstraint = !result ? noConstraintType : result;
return result;
const c = getImmediateBaseConstraint(t);
return c !== noConstraintType && c !== circularConstraintType ? c : undefined;
}

function computeBaseConstraint(t: Type): Type | undefined {
Expand Down Expand Up @@ -7877,6 +7858,7 @@ namespace ts {
return inferences && getIntersectionType(inferences);
}

/** This is a worker function. Use getConstraintOfTypeParameter which guards against circular constraints. */
function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
if (!typeParameter.constraint) {
if (typeParameter.target) {
Expand Down Expand Up @@ -9145,7 +9127,7 @@ namespace ts {
return type.simplified = substituteIndexedMappedType(objectType, type);
}
if (objectType.flags & TypeFlags.TypeParameter) {
const constraint = getConstraintFromTypeParameter(objectType as TypeParameter);
const constraint = getConstraintOfTypeParameter(objectType as TypeParameter);
if (constraint && isGenericMappedType(constraint)) {
return type.simplified = substituteIndexedMappedType(constraint, type);
}
Expand Down Expand Up @@ -12092,7 +12074,7 @@ namespace ts {
}

function isUnconstrainedTypeParameter(type: Type) {
return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(<TypeParameter>type);
return type.flags & TypeFlags.TypeParameter && !getConstraintOfTypeParameter(<TypeParameter>type);
}

function isTypeReferenceWithGenericArguments(type: Type): boolean {
Expand Down Expand Up @@ -17620,7 +17602,7 @@ namespace ts {
}

const thisType = getTypeFromTypeNode(thisParameter.type);
enclosingClass = ((thisType.flags & TypeFlags.TypeParameter) ? getConstraintFromTypeParameter(<TypeParameter>thisType) : thisType) as InterfaceType;
enclosingClass = ((thisType.flags & TypeFlags.TypeParameter) ? getConstraintOfTypeParameter(<TypeParameter>thisType) : thisType) as InterfaceType;
}
// No further restrictions for static properties
if (flags & ModifierFlags.Static) {
Expand Down Expand Up @@ -19261,7 +19243,7 @@ namespace ts {
typeArguments.pop();
}
while (typeArguments.length < typeParameters.length) {
typeArguments.push(getConstraintFromTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isInJavaScriptFile(node)));
typeArguments.push(getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isInJavaScriptFile(node)));
}
const instantiated = createSignatureInstantiation(candidate, typeArguments);
candidates[bestIndex] = instantiated;
Expand Down Expand Up @@ -25164,7 +25146,7 @@ namespace ts {
// If the type parameter node does not have an identical constraint as the resolved
// type parameter at this position, we report an error.
const sourceConstraint = source.constraint && getTypeFromTypeNode(source.constraint);
const targetConstraint = getConstraintFromTypeParameter(target);
const targetConstraint = getConstraintOfTypeParameter(target);
if (sourceConstraint) {
// relax check if later interface augmentation has no constraint
if (!targetConstraint || !isTypeIdenticalTo(sourceConstraint, targetConstraint)) {
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/symbolWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace ts {
getTypeOfSymbol: (sym: Symbol) => Type,
getResolvedSymbol: (node: Node) => Symbol,
getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type | undefined,
getConstraintFromTypeParameter: (typeParameter: TypeParameter) => Type | undefined,
getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined,
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier) {

return getSymbolWalker;
Expand Down Expand Up @@ -93,7 +93,7 @@ namespace ts {
}

function visitTypeParameter(type: TypeParameter): void {
visitType(getConstraintFromTypeParameter(type));
visitType(getConstraintOfTypeParameter(type));
}

function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ interface Foo {
}

function foo<T extends Foo | T["hello"]>() {
>foo : <T extends Foo | T["hello"]>() => void
>foo : <T>() => void
>T : T
>Foo : Foo
>T : T
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
=== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts ===
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
>sum : <T extends { [x: string]: number; }, K extends keyof T>(n: number, v: T, k: K) => void
>sum : <T, K extends keyof T>(n: number, v: T, k: K) => void
>T : T
>P : P
>T : T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ interface I2<T, U extends U> { }
>U : U

function f<T extends T>() { }
>f : <T extends T>() => void
>f : <T>() => void
>T : T
>T : T

function f2<T, U extends U>() { }
>f2 : <T, U extends U>() => void
>f2 : <T, U>() => void
>T : T
>U : U
>U : U

var a: {
>a : { <T extends T>(): void; <T, U extends U>(): void; }
>a : { <T>(): void; <T, U>(): void; }

<T extends T>(): void;
>T : T
Expand All @@ -48,14 +48,14 @@ var a: {
}

var b = <T extends T>() => { }
>b : <T extends T>() => void
><T extends T>() => { } : <T extends T>() => void
>b : <T>() => void
><T extends T>() => { } : <T>() => void
>T : T
>T : T

var b2 = <T, U extends U>() => { }
>b2 : <T, U extends U>() => void
><T, U extends U>() => { } : <T, U extends U>() => void
>b2 : <T, U>() => void
><T, U extends U>() => { } : <T, U>() => void
>T : T
>U : U
>U : U
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/compiler/typeParameterHasSelfAsConstraint.ts ===
function foo<T extends T>(x: T): number {
>foo : <T extends T>(x: T) => number
>foo : <T>(x: T) => number
>T : T
>T : T
>x : T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterInd
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(16,21): error TS2313: Type parameter 'T' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(16,34): error TS2313: Type parameter 'U' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(16,47): error TS2313: Type parameter 'V' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(18,19): error TS2313: Type parameter 'U' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(18,32): error TS2313: Type parameter 'T' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(18,45): error TS2313: Type parameter 'V' has a circular constraint.
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts(23,24): error TS2313: Type parameter 'S' has a circular constraint.


==== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts (28 errors) ====
Expand Down Expand Up @@ -97,9 +97,15 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterInd
!!! error TS2313: Type parameter 'V' has a circular constraint.

class D<U extends T, T extends V, V extends T> { }
~
!!! error TS2313: Type parameter 'U' has a circular constraint.
~
!!! error TS2313: Type parameter 'T' has a circular constraint.
~
!!! error TS2313: Type parameter 'V' has a circular constraint.
!!! error TS2313: Type parameter 'V' has a circular constraint.

// Repro from #25740

type Foo<T> = [T] extends [number] ? {} : {};
function foo<S extends Foo<S>>() {}
~~~~~~
!!! error TS2313: Type parameter 'S' has a circular constraint.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ var a: {
var b = <U extends T, T extends U>() => { }
var b2 = <T extends U, U extends V, V extends T>() => { }

class D<U extends T, T extends V, V extends T> { }
class D<U extends T, T extends V, V extends T> { }

// Repro from #25740

type Foo<T> = [T] extends [number] ? {} : {};
function foo<S extends Foo<S>>() {}


//// [typeParameterIndirectlyConstrainedToItself.js]
var C = /** @class */ (function () {
Expand All @@ -39,3 +45,4 @@ var D = /** @class */ (function () {
}
return D;
}());
function foo() { }
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,16 @@ class D<U extends T, T extends V, V extends T> { }
>V : Symbol(V, Decl(typeParameterIndirectlyConstrainedToItself.ts, 17, 33))
>T : Symbol(T, Decl(typeParameterIndirectlyConstrainedToItself.ts, 17, 20))

// Repro from #25740

type Foo<T> = [T] extends [number] ? {} : {};
>Foo : Symbol(Foo, Decl(typeParameterIndirectlyConstrainedToItself.ts, 17, 50))
>T : Symbol(T, Decl(typeParameterIndirectlyConstrainedToItself.ts, 21, 9))
>T : Symbol(T, Decl(typeParameterIndirectlyConstrainedToItself.ts, 21, 9))

function foo<S extends Foo<S>>() {}
>foo : Symbol(foo, Decl(typeParameterIndirectlyConstrainedToItself.ts, 21, 45))
>S : Symbol(S, Decl(typeParameterIndirectlyConstrainedToItself.ts, 22, 13))
>Foo : Symbol(Foo, Decl(typeParameterIndirectlyConstrainedToItself.ts, 17, 50))
>S : Symbol(S, Decl(typeParameterIndirectlyConstrainedToItself.ts, 22, 13))

Loading