From 12f5dd85d71b6ffddec54d74a6875dd0b82bdd8e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Sep 2017 06:33:47 -0700 Subject: [PATCH 01/24] Introduce --strictFunctionTypes mode --- src/compiler/checker.ts | 82 +++++++++++++++++++++++----- src/compiler/commandLineParser.ts | 7 +++ src/compiler/diagnosticMessages.json | 4 ++ src/compiler/types.ts | 10 ++++ 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 62d44d160a7b5..33d8b9249da1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -66,6 +66,7 @@ namespace ts { const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters; const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System; const strictNullChecks = compilerOptions.strictNullChecks === undefined ? compilerOptions.strict : compilerOptions.strictNullChecks; + const strictFunctionTypes = compilerOptions.strictFunctionTypes === undefined ? compilerOptions.strict : compilerOptions.strictFunctionTypes; const noImplicitAny = compilerOptions.noImplicitAny === undefined ? compilerOptions.strict : compilerOptions.noImplicitAny; const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis; @@ -2517,7 +2518,7 @@ namespace ts { return typeReferenceToTypeNode(type); } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { - const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); + 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); } @@ -6729,7 +6730,7 @@ namespace ts { } function getConstraintDeclaration(type: TypeParameter) { - return getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter).constraint; + return type.symbol && getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter).constraint; } function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type { @@ -8541,6 +8542,9 @@ namespace ts { source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } + const targetKind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; + const strictVariance = strictFunctionTypes && targetKind !== SyntaxKind.MethodDeclaration && targetKind !== SyntaxKind.MethodSignature; + let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -8548,7 +8552,7 @@ namespace ts { const targetThisType = getThisTypeOfSignature(target); if (targetThisType) { // void sources are assignable to anything. - const related = compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) + const related = !strictVariance && compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) || compareTypes(targetThisType, sourceThisType, reportErrors); if (!related) { if (reportErrors) { @@ -8582,7 +8586,7 @@ namespace ts { (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); const related = callbacks ? compareSignaturesRelated(targetSig, sourceSig, /*checkAsCallback*/ true, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) : - !checkAsCallback && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + !checkAsCallback && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); if (!related) { if (reportErrors) { errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, @@ -9194,7 +9198,7 @@ namespace ts { return result; } - function typeArgumentsRelatedTo(source: TypeReference, target: TypeReference, reportErrors: boolean): Ternary { + function typeArgumentsRelatedTo(source: TypeReference, target: TypeReference, variances: Variance[], reportErrors: boolean): Ternary { const sources = source.typeArguments || emptyArray; const targets = target.typeArguments || emptyArray; if (sources.length !== targets.length && relation === identityRelation) { @@ -9203,11 +9207,34 @@ namespace ts { const length = sources.length <= targets.length ? sources.length : targets.length; let result = Ternary.True; for (let i = 0; i < length; i++) { - const related = isRelatedTo(sources[i], targets[i], reportErrors); - if (!related) { - return Ternary.False; + const variance = i < variances.length ? variances[i] : Variance.Covariant; + if (variance !== Variance.Omnivariant) { + const s = sources[i]; + const t = targets[i]; + let related = Ternary.True; + if (variance === Variance.Covariant) { + related = isRelatedTo(s, t, reportErrors); + } + else if (variance === Variance.Contravariant) { + related = isRelatedTo(t, s, reportErrors); + } + else if (variance === Variance.Bivariant) { + related = isRelatedTo(t, s, /*reportErrors*/ false); + if (!related) { + related = isRelatedTo(s, t, reportErrors); + } + } + else { + related = isRelatedTo(s, t, reportErrors); + if (related) { + related &= isRelatedTo(t, s, reportErrors); + } + } + if (!related) { + return Ternary.False; + } + result &= related; } - result &= related; } return result; } @@ -9371,9 +9398,15 @@ namespace ts { } else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { - // We have type references to same target type, see if relationship holds for all type arguments - if (result = typeArgumentsRelatedTo(source, target, reportErrors)) { - return result; + const variances = getVariances((source).target); + if (variances) { + // We have type references to same target type, see if relationship holds for all type arguments + if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { + return result; + } + if (variances !== emptyArray) { + return Ternary.False; + } } } // Even if relationship doesn't hold for unions, intersections, or generic type references, @@ -9785,6 +9818,29 @@ namespace ts { } } + function getVarianceType(type: GenericType, source: TypeParameter, target: Type) { + return createTypeReference(type, map(type.typeParameters, t => t === source ? target: t)); + } + + function getVariances(type: GenericType) { + const typeParameters = type.typeParameters || emptyArray; + let variances = type.variances; + if (!variances) { + variances = type.variances = []; + for (const tp of typeParameters) { + const superType = getVarianceType(type, tp, stringType); + const subType = getVarianceType(type, tp, emptyStringType); + let variance = (isTypeAssignableTo(subType, superType) ? Variance.Covariant : 0) | + (isTypeAssignableTo(superType, subType) ? Variance.Contravariant : 0); + if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, numberType), superType)) { + variance = Variance.Omnivariant; + } + variances.push(variance); + } + } + return variances.length === typeParameters.length ? variances : emptyArray; + } + function isUnconstrainedTypeParameter(type: Type) { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } @@ -18856,7 +18912,7 @@ namespace ts { const typeArgument = typeArguments[i]; result = result && checkTypeAssignableTo( typeArgument, - getTypeWithThisArgument(instantiateType(constraint, mapper), typeArgument), + instantiateType(constraint, mapper), typeArgumentNodes[i], Diagnostics.Type_0_does_not_satisfy_the_constraint_1); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 54e5ee1d01dbc..b63442bc89a5a 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -269,6 +269,13 @@ namespace ts { category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Enable_strict_null_checks }, + { + name: "strictFunctionTypes", + type: "boolean", + showInSimplifiedHelpView: true, + category: Diagnostics.Strict_Type_Checking_Options, + description: Diagnostics.Enable_strict_checking_of_function_types + }, { name: "noImplicitThis", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8a76ddcda9ae1..3a9857e09eafd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3318,6 +3318,10 @@ "category": "Message", "code": 6185 }, + "Enable strict checking of function types.": { + "category": "Message", + "code": 6186 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5347d7caaf02c..cddfcee6413d8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3347,6 +3347,7 @@ namespace ts { export interface GenericType extends InterfaceType, TypeReference { /* @internal */ instantiations: Map; // Generic instantiation cache + variances?: Variance[]; } export interface UnionOrIntersectionType extends Type { @@ -3440,6 +3441,14 @@ namespace ts { resolvedIndexType: IndexType; } + export const enum Variance { + Invariant = 0, + Covariant = 1, + Contravariant = 2, + Bivariant = Covariant | Contravariant, + Omnivariant = 4 + } + // Type parameters (TypeFlags.TypeParameter) export interface TypeParameter extends TypeVariable { /** Retrieve using getConstraintFromTypeParameter */ @@ -3707,6 +3716,7 @@ namespace ts { sourceMap?: boolean; sourceRoot?: string; strict?: boolean; + strictFunctionTypes?: boolean; // Always combine with strict property strictNullChecks?: boolean; // Always combine with strict property /* @internal */ stripInternal?: boolean; suppressExcessPropertyErrors?: boolean; From f8ff7f73651ac87c50d5a0c6ff16125011be3b6c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Sep 2017 13:36:46 -0700 Subject: [PATCH 02/24] Use dedicated marker types for variance determination --- src/compiler/checker.ts | 16 +++++++++++----- src/compiler/types.ts | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 33d8b9249da1b..f98e7bde2ad30 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -282,6 +282,10 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const markerSuperType = createType(TypeFlags.MarkerType); + const markerSubType = createType(TypeFlags.MarkerType); + const markerOtherType = createType(TypeFlags.MarkerType); + const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -8944,6 +8948,10 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; + if (source.flags & TypeFlags.MarkerType && target.flags & TypeFlags.MarkerType) { + return source === markerSubType && target === markerSuperType ? Ternary.True : Ternary.False; + } + if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { @@ -9367,8 +9375,6 @@ namespace ts { if (!constraint || constraint.flags & TypeFlags.Any) { constraint = emptyObjectType; } - // The constraint may need to be further instantiated with its 'this' type. - constraint = getTypeWithThisArgument(constraint, source); // Report constraint errors only if the constraint is not the empty object type const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { @@ -9828,11 +9834,11 @@ namespace ts { if (!variances) { variances = type.variances = []; for (const tp of typeParameters) { - const superType = getVarianceType(type, tp, stringType); - const subType = getVarianceType(type, tp, emptyStringType); + const superType = getVarianceType(type, tp, markerSuperType); + const subType = getVarianceType(type, tp, markerSubType); let variance = (isTypeAssignableTo(subType, superType) ? Variance.Covariant : 0) | (isTypeAssignableTo(superType, subType) ? Variance.Contravariant : 0); - if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, numberType), superType)) { + if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), superType)) { variance = Variance.Omnivariant; } variances.push(variance); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cddfcee6413d8..a837722cc894b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3215,6 +3215,7 @@ namespace ts { NonPrimitive = 1 << 24, // intrinsic object type /* @internal */ JsxAttributes = 1 << 25, // Jsx attributes type + MarkerType = 1 << 26, // Marker type used for variance probing /* @internal */ Nullable = Undefined | Null, From 670d7113dac4624285e305ddb51ba85b72f7236e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Sep 2017 13:56:59 -0700 Subject: [PATCH 03/24] Add quick path for computing array variance as it is already known --- src/compiler/checker.ts | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f98e7bde2ad30..65c95344c67be 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9832,19 +9832,26 @@ namespace ts { const typeParameters = type.typeParameters || emptyArray; let variances = type.variances; if (!variances) { - variances = type.variances = []; - for (const tp of typeParameters) { - const superType = getVarianceType(type, tp, markerSuperType); - const subType = getVarianceType(type, tp, markerSubType); - let variance = (isTypeAssignableTo(subType, superType) ? Variance.Covariant : 0) | - (isTypeAssignableTo(superType, subType) ? Variance.Contravariant : 0); - if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), superType)) { - variance = Variance.Omnivariant; + if (type === globalArrayType || type === globalReadonlyArrayType) { + variances = [Variance.Covariant]; + } + else { + type.variances = emptyArray; + variances = []; + for (const tp of typeParameters) { + const superType = getVarianceType(type, tp, markerSuperType); + const subType = getVarianceType(type, tp, markerSubType); + let variance = (isTypeAssignableTo(subType, superType) ? Variance.Covariant : 0) | + (isTypeAssignableTo(superType, subType) ? Variance.Contravariant : 0); + if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), superType)) { + variance = Variance.Omnivariant; + } + variances.push(variance); } - variances.push(variance); } + type.variances = variances; } - return variances.length === typeParameters.length ? variances : emptyArray; + return variances; } function isUnconstrainedTypeParameter(type: Type) { From a0fa69ff6c8ffc2ee533407f57ea53d61a28de8c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Sep 2017 17:31:54 -0700 Subject: [PATCH 04/24] Handle contravariance in type inference --- src/compiler/checker.ts | 30 ++++++++++++++++++++++++++---- src/compiler/types.ts | 7 ++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65c95344c67be..ae461119e8bfe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10129,6 +10129,10 @@ namespace ts { getUnionType(types, /*subtypeReduction*/ true); } + function getCommonSubtype(types: Type[]) { + return reduceLeft(types, (s, t) => isTypeSubtypeOf(t, s) ? t : s); + } + function isArrayType(type: Type): boolean { return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalArrayType; } @@ -10655,8 +10659,14 @@ namespace ts { const sourceTypes = (source).typeArguments || emptyArray; const targetTypes = (target).typeArguments || emptyArray; const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; + const variances = strictFunctionTypes ? getVariances((source).target) : undefined; for (let i = 0; i < count; i++) { - inferFromTypes(sourceTypes[i], targetTypes[i]); + if (variances && i < variances.length && variances[i] === Variance.Contravariant) { + inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); + } + else { + inferFromTypes(sourceTypes[i], targetTypes[i]); + } } } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { @@ -10727,6 +10737,17 @@ namespace ts { } } + function inferFromContravariantTypes(source: Type, target: Type) { + if (strictFunctionTypes) { + priority ^= InferencePriority.Contravariant; + inferFromTypes(source, target); + priority ^= InferencePriority.Contravariant; + } + else { + inferFromTypes(source, target); + } + } + function getInferenceInfoForType(type: Type) { if (type.flags & TypeFlags.TypeVariable) { for (const inference of inferences) { @@ -10804,7 +10825,7 @@ namespace ts { } function inferFromSignature(source: Signature, target: Signature) { - forEachMatchingParameterType(source, target, inferFromTypes); + forEachMatchingParameterType(source, target, inferFromContravariantTypes); if (source.typePredicate && target.typePredicate && source.typePredicate.kind === target.typePredicate.kind) { inferFromTypes(source.typePredicate.type, target.typePredicate.type); @@ -10879,8 +10900,9 @@ namespace ts { const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; // Infer widened union or supertype, or the unknown type for no common supertype. We infer union types // for inferences coming from return types in order to avoid common supertype failures. - const unionOrSuperType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? - getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); + const unionOrSuperType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) : + context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : + getCommonSupertype(baseCandidates); inferredType = getWidenedType(unionOrSuperType); } else if (context.flags & InferenceFlags.NoDefault) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a837722cc894b..67974774ab59a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3532,9 +3532,10 @@ namespace ts { } export const enum InferencePriority { - NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type - MappedType = 1 << 1, // Reverse inference for mapped type - ReturnType = 1 << 2, // Inference made from return type of generic function + Contravariant = 1 << 0, // Contravariant inference + NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type + MappedType = 1 << 2, // Reverse inference for mapped type + ReturnType = 1 << 3, // Inference made from return type of generic function } export interface InferenceInfo { From b58e0fba0ca692a8c1eee06a1967a9f445dcdbdc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Sep 2017 10:11:18 -0700 Subject: [PATCH 05/24] Add comments --- src/compiler/checker.ts | 65 ++++++++++++++++++++++++++++++----------- src/compiler/types.ts | 22 +++++++------- 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ae461119e8bfe..8db4466cb8612 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9215,7 +9215,11 @@ namespace ts { const length = sources.length <= targets.length ? sources.length : targets.length; let result = Ternary.True; for (let i = 0; i < length; i++) { + // When variance information isn't available we default to covariance. This happens + // in the process of computing variance information for recursive types and when + // comparing 'this' type arguments. const variance = i < variances.length ? variances[i] : Variance.Covariant; + // We simply ignore omnivariant type arguments (because they're never witnessed). if (variance !== Variance.Omnivariant) { const s = sources[i]; const t = targets[i]; @@ -9227,12 +9231,19 @@ namespace ts { related = isRelatedTo(t, s, reportErrors); } else if (variance === Variance.Bivariant) { + // In the bivariant case we first compare contravariantly without reporting + // errors. Then, if that doesn't succeed, we compare covariantly with error + // reporting. Thus, error elaboration will be based on the the covariant check, + // which is generally easier to reason about. related = isRelatedTo(t, s, /*reportErrors*/ false); if (!related) { related = isRelatedTo(s, t, reportErrors); } } else { + // In the invariant case we first compare covariantly, and only when that + // succeeds do we proceed to compare contravariantly. Thus, error elaboration + // will typically be based on the covariant check. related = isRelatedTo(s, t, reportErrors); if (related) { related &= isRelatedTo(t, s, reportErrors); @@ -9404,15 +9415,18 @@ namespace ts { } else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { + // We have type references to the same generic type. Obtain the variance information for the + // type parameters and relate the type arguments accordingly. const variances = getVariances((source).target); - if (variances) { - // We have type references to same target type, see if relationship holds for all type arguments - if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { - return result; - } - if (variances !== emptyArray) { - return Ternary.False; - } + if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { + return result; + } + // The type arguments did not relate appropriately, but it may be because getVariances was + // invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaults + // to covariance for all type arguments). In that case we need to contine with a structural + // comparison. Otherwise, we know for certain the instantiations aren't related. + if (variances !== emptyArray) { + return Ternary.False; } } // Even if relationship doesn't hold for unions, intersections, or generic type references, @@ -9828,22 +9842,37 @@ namespace ts { return createTypeReference(type, map(type.typeParameters, t => t === source ? target: t)); } + // Return an array containing the variance of each type parameter. The variance is effectively + // a digest of the type comparisons that occur for each type argument when instantiations of the + // generic type are structurally compared. We infer the variance information by comparing + // instantiations of the generic type for type arguments with known relations. Note that the + // function returns the emptyArray singleton to signal that it has been invoked recursively for + // the given generic type. function getVariances(type: GenericType) { const typeParameters = type.typeParameters || emptyArray; let variances = type.variances; if (!variances) { if (type === globalArrayType || type === globalReadonlyArrayType) { + // Arrays are known to be covariant, no need to spend time computing this variances = [Variance.Covariant]; } else { + // The emptyArray singleton is used to signal a recursive invocation. type.variances = emptyArray; variances = []; for (const tp of typeParameters) { - const superType = getVarianceType(type, tp, markerSuperType); - const subType = getVarianceType(type, tp, markerSubType); - let variance = (isTypeAssignableTo(subType, superType) ? Variance.Covariant : 0) | - (isTypeAssignableTo(superType, subType) ? Variance.Contravariant : 0); - if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), superType)) { + // We first compare instantiations where the type parameter is replaced with + // marker types that have a known subtype relationship. From this we can infer + // invariance, covariance, contravariance or bivariance. + const typeWithSuper = getVarianceType(type, tp, markerSuperType); + const typeWithSub = getVarianceType(type, tp, markerSubType); + let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : 0) | + (isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : 0); + // If the instantiations appear to be related bivariantly, it may be because the + // type parameter is omnivariant (i.e. it isn't witnessed anywhere in the generic + // type). To determine this we compare instantiations where the type parameter is + // replaced with marker types that are known to be unrelated. + if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), typeWithSuper)) { variance = Variance.Omnivariant; } variances.push(variance); @@ -10129,6 +10158,7 @@ namespace ts { getUnionType(types, /*subtypeReduction*/ true); } + // Return the leftmost type for which no type to the right is a subtype. function getCommonSubtype(types: Type[]) { return reduceLeft(types, (s, t) => isTypeSubtypeOf(t, s) ? t : s); } @@ -10898,12 +10928,13 @@ namespace ts { !hasPrimitiveConstraint(inference.typeParameter) && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; - // Infer widened union or supertype, or the unknown type for no common supertype. We infer union types - // for inferences coming from return types in order to avoid common supertype failures. - const unionOrSuperType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) : + // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if + // union types were requested or if all inferences were made from the return type position, infer a + // union type. Otherwise, infer a common supertype. + const unwidenedType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) : context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); - inferredType = getWidenedType(unionOrSuperType); + inferredType = getWidenedType(unwidenedType); } else if (context.flags & InferenceFlags.NoDefault) { // We use silentNeverType as the wildcard that signals no inferences. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 67974774ab59a..3f07716fd1b70 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3344,11 +3344,19 @@ namespace ts { typeArguments?: Type[]; // Type reference type arguments (undefined if none) } + export const enum Variance { + Invariant = 0, // Both covariant and contravariant + Covariant = 1, // Covariant + Contravariant = 2, // Contravariant + Bivariant = 3, // Either covariant or contravariant + Omnivariant = 4 // Unwitnessed type parameter + } + // Generic class and interface types export interface GenericType extends InterfaceType, TypeReference { /* @internal */ - instantiations: Map; // Generic instantiation cache - variances?: Variance[]; + instantiations: Map; // Generic instantiation cache + variances?: Variance[]; // Variance of each type parameter } export interface UnionOrIntersectionType extends Type { @@ -3442,14 +3450,6 @@ namespace ts { resolvedIndexType: IndexType; } - export const enum Variance { - Invariant = 0, - Covariant = 1, - Contravariant = 2, - Bivariant = Covariant | Contravariant, - Omnivariant = 4 - } - // Type parameters (TypeFlags.TypeParameter) export interface TypeParameter extends TypeVariable { /** Retrieve using getConstraintFromTypeParameter */ @@ -3532,7 +3532,7 @@ namespace ts { } export const enum InferencePriority { - Contravariant = 1 << 0, // Contravariant inference + Contravariant = 1 << 0, // Inference from contravariant position NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type MappedType = 1 << 2, // Reverse inference for mapped type ReturnType = 1 << 3, // Inference made from return type of generic function From 84f7afd29e3082d5279594aee745e68f958ebc88 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Sep 2017 13:29:03 -0700 Subject: [PATCH 06/24] Handle special case of 'void' type arguments for covariant type parameters --- src/compiler/checker.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8db4466cb8612..4bacb88ef4a0f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9422,10 +9422,13 @@ namespace ts { return result; } // The type arguments did not relate appropriately, but it may be because getVariances was - // invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaults - // to covariance for all type arguments). In that case we need to contine with a structural - // comparison. Otherwise, we know for certain the instantiations aren't related. - if (variances !== emptyArray) { + // invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaulted + // to covariance for all type arguments). It might also be the case that the target type has a + // 'void' type argument for a covariant type parameter that is only used in return positions + // within the generic type (in which case any type argument is permitted on the source side). + // In those cases we proceed with a structural comparison. Otherwise, we know for certain the + // instantiations aren't related and we can return here. + if (variances !== emptyArray && !hasCovariantVoidArgument(target, variances)) { return Ternary.False; } } @@ -9839,7 +9842,7 @@ namespace ts { } function getVarianceType(type: GenericType, source: TypeParameter, target: Type) { - return createTypeReference(type, map(type.typeParameters, t => t === source ? target: t)); + return createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); } // Return an array containing the variance of each type parameter. The variance is effectively @@ -9848,7 +9851,7 @@ namespace ts { // instantiations of the generic type for type arguments with known relations. Note that the // function returns the emptyArray singleton to signal that it has been invoked recursively for // the given generic type. - function getVariances(type: GenericType) { + function getVariances(type: GenericType): Variance[] { const typeParameters = type.typeParameters || emptyArray; let variances = type.variances; if (!variances) { @@ -9883,6 +9886,17 @@ namespace ts { return variances; } + // Return true if the given type reference has a 'void' type argument for a covariant type parameter. + // See comment at call in recursiveTypeRelatedTo for when this case matters. + function hasCovariantVoidArgument(type: TypeReference, variances: Variance[]): boolean { + for (let i = 0; i < variances.length; i++) { + if (variances[i] === Variance.Covariant && type.typeArguments[i].flags & TypeFlags.Void) { + return true; + } + } + return false; + } + function isUnconstrainedTypeParameter(type: Type) { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } From 54eadef408884239025aa70c16d933e0c285d924 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Sep 2017 13:30:18 -0700 Subject: [PATCH 07/24] Accept new baselines --- tests/baselines/reference/fuzzy.errors.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/baselines/reference/fuzzy.errors.txt b/tests/baselines/reference/fuzzy.errors.txt index c3f05fd7f2f04..b32f225a33e31 100644 --- a/tests/baselines/reference/fuzzy.errors.txt +++ b/tests/baselines/reference/fuzzy.errors.txt @@ -4,6 +4,7 @@ tests/cases/compiler/fuzzy.ts(21,13): error TS2322: Type '{ anything: number; on Types of property 'oneI' are incompatible. Type 'this' is not assignable to type 'I'. Type 'C' is not assignable to type 'I'. + Property 'alsoWorks' is missing in type 'C'. tests/cases/compiler/fuzzy.ts(25,20): error TS2352: Type '{ oneI: this; }' cannot be converted to type 'R'. Property 'anything' is missing in type '{ oneI: this; }'. @@ -38,6 +39,7 @@ tests/cases/compiler/fuzzy.ts(25,20): error TS2352: Type '{ oneI: this; }' canno !!! error TS2322: Types of property 'oneI' are incompatible. !!! error TS2322: Type 'this' is not assignable to type 'I'. !!! error TS2322: Type 'C' is not assignable to type 'I'. +!!! error TS2322: Property 'alsoWorks' is missing in type 'C'. } worksToo():R { From 44cc8c5ffe53d0fd034275fe4f6ebe809d58db43 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Sep 2017 14:23:01 -0700 Subject: [PATCH 08/24] Use methods in dom.generated.d.ts to opt out of strict checks --- src/lib/dom.generated.d.ts | 214 ++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index d4ee81e497424..93bfb98295555 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -4230,25 +4230,25 @@ interface HTMLBodyElement extends HTMLElement { bgProperties: string; link: any; noWrap: boolean; - onafterprint: (this: HTMLBodyElement, ev: Event) => any; - onbeforeprint: (this: HTMLBodyElement, ev: Event) => any; - onbeforeunload: (this: HTMLBodyElement, ev: BeforeUnloadEvent) => any; - onblur: (this: HTMLBodyElement, ev: FocusEvent) => any; - onerror: (this: HTMLBodyElement, ev: ErrorEvent) => any; - onfocus: (this: HTMLBodyElement, ev: FocusEvent) => any; - onhashchange: (this: HTMLBodyElement, ev: HashChangeEvent) => any; - onload: (this: HTMLBodyElement, ev: Event) => any; - onmessage: (this: HTMLBodyElement, ev: MessageEvent) => any; - onoffline: (this: HTMLBodyElement, ev: Event) => any; - ononline: (this: HTMLBodyElement, ev: Event) => any; - onorientationchange: (this: HTMLBodyElement, ev: Event) => any; - onpagehide: (this: HTMLBodyElement, ev: PageTransitionEvent) => any; - onpageshow: (this: HTMLBodyElement, ev: PageTransitionEvent) => any; - onpopstate: (this: HTMLBodyElement, ev: PopStateEvent) => any; - onresize: (this: HTMLBodyElement, ev: UIEvent) => any; - onscroll: (this: HTMLBodyElement, ev: UIEvent) => any; - onstorage: (this: HTMLBodyElement, ev: StorageEvent) => any; - onunload: (this: HTMLBodyElement, ev: Event) => any; + onafterprint(this: HTMLBodyElement, ev: Event): any; + onbeforeprint(this: HTMLBodyElement, ev: Event): any; + onbeforeunload(this: HTMLBodyElement, ev: BeforeUnloadEvent): any; + onblur(this: HTMLBodyElement, ev: FocusEvent): any; + onerror(this: HTMLBodyElement, ev: ErrorEvent): any; + onfocus(this: HTMLBodyElement, ev: FocusEvent): any; + onhashchange(this: HTMLBodyElement, ev: HashChangeEvent): any; + onload(this: HTMLBodyElement, ev: Event): any; + onmessage(this: HTMLBodyElement, ev: MessageEvent): any; + onoffline(this: HTMLBodyElement, ev: Event): any; + ononline(this: HTMLBodyElement, ev: Event): any; + onorientationchange(this: HTMLBodyElement, ev: Event): any; + onpagehide(this: HTMLBodyElement, ev: PageTransitionEvent): any; + onpageshow(this: HTMLBodyElement, ev: PageTransitionEvent): any; + onpopstate(this: HTMLBodyElement, ev: PopStateEvent): any; + onresize(this: HTMLBodyElement, ev: UIEvent): any; + onscroll(this: HTMLBodyElement, ev: UIEvent): any; + onstorage(this: HTMLBodyElement, ev: StorageEvent): any; + onunload(this: HTMLBodyElement, ev: Event): any; text: any; vLink: any; addEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, useCapture?: boolean): void; @@ -4565,73 +4565,73 @@ interface HTMLElement extends Element { readonly offsetParent: Element; readonly offsetTop: number; readonly offsetWidth: number; - onabort: (this: HTMLElement, ev: UIEvent) => any; - onactivate: (this: HTMLElement, ev: UIEvent) => any; - onbeforeactivate: (this: HTMLElement, ev: UIEvent) => any; - onbeforecopy: (this: HTMLElement, ev: ClipboardEvent) => any; - onbeforecut: (this: HTMLElement, ev: ClipboardEvent) => any; - onbeforedeactivate: (this: HTMLElement, ev: UIEvent) => any; - onbeforepaste: (this: HTMLElement, ev: ClipboardEvent) => any; - onblur: (this: HTMLElement, ev: FocusEvent) => any; - oncanplay: (this: HTMLElement, ev: Event) => any; - oncanplaythrough: (this: HTMLElement, ev: Event) => any; - onchange: (this: HTMLElement, ev: Event) => any; - onclick: (this: HTMLElement, ev: MouseEvent) => any; - oncontextmenu: (this: HTMLElement, ev: PointerEvent) => any; - oncopy: (this: HTMLElement, ev: ClipboardEvent) => any; - oncuechange: (this: HTMLElement, ev: Event) => any; - oncut: (this: HTMLElement, ev: ClipboardEvent) => any; - ondblclick: (this: HTMLElement, ev: MouseEvent) => any; - ondeactivate: (this: HTMLElement, ev: UIEvent) => any; - ondrag: (this: HTMLElement, ev: DragEvent) => any; - ondragend: (this: HTMLElement, ev: DragEvent) => any; - ondragenter: (this: HTMLElement, ev: DragEvent) => any; - ondragleave: (this: HTMLElement, ev: DragEvent) => any; - ondragover: (this: HTMLElement, ev: DragEvent) => any; - ondragstart: (this: HTMLElement, ev: DragEvent) => any; - ondrop: (this: HTMLElement, ev: DragEvent) => any; - ondurationchange: (this: HTMLElement, ev: Event) => any; - onemptied: (this: HTMLElement, ev: Event) => any; - onended: (this: HTMLElement, ev: MediaStreamErrorEvent) => any; - onerror: (this: HTMLElement, ev: ErrorEvent) => any; - onfocus: (this: HTMLElement, ev: FocusEvent) => any; - oninput: (this: HTMLElement, ev: Event) => any; - oninvalid: (this: HTMLElement, ev: Event) => any; - onkeydown: (this: HTMLElement, ev: KeyboardEvent) => any; - onkeypress: (this: HTMLElement, ev: KeyboardEvent) => any; - onkeyup: (this: HTMLElement, ev: KeyboardEvent) => any; - onload: (this: HTMLElement, ev: Event) => any; - onloadeddata: (this: HTMLElement, ev: Event) => any; - onloadedmetadata: (this: HTMLElement, ev: Event) => any; - onloadstart: (this: HTMLElement, ev: Event) => any; - onmousedown: (this: HTMLElement, ev: MouseEvent) => any; - onmouseenter: (this: HTMLElement, ev: MouseEvent) => any; - onmouseleave: (this: HTMLElement, ev: MouseEvent) => any; - onmousemove: (this: HTMLElement, ev: MouseEvent) => any; - onmouseout: (this: HTMLElement, ev: MouseEvent) => any; - onmouseover: (this: HTMLElement, ev: MouseEvent) => any; - onmouseup: (this: HTMLElement, ev: MouseEvent) => any; - onmousewheel: (this: HTMLElement, ev: WheelEvent) => any; - onmscontentzoom: (this: HTMLElement, ev: UIEvent) => any; - onmsmanipulationstatechanged: (this: HTMLElement, ev: MSManipulationEvent) => any; - onpaste: (this: HTMLElement, ev: ClipboardEvent) => any; - onpause: (this: HTMLElement, ev: Event) => any; - onplay: (this: HTMLElement, ev: Event) => any; - onplaying: (this: HTMLElement, ev: Event) => any; - onprogress: (this: HTMLElement, ev: ProgressEvent) => any; - onratechange: (this: HTMLElement, ev: Event) => any; - onreset: (this: HTMLElement, ev: Event) => any; - onscroll: (this: HTMLElement, ev: UIEvent) => any; - onseeked: (this: HTMLElement, ev: Event) => any; - onseeking: (this: HTMLElement, ev: Event) => any; - onselect: (this: HTMLElement, ev: UIEvent) => any; - onselectstart: (this: HTMLElement, ev: Event) => any; - onstalled: (this: HTMLElement, ev: Event) => any; - onsubmit: (this: HTMLElement, ev: Event) => any; - onsuspend: (this: HTMLElement, ev: Event) => any; - ontimeupdate: (this: HTMLElement, ev: Event) => any; - onvolumechange: (this: HTMLElement, ev: Event) => any; - onwaiting: (this: HTMLElement, ev: Event) => any; + onabort(this: HTMLElement, ev: UIEvent): any; + onactivate(this: HTMLElement, ev: UIEvent): any; + onbeforeactivate(this: HTMLElement, ev: UIEvent): any; + onbeforecopy(this: HTMLElement, ev: ClipboardEvent): any; + onbeforecut(this: HTMLElement, ev: ClipboardEvent): any; + onbeforedeactivate(this: HTMLElement, ev: UIEvent): any; + onbeforepaste(this: HTMLElement, ev: ClipboardEvent): any; + onblur(this: HTMLElement, ev: FocusEvent): any; + oncanplay(this: HTMLElement, ev: Event): any; + oncanplaythrough(this: HTMLElement, ev: Event): any; + onchange(this: HTMLElement, ev: Event): any; + onclick(this: HTMLElement, ev: MouseEvent): any; + oncontextmenu(this: HTMLElement, ev: PointerEvent): any; + oncopy(this: HTMLElement, ev: ClipboardEvent): any; + oncuechange(this: HTMLElement, ev: Event): any; + oncut(this: HTMLElement, ev: ClipboardEvent): any; + ondblclick(this: HTMLElement, ev: MouseEvent): any; + ondeactivate(this: HTMLElement, ev: UIEvent): any; + ondrag(this: HTMLElement, ev: DragEvent): any; + ondragend(this: HTMLElement, ev: DragEvent): any; + ondragenter(this: HTMLElement, ev: DragEvent): any; + ondragleave(this: HTMLElement, ev: DragEvent): any; + ondragover(this: HTMLElement, ev: DragEvent): any; + ondragstart(this: HTMLElement, ev: DragEvent): any; + ondrop(this: HTMLElement, ev: DragEvent): any; + ondurationchange(this: HTMLElement, ev: Event): any; + onemptied(this: HTMLElement, ev: Event): any; + onended(this: HTMLElement, ev: MediaStreamErrorEvent): any; + onerror(this: HTMLElement, ev: ErrorEvent): any; + onfocus(this: HTMLElement, ev: FocusEvent): any; + oninput(this: HTMLElement, ev: Event): any; + oninvalid(this: HTMLElement, ev: Event): any; + onkeydown(this: HTMLElement, ev: KeyboardEvent): any; + onkeypress(this: HTMLElement, ev: KeyboardEvent): any; + onkeyup(this: HTMLElement, ev: KeyboardEvent): any; + onload(this: HTMLElement, ev: Event): any; + onloadeddata(this: HTMLElement, ev: Event): any; + onloadedmetadata(this: HTMLElement, ev: Event): any; + onloadstart(this: HTMLElement, ev: Event): any; + onmousedown(this: HTMLElement, ev: MouseEvent): any; + onmouseenter(this: HTMLElement, ev: MouseEvent): any; + onmouseleave(this: HTMLElement, ev: MouseEvent): any; + onmousemove(this: HTMLElement, ev: MouseEvent): any; + onmouseout(this: HTMLElement, ev: MouseEvent): any; + onmouseover(this: HTMLElement, ev: MouseEvent): any; + onmouseup(this: HTMLElement, ev: MouseEvent): any; + onmousewheel(this: HTMLElement, ev: WheelEvent): any; + onmscontentzoom(this: HTMLElement, ev: UIEvent): any; + onmsmanipulationstatechanged(this: HTMLElement, ev: MSManipulationEvent): any; + onpaste(this: HTMLElement, ev: ClipboardEvent): any; + onpause(this: HTMLElement, ev: Event): any; + onplay(this: HTMLElement, ev: Event): any; + onplaying(this: HTMLElement, ev: Event): any; + onprogress(this: HTMLElement, ev: ProgressEvent): any; + onratechange(this: HTMLElement, ev: Event): any; + onreset(this: HTMLElement, ev: Event): any; + onscroll(this: HTMLElement, ev: UIEvent): any; + onseeked(this: HTMLElement, ev: Event): any; + onseeking(this: HTMLElement, ev: Event): any; + onselect(this: HTMLElement, ev: UIEvent): any; + onselectstart(this: HTMLElement, ev: Event): any; + onstalled(this: HTMLElement, ev: Event): any; + onsubmit(this: HTMLElement, ev: Event): any; + onsuspend(this: HTMLElement, ev: Event): any; + ontimeupdate(this: HTMLElement, ev: Event): any; + onvolumechange(this: HTMLElement, ev: Event): any; + onwaiting(this: HTMLElement, ev: Event): any; outerText: string; spellcheck: boolean; readonly style: CSSStyleDeclaration; @@ -4904,7 +4904,7 @@ interface HTMLFrameElement extends HTMLElement, GetSVGDocument { /** * Raised when the object has been completely received from the server. */ - onload: (this: HTMLFrameElement, ev: Event) => any; + onload(this: HTMLFrameElement, ev: Event): any; /** * Sets or retrieves whether the frame can be scrolled. */ @@ -4967,31 +4967,31 @@ interface HTMLFrameSetElement extends HTMLElement { */ frameSpacing: any; name: string; - onafterprint: (this: HTMLFrameSetElement, ev: Event) => any; - onbeforeprint: (this: HTMLFrameSetElement, ev: Event) => any; - onbeforeunload: (this: HTMLFrameSetElement, ev: BeforeUnloadEvent) => any; + onafterprint(this: HTMLFrameSetElement, ev: Event): any; + onbeforeprint(this: HTMLFrameSetElement, ev: Event): any; + onbeforeunload(this: HTMLFrameSetElement, ev: BeforeUnloadEvent): any; /** * Fires when the object loses the input focus. */ - onblur: (this: HTMLFrameSetElement, ev: FocusEvent) => any; - onerror: (this: HTMLFrameSetElement, ev: ErrorEvent) => any; + onblur(this: HTMLFrameSetElement, ev: FocusEvent): any; + onerror(this: HTMLFrameSetElement, ev: ErrorEvent): any; /** * Fires when the object receives focus. */ - onfocus: (this: HTMLFrameSetElement, ev: FocusEvent) => any; - onhashchange: (this: HTMLFrameSetElement, ev: HashChangeEvent) => any; - onload: (this: HTMLFrameSetElement, ev: Event) => any; - onmessage: (this: HTMLFrameSetElement, ev: MessageEvent) => any; - onoffline: (this: HTMLFrameSetElement, ev: Event) => any; - ononline: (this: HTMLFrameSetElement, ev: Event) => any; - onorientationchange: (this: HTMLFrameSetElement, ev: Event) => any; - onpagehide: (this: HTMLFrameSetElement, ev: PageTransitionEvent) => any; - onpageshow: (this: HTMLFrameSetElement, ev: PageTransitionEvent) => any; - onpopstate: (this: HTMLFrameSetElement, ev: PopStateEvent) => any; - onresize: (this: HTMLFrameSetElement, ev: UIEvent) => any; - onscroll: (this: HTMLFrameSetElement, ev: UIEvent) => any; - onstorage: (this: HTMLFrameSetElement, ev: StorageEvent) => any; - onunload: (this: HTMLFrameSetElement, ev: Event) => any; + onfocus(this: HTMLFrameSetElement, ev: FocusEvent): any; + onhashchange(this: HTMLFrameSetElement, ev: HashChangeEvent): any; + onload(this: HTMLFrameSetElement, ev: Event): any; + onmessage(this: HTMLFrameSetElement, ev: MessageEvent): any; + onoffline(this: HTMLFrameSetElement, ev: Event): any; + ononline(this: HTMLFrameSetElement, ev: Event): any; + onorientationchange(this: HTMLFrameSetElement, ev: Event): any; + onpagehide(this: HTMLFrameSetElement, ev: PageTransitionEvent): any; + onpageshow(this: HTMLFrameSetElement, ev: PageTransitionEvent): any; + onpopstate(this: HTMLFrameSetElement, ev: PopStateEvent): any; + onresize(this: HTMLFrameSetElement, ev: UIEvent): any; + onscroll(this: HTMLFrameSetElement, ev: UIEvent): any; + onstorage(this: HTMLFrameSetElement, ev: StorageEvent): any; + onunload(this: HTMLFrameSetElement, ev: Event): any; /** * Sets or retrieves the frame heights of the object. */ @@ -5128,7 +5128,7 @@ interface HTMLIFrameElement extends HTMLElement, GetSVGDocument { /** * Raised when the object has been completely received from the server. */ - onload: (this: HTMLIFrameElement, ev: Event) => any; + onload(this: HTMLIFrameElement, ev: Event): any; readonly sandbox: DOMSettableTokenList; /** * Sets or retrieves whether the frame can be scrolled. From dd466ae599587d863c678debf44129d618467738 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Sep 2017 15:29:36 -0700 Subject: [PATCH 09/24] Update tsconfig baselines --- .../tsConfig/Default initialized TSConfig/tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../Initialized TSConfig with files options/tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + 8 files changed, 8 insertions(+) diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 0f5b23784683f..bae0e1c0eb025 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index a545124a72397..4d0db39092f63 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index b53ac2d8552d8..010a1186211e1 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 4e06e06d159a4..b78057d07088a 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 94808d89ed05d..be4fc190f9ba9 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 0f5b23784683f..bae0e1c0eb025 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index d165b0f277541..d7496d18dbba2 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index 2a169b3aaafa1..6d6964b829429 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ From 24698dd353e9303ed311705630bfcd8bf75ad88a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Sep 2017 13:49:57 -0700 Subject: [PATCH 10/24] Revert dom.generated.d.ts and fix duplicate declarations --- src/lib/dom.generated.d.ts | 212 +++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 116 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 93bfb98295555..420be2f0f5dc4 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -4230,25 +4230,20 @@ interface HTMLBodyElement extends HTMLElement { bgProperties: string; link: any; noWrap: boolean; - onafterprint(this: HTMLBodyElement, ev: Event): any; - onbeforeprint(this: HTMLBodyElement, ev: Event): any; - onbeforeunload(this: HTMLBodyElement, ev: BeforeUnloadEvent): any; - onblur(this: HTMLBodyElement, ev: FocusEvent): any; - onerror(this: HTMLBodyElement, ev: ErrorEvent): any; - onfocus(this: HTMLBodyElement, ev: FocusEvent): any; - onhashchange(this: HTMLBodyElement, ev: HashChangeEvent): any; - onload(this: HTMLBodyElement, ev: Event): any; - onmessage(this: HTMLBodyElement, ev: MessageEvent): any; - onoffline(this: HTMLBodyElement, ev: Event): any; - ononline(this: HTMLBodyElement, ev: Event): any; - onorientationchange(this: HTMLBodyElement, ev: Event): any; - onpagehide(this: HTMLBodyElement, ev: PageTransitionEvent): any; - onpageshow(this: HTMLBodyElement, ev: PageTransitionEvent): any; - onpopstate(this: HTMLBodyElement, ev: PopStateEvent): any; - onresize(this: HTMLBodyElement, ev: UIEvent): any; - onscroll(this: HTMLBodyElement, ev: UIEvent): any; - onstorage(this: HTMLBodyElement, ev: StorageEvent): any; - onunload(this: HTMLBodyElement, ev: Event): any; + onafterprint: (this: HTMLBodyElement, ev: Event) => any; + onbeforeprint: (this: HTMLBodyElement, ev: Event) => any; + onbeforeunload: (this: HTMLBodyElement, ev: BeforeUnloadEvent) => any; + onhashchange: (this: HTMLBodyElement, ev: HashChangeEvent) => any; + onmessage: (this: HTMLBodyElement, ev: MessageEvent) => any; + onoffline: (this: HTMLBodyElement, ev: Event) => any; + ononline: (this: HTMLBodyElement, ev: Event) => any; + onorientationchange: (this: HTMLBodyElement, ev: Event) => any; + onpagehide: (this: HTMLBodyElement, ev: PageTransitionEvent) => any; + onpageshow: (this: HTMLBodyElement, ev: PageTransitionEvent) => any; + onpopstate: (this: HTMLBodyElement, ev: PopStateEvent) => any; + onresize: (this: HTMLBodyElement, ev: UIEvent) => any; + onstorage: (this: HTMLBodyElement, ev: StorageEvent) => any; + onunload: (this: HTMLBodyElement, ev: Event) => any; text: any; vLink: any; addEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, useCapture?: boolean): void; @@ -4565,73 +4560,73 @@ interface HTMLElement extends Element { readonly offsetParent: Element; readonly offsetTop: number; readonly offsetWidth: number; - onabort(this: HTMLElement, ev: UIEvent): any; - onactivate(this: HTMLElement, ev: UIEvent): any; - onbeforeactivate(this: HTMLElement, ev: UIEvent): any; - onbeforecopy(this: HTMLElement, ev: ClipboardEvent): any; - onbeforecut(this: HTMLElement, ev: ClipboardEvent): any; - onbeforedeactivate(this: HTMLElement, ev: UIEvent): any; - onbeforepaste(this: HTMLElement, ev: ClipboardEvent): any; - onblur(this: HTMLElement, ev: FocusEvent): any; - oncanplay(this: HTMLElement, ev: Event): any; - oncanplaythrough(this: HTMLElement, ev: Event): any; - onchange(this: HTMLElement, ev: Event): any; - onclick(this: HTMLElement, ev: MouseEvent): any; - oncontextmenu(this: HTMLElement, ev: PointerEvent): any; - oncopy(this: HTMLElement, ev: ClipboardEvent): any; - oncuechange(this: HTMLElement, ev: Event): any; - oncut(this: HTMLElement, ev: ClipboardEvent): any; - ondblclick(this: HTMLElement, ev: MouseEvent): any; - ondeactivate(this: HTMLElement, ev: UIEvent): any; - ondrag(this: HTMLElement, ev: DragEvent): any; - ondragend(this: HTMLElement, ev: DragEvent): any; - ondragenter(this: HTMLElement, ev: DragEvent): any; - ondragleave(this: HTMLElement, ev: DragEvent): any; - ondragover(this: HTMLElement, ev: DragEvent): any; - ondragstart(this: HTMLElement, ev: DragEvent): any; - ondrop(this: HTMLElement, ev: DragEvent): any; - ondurationchange(this: HTMLElement, ev: Event): any; - onemptied(this: HTMLElement, ev: Event): any; - onended(this: HTMLElement, ev: MediaStreamErrorEvent): any; - onerror(this: HTMLElement, ev: ErrorEvent): any; - onfocus(this: HTMLElement, ev: FocusEvent): any; - oninput(this: HTMLElement, ev: Event): any; - oninvalid(this: HTMLElement, ev: Event): any; - onkeydown(this: HTMLElement, ev: KeyboardEvent): any; - onkeypress(this: HTMLElement, ev: KeyboardEvent): any; - onkeyup(this: HTMLElement, ev: KeyboardEvent): any; - onload(this: HTMLElement, ev: Event): any; - onloadeddata(this: HTMLElement, ev: Event): any; - onloadedmetadata(this: HTMLElement, ev: Event): any; - onloadstart(this: HTMLElement, ev: Event): any; - onmousedown(this: HTMLElement, ev: MouseEvent): any; - onmouseenter(this: HTMLElement, ev: MouseEvent): any; - onmouseleave(this: HTMLElement, ev: MouseEvent): any; - onmousemove(this: HTMLElement, ev: MouseEvent): any; - onmouseout(this: HTMLElement, ev: MouseEvent): any; - onmouseover(this: HTMLElement, ev: MouseEvent): any; - onmouseup(this: HTMLElement, ev: MouseEvent): any; - onmousewheel(this: HTMLElement, ev: WheelEvent): any; - onmscontentzoom(this: HTMLElement, ev: UIEvent): any; - onmsmanipulationstatechanged(this: HTMLElement, ev: MSManipulationEvent): any; - onpaste(this: HTMLElement, ev: ClipboardEvent): any; - onpause(this: HTMLElement, ev: Event): any; - onplay(this: HTMLElement, ev: Event): any; - onplaying(this: HTMLElement, ev: Event): any; - onprogress(this: HTMLElement, ev: ProgressEvent): any; - onratechange(this: HTMLElement, ev: Event): any; - onreset(this: HTMLElement, ev: Event): any; - onscroll(this: HTMLElement, ev: UIEvent): any; - onseeked(this: HTMLElement, ev: Event): any; - onseeking(this: HTMLElement, ev: Event): any; - onselect(this: HTMLElement, ev: UIEvent): any; - onselectstart(this: HTMLElement, ev: Event): any; - onstalled(this: HTMLElement, ev: Event): any; - onsubmit(this: HTMLElement, ev: Event): any; - onsuspend(this: HTMLElement, ev: Event): any; - ontimeupdate(this: HTMLElement, ev: Event): any; - onvolumechange(this: HTMLElement, ev: Event): any; - onwaiting(this: HTMLElement, ev: Event): any; + onabort: (this: HTMLElement, ev: UIEvent) => any; + onactivate: (this: HTMLElement, ev: UIEvent) => any; + onbeforeactivate: (this: HTMLElement, ev: UIEvent) => any; + onbeforecopy: (this: HTMLElement, ev: ClipboardEvent) => any; + onbeforecut: (this: HTMLElement, ev: ClipboardEvent) => any; + onbeforedeactivate: (this: HTMLElement, ev: UIEvent) => any; + onbeforepaste: (this: HTMLElement, ev: ClipboardEvent) => any; + onblur: (this: HTMLElement, ev: FocusEvent) => any; + oncanplay: (this: HTMLElement, ev: Event) => any; + oncanplaythrough: (this: HTMLElement, ev: Event) => any; + onchange: (this: HTMLElement, ev: Event) => any; + onclick: (this: HTMLElement, ev: MouseEvent) => any; + oncontextmenu: (this: HTMLElement, ev: PointerEvent) => any; + oncopy: (this: HTMLElement, ev: ClipboardEvent) => any; + oncuechange: (this: HTMLElement, ev: Event) => any; + oncut: (this: HTMLElement, ev: ClipboardEvent) => any; + ondblclick: (this: HTMLElement, ev: MouseEvent) => any; + ondeactivate: (this: HTMLElement, ev: UIEvent) => any; + ondrag: (this: HTMLElement, ev: DragEvent) => any; + ondragend: (this: HTMLElement, ev: DragEvent) => any; + ondragenter: (this: HTMLElement, ev: DragEvent) => any; + ondragleave: (this: HTMLElement, ev: DragEvent) => any; + ondragover: (this: HTMLElement, ev: DragEvent) => any; + ondragstart: (this: HTMLElement, ev: DragEvent) => any; + ondrop: (this: HTMLElement, ev: DragEvent) => any; + ondurationchange: (this: HTMLElement, ev: Event) => any; + onemptied: (this: HTMLElement, ev: Event) => any; + onended: (this: HTMLElement, ev: MediaStreamErrorEvent) => any; + onerror: (this: HTMLElement, ev: ErrorEvent) => any; + onfocus: (this: HTMLElement, ev: FocusEvent) => any; + oninput: (this: HTMLElement, ev: Event) => any; + oninvalid: (this: HTMLElement, ev: Event) => any; + onkeydown: (this: HTMLElement, ev: KeyboardEvent) => any; + onkeypress: (this: HTMLElement, ev: KeyboardEvent) => any; + onkeyup: (this: HTMLElement, ev: KeyboardEvent) => any; + onload: (this: HTMLElement, ev: Event) => any; + onloadeddata: (this: HTMLElement, ev: Event) => any; + onloadedmetadata: (this: HTMLElement, ev: Event) => any; + onloadstart: (this: HTMLElement, ev: Event) => any; + onmousedown: (this: HTMLElement, ev: MouseEvent) => any; + onmouseenter: (this: HTMLElement, ev: MouseEvent) => any; + onmouseleave: (this: HTMLElement, ev: MouseEvent) => any; + onmousemove: (this: HTMLElement, ev: MouseEvent) => any; + onmouseout: (this: HTMLElement, ev: MouseEvent) => any; + onmouseover: (this: HTMLElement, ev: MouseEvent) => any; + onmouseup: (this: HTMLElement, ev: MouseEvent) => any; + onmousewheel: (this: HTMLElement, ev: WheelEvent) => any; + onmscontentzoom: (this: HTMLElement, ev: UIEvent) => any; + onmsmanipulationstatechanged: (this: HTMLElement, ev: MSManipulationEvent) => any; + onpaste: (this: HTMLElement, ev: ClipboardEvent) => any; + onpause: (this: HTMLElement, ev: Event) => any; + onplay: (this: HTMLElement, ev: Event) => any; + onplaying: (this: HTMLElement, ev: Event) => any; + onprogress: (this: HTMLElement, ev: ProgressEvent) => any; + onratechange: (this: HTMLElement, ev: Event) => any; + onreset: (this: HTMLElement, ev: Event) => any; + onscroll: (this: HTMLElement, ev: UIEvent) => any; + onseeked: (this: HTMLElement, ev: Event) => any; + onseeking: (this: HTMLElement, ev: Event) => any; + onselect: (this: HTMLElement, ev: UIEvent) => any; + onselectstart: (this: HTMLElement, ev: Event) => any; + onstalled: (this: HTMLElement, ev: Event) => any; + onsubmit: (this: HTMLElement, ev: Event) => any; + onsuspend: (this: HTMLElement, ev: Event) => any; + ontimeupdate: (this: HTMLElement, ev: Event) => any; + onvolumechange: (this: HTMLElement, ev: Event) => any; + onwaiting: (this: HTMLElement, ev: Event) => any; outerText: string; spellcheck: boolean; readonly style: CSSStyleDeclaration; @@ -4901,10 +4896,6 @@ interface HTMLFrameElement extends HTMLElement, GetSVGDocument { * Sets or retrieves whether the user can resize the frame. */ noResize: boolean; - /** - * Raised when the object has been completely received from the server. - */ - onload(this: HTMLFrameElement, ev: Event): any; /** * Sets or retrieves whether the frame can be scrolled. */ @@ -4967,31 +4958,23 @@ interface HTMLFrameSetElement extends HTMLElement { */ frameSpacing: any; name: string; - onafterprint(this: HTMLFrameSetElement, ev: Event): any; - onbeforeprint(this: HTMLFrameSetElement, ev: Event): any; - onbeforeunload(this: HTMLFrameSetElement, ev: BeforeUnloadEvent): any; - /** - * Fires when the object loses the input focus. - */ - onblur(this: HTMLFrameSetElement, ev: FocusEvent): any; - onerror(this: HTMLFrameSetElement, ev: ErrorEvent): any; + onafterprint: (this: HTMLFrameSetElement, ev: Event) => any; + onbeforeprint: (this: HTMLFrameSetElement, ev: Event) => any; + onbeforeunload: (this: HTMLFrameSetElement, ev: BeforeUnloadEvent) => any; /** * Fires when the object receives focus. */ - onfocus(this: HTMLFrameSetElement, ev: FocusEvent): any; - onhashchange(this: HTMLFrameSetElement, ev: HashChangeEvent): any; - onload(this: HTMLFrameSetElement, ev: Event): any; - onmessage(this: HTMLFrameSetElement, ev: MessageEvent): any; - onoffline(this: HTMLFrameSetElement, ev: Event): any; - ononline(this: HTMLFrameSetElement, ev: Event): any; - onorientationchange(this: HTMLFrameSetElement, ev: Event): any; - onpagehide(this: HTMLFrameSetElement, ev: PageTransitionEvent): any; - onpageshow(this: HTMLFrameSetElement, ev: PageTransitionEvent): any; - onpopstate(this: HTMLFrameSetElement, ev: PopStateEvent): any; - onresize(this: HTMLFrameSetElement, ev: UIEvent): any; - onscroll(this: HTMLFrameSetElement, ev: UIEvent): any; - onstorage(this: HTMLFrameSetElement, ev: StorageEvent): any; - onunload(this: HTMLFrameSetElement, ev: Event): any; + onhashchange: (this: HTMLFrameSetElement, ev: HashChangeEvent) => any; + onmessage: (this: HTMLFrameSetElement, ev: MessageEvent) => any; + onoffline: (this: HTMLFrameSetElement, ev: Event) => any; + ononline: (this: HTMLFrameSetElement, ev: Event) => any; + onorientationchange: (this: HTMLFrameSetElement, ev: Event) => any; + onpagehide: (this: HTMLFrameSetElement, ev: PageTransitionEvent) => any; + onpageshow: (this: HTMLFrameSetElement, ev: PageTransitionEvent) => any; + onpopstate: (this: HTMLFrameSetElement, ev: PopStateEvent) => any; + onresize: (this: HTMLFrameSetElement, ev: UIEvent) => any; + onstorage: (this: HTMLFrameSetElement, ev: StorageEvent) => any; + onunload: (this: HTMLFrameSetElement, ev: Event) => any; /** * Sets or retrieves the frame heights of the object. */ @@ -5125,10 +5108,7 @@ interface HTMLIFrameElement extends HTMLElement, GetSVGDocument { * Sets or retrieves whether the user can resize the frame. */ noResize: boolean; - /** - * Raised when the object has been completely received from the server. - */ - onload(this: HTMLIFrameElement, ev: Event): any; + readonly sandbox: DOMSettableTokenList; /** * Sets or retrieves whether the frame can be scrolled. From f8e2cc13918c08c9697474c3cdc516fcee9596b0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Sep 2017 07:10:11 -0700 Subject: [PATCH 11/24] Properly flag and structurally compare marker type references --- src/compiler/checker.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4bacb88ef4a0f..fce58ad866f10 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8948,7 +8948,7 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (source.flags & TypeFlags.MarkerType && target.flags & TypeFlags.MarkerType) { + if (source.flags & TypeFlags.MarkerType && target.flags & TypeFlags.MarkerType && !(source.flags & TypeFlags.Object || target.flags & TypeFlags.Object)) { return source === markerSubType && target === markerSuperType ? Ternary.True : Ternary.False; } @@ -9414,9 +9414,11 @@ namespace ts { } } else { - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { - // We have type references to the same generic type. Obtain the variance information for the - // type parameters and relate the type arguments accordingly. + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && + !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) { + // We have type references to the same generic type, and the type references are not marker + // type references (which we always compare structurally). Obtain the variance information + // for the type parameters and relate the type arguments accordingly. const variances = getVariances((source).target); if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { return result; @@ -9841,8 +9843,12 @@ namespace ts { } } - function getVarianceType(type: GenericType, source: TypeParameter, target: Type) { - return createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); + // Return a type reference where the source type parameter is replaced with the target marker + // type, and flag the result as a marker type reference. + function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) { + const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); + result.flags |= TypeFlags.MarkerType; + return result; } // Return an array containing the variance of each type parameter. The variance is effectively @@ -9867,15 +9873,15 @@ namespace ts { // We first compare instantiations where the type parameter is replaced with // marker types that have a known subtype relationship. From this we can infer // invariance, covariance, contravariance or bivariance. - const typeWithSuper = getVarianceType(type, tp, markerSuperType); - const typeWithSub = getVarianceType(type, tp, markerSubType); + const typeWithSuper = getMarkerTypeReference(type, tp, markerSuperType); + const typeWithSub = getMarkerTypeReference(type, tp, markerSubType); let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : 0) | (isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : 0); // If the instantiations appear to be related bivariantly, it may be because the // type parameter is omnivariant (i.e. it isn't witnessed anywhere in the generic // type). To determine this we compare instantiations where the type parameter is // replaced with marker types that are known to be unrelated. - if (variance === Variance.Bivariant && isTypeAssignableTo(getVarianceType(type, tp, markerOtherType), typeWithSuper)) { + if (variance === Variance.Bivariant && isTypeAssignableTo(getMarkerTypeReference(type, tp, markerOtherType), typeWithSuper)) { variance = Variance.Omnivariant; } variances.push(variance); From 589e1f440c7b76d359d8e9f9fd8722d199da3c59 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Sep 2017 08:52:22 -0700 Subject: [PATCH 12/24] Update comment --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fce58ad866f10..574ce5c6d8066 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9417,8 +9417,8 @@ namespace ts { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker - // type references (which we always compare structurally). Obtain the variance information - // for the type parameters and relate the type arguments accordingly. + // type references (which are intended by be compared structurally). Obtain the variance + // information for the type parameters and relate the type arguments accordingly. const variances = getVariances((source).target); if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { return result; From afc8a261ccc6b19873032f9f5adb47b2ce874eef Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Sep 2017 21:31:11 -0700 Subject: [PATCH 13/24] Always perform structural comparison when variance check fails --- src/compiler/checker.ts | 117 ++++++++++++---------------------------- src/compiler/types.ts | 4 +- 2 files changed, 35 insertions(+), 86 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 574ce5c6d8066..25dc303055684 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -282,9 +282,9 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const markerSuperType = createType(TypeFlags.MarkerType); - const markerSubType = createType(TypeFlags.MarkerType); - const markerOtherType = createType(TypeFlags.MarkerType); + const markerSuperType = createType(TypeFlags.TypeParameter); + const markerSubType = createType(TypeFlags.TypeParameter); + markerSubType.constraint = markerSuperType; const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -8948,10 +8948,6 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (source.flags & TypeFlags.MarkerType && target.flags & TypeFlags.MarkerType && !(source.flags & TypeFlags.Object || target.flags & TypeFlags.Object)) { - return source === markerSubType && target === markerSuperType ? Ternary.True : Ternary.False; - } - if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { @@ -9219,41 +9215,15 @@ namespace ts { // in the process of computing variance information for recursive types and when // comparing 'this' type arguments. const variance = i < variances.length ? variances[i] : Variance.Covariant; - // We simply ignore omnivariant type arguments (because they're never witnessed). - if (variance !== Variance.Omnivariant) { - const s = sources[i]; - const t = targets[i]; - let related = Ternary.True; - if (variance === Variance.Covariant) { - related = isRelatedTo(s, t, reportErrors); - } - else if (variance === Variance.Contravariant) { - related = isRelatedTo(t, s, reportErrors); - } - else if (variance === Variance.Bivariant) { - // In the bivariant case we first compare contravariantly without reporting - // errors. Then, if that doesn't succeed, we compare covariantly with error - // reporting. Thus, error elaboration will be based on the the covariant check, - // which is generally easier to reason about. - related = isRelatedTo(t, s, /*reportErrors*/ false); - if (!related) { - related = isRelatedTo(s, t, reportErrors); - } - } - else { - // In the invariant case we first compare covariantly, and only when that - // succeeds do we proceed to compare contravariantly. Thus, error elaboration - // will typically be based on the covariant check. - related = isRelatedTo(s, t, reportErrors); - if (related) { - related &= isRelatedTo(t, s, reportErrors); - } - } - if (!related) { - return Ternary.False; - } - result &= related; + const s = sources[i]; + const t = targets[i]; + const related = variance === Variance.Covariant ? isRelatedTo(s, t, reportErrors) : + variance === Variance.Contravariant ? isRelatedTo(t, s, reportErrors) : + Ternary.False; + if (!related) { + return Ternary.False; } + result &= related; } return result; } @@ -9418,21 +9388,14 @@ namespace ts { !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance - // information for the type parameters and relate the type arguments accordingly. + // information for the type parameters and relate the type arguments accordingly. If we do + // not succeed, fall through and do a structural comparison instead (there are instances + // where the variance information isn't accurate, e.g. when type parameters are used only + // in bivariant positions or when a type argument is 'any' or 'void'.) const variances = getVariances((source).target); if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { return result; } - // The type arguments did not relate appropriately, but it may be because getVariances was - // invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaulted - // to covariance for all type arguments). It might also be the case that the target type has a - // 'void' type argument for a covariant type parameter that is only used in return positions - // within the generic type (in which case any type argument is permitted on the source side). - // In those cases we proceed with a structural comparison. Otherwise, we know for certain the - // instantiations aren't related and we can return here. - if (variances !== emptyArray && !hasCovariantVoidArgument(target, variances)) { - return Ternary.False; - } } // Even if relationship doesn't hold for unions, intersections, or generic type references, // it may hold in a structural comparison. @@ -9851,13 +9814,18 @@ namespace ts { return result; } - // Return an array containing the variance of each type parameter. The variance is effectively - // a digest of the type comparisons that occur for each type argument when instantiations of the - // generic type are structurally compared. We infer the variance information by comparing - // instantiations of the generic type for type arguments with known relations. Note that the - // function returns the emptyArray singleton to signal that it has been invoked recursively for - // the given generic type. + // Return an array containing the variance of each type parameter. The variance information is + // computed by comparing instantiations of the generic type for type arguments with known relations. + // A type parameter is marked as covariant if a covariant comparison succeeds; otherwise, it is + // marked contravariant if a contravarint comparison succeeds; otherwise, it is marked invariant. + // One form of variance doesn't exclude another, so this information simply serves to indicate + // a "primary" relationship that can be checked as an optimization ahead of a full structural + // comparison. The function returns the emptyArray singleton if we're not in strictFunctionTypes + // mode or if the function has been invoked recursively for the given generic type. function getVariances(type: GenericType): Variance[] { + if (!strictFunctionTypes) { + return emptyArray; + } const typeParameters = type.typeParameters || emptyArray; let variances = type.variances; if (!variances) { @@ -9870,20 +9838,14 @@ namespace ts { type.variances = emptyArray; variances = []; for (const tp of typeParameters) { - // We first compare instantiations where the type parameter is replaced with - // marker types that have a known subtype relationship. From this we can infer - // invariance, covariance, contravariance or bivariance. + // We compare instantiations where the type parameter is replaced with marker types + // that have a known subtype relationship. From this we infer covariance, contravariance + // or invariance. const typeWithSuper = getMarkerTypeReference(type, tp, markerSuperType); const typeWithSub = getMarkerTypeReference(type, tp, markerSubType); - let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : 0) | - (isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : 0); - // If the instantiations appear to be related bivariantly, it may be because the - // type parameter is omnivariant (i.e. it isn't witnessed anywhere in the generic - // type). To determine this we compare instantiations where the type parameter is - // replaced with marker types that are known to be unrelated. - if (variance === Variance.Bivariant && isTypeAssignableTo(getMarkerTypeReference(type, tp, markerOtherType), typeWithSuper)) { - variance = Variance.Omnivariant; - } + const variance = isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : + isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : + Variance.Invariant; variances.push(variance); } } @@ -9892,17 +9854,6 @@ namespace ts { return variances; } - // Return true if the given type reference has a 'void' type argument for a covariant type parameter. - // See comment at call in recursiveTypeRelatedTo for when this case matters. - function hasCovariantVoidArgument(type: TypeReference, variances: Variance[]): boolean { - for (let i = 0; i < variances.length; i++) { - if (variances[i] === Variance.Covariant && type.typeArguments[i].flags & TypeFlags.Void) { - return true; - } - } - return false; - } - function isUnconstrainedTypeParameter(type: Type) { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } @@ -10709,9 +10660,9 @@ namespace ts { const sourceTypes = (source).typeArguments || emptyArray; const targetTypes = (target).typeArguments || emptyArray; const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; - const variances = strictFunctionTypes ? getVariances((source).target) : undefined; + const variances = getVariances((source).target); for (let i = 0; i < count; i++) { - if (variances && i < variances.length && variances[i] === Variance.Contravariant) { + if (i < variances.length && variances[i] === Variance.Contravariant) { inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3f07716fd1b70..8ab999032bc79 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3345,11 +3345,9 @@ namespace ts { } export const enum Variance { - Invariant = 0, // Both covariant and contravariant + Invariant = 0, // Neither covariant nor contravariant Covariant = 1, // Covariant Contravariant = 2, // Contravariant - Bivariant = 3, // Either covariant or contravariant - Omnivariant = 4 // Unwitnessed type parameter } // Generic class and interface types From 70e8f7364e813c5bff4ada3ecb581d31eeb38122 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Sep 2017 21:40:31 -0700 Subject: [PATCH 14/24] Add tests --- .../reference/strictFunctionTypes1.js | 25 ++ .../reference/strictFunctionTypes1.symbols | 96 +++++++ .../reference/strictFunctionTypes1.types | 102 +++++++ .../strictFunctionTypesErrors.errors.txt | 271 ++++++++++++++++++ .../reference/strictFunctionTypesErrors.js | 170 +++++++++++ tests/cases/compiler/strictFunctionTypes1.ts | 18 ++ .../compiler/strictFunctionTypesErrors.ts | 113 ++++++++ 7 files changed, 795 insertions(+) create mode 100644 tests/baselines/reference/strictFunctionTypes1.js create mode 100644 tests/baselines/reference/strictFunctionTypes1.symbols create mode 100644 tests/baselines/reference/strictFunctionTypes1.types create mode 100644 tests/baselines/reference/strictFunctionTypesErrors.errors.txt create mode 100644 tests/baselines/reference/strictFunctionTypesErrors.js create mode 100644 tests/cases/compiler/strictFunctionTypes1.ts create mode 100644 tests/cases/compiler/strictFunctionTypesErrors.ts diff --git a/tests/baselines/reference/strictFunctionTypes1.js b/tests/baselines/reference/strictFunctionTypes1.js new file mode 100644 index 0000000000000..28a7a7f61d607 --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypes1.js @@ -0,0 +1,25 @@ +//// [strictFunctionTypes1.ts] +declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; +declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; +declare function f3(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T; + +interface Func { (x: T): void } + +declare function f4(f1: Func, f2: Func): Func; + +declare function fo(x: Object): void; +declare function fs(x: string): void; +declare function fx(f: (x: "def") => void): void; + +const x1 = f1(fo, fs); // (x: string) => void +const x2 = f2("abc", fo, fs); // "abc" +const x3 = f3("abc", fo, fx); // "abc" | "def" +const x4 = f4(fo, fs); // Func + + +//// [strictFunctionTypes1.js] +"use strict"; +var x1 = f1(fo, fs); // (x: string) => void +var x2 = f2("abc", fo, fs); // "abc" +var x3 = f3("abc", fo, fx); // "abc" | "def" +var x4 = f4(fo, fs); // Func diff --git a/tests/baselines/reference/strictFunctionTypes1.symbols b/tests/baselines/reference/strictFunctionTypes1.symbols new file mode 100644 index 0000000000000..70253411201db --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypes1.symbols @@ -0,0 +1,96 @@ +=== tests/cases/compiler/strictFunctionTypes1.ts === +declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 0, 20)) +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 0, 23)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 0, 28)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 0, 20)) +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 0, 42)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 0, 48)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 0, 20)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 0, 65)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 0, 20)) + +declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 0, 79)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 1, 20)) +>obj : Symbol(obj, Decl(strictFunctionTypes1.ts, 1, 23)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 1, 20)) +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 1, 30)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 1, 36)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 1, 20)) +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 1, 50)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 1, 56)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 1, 20)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 1, 20)) + +declare function f3(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T; +>f3 : Symbol(f3, Decl(strictFunctionTypes1.ts, 1, 74)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 2, 20)) +>obj : Symbol(obj, Decl(strictFunctionTypes1.ts, 2, 23)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 2, 20)) +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 2, 30)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 2, 36)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 2, 20)) +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 2, 50)) +>f : Symbol(f, Decl(strictFunctionTypes1.ts, 2, 56)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 2, 60)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 2, 20)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 2, 20)) + +interface Func { (x: T): void } +>Func : Symbol(Func, Decl(strictFunctionTypes1.ts, 2, 87)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 4, 15)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 4, 21)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 4, 15)) + +declare function f4(f1: Func, f2: Func): Func; +>f4 : Symbol(f4, Decl(strictFunctionTypes1.ts, 4, 34)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 6, 20)) +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 6, 23)) +>Func : Symbol(Func, Decl(strictFunctionTypes1.ts, 2, 87)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 6, 20)) +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 6, 35)) +>Func : Symbol(Func, Decl(strictFunctionTypes1.ts, 2, 87)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 6, 20)) +>Func : Symbol(Func, Decl(strictFunctionTypes1.ts, 2, 87)) +>T : Symbol(T, Decl(strictFunctionTypes1.ts, 6, 20)) + +declare function fo(x: Object): void; +>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 8, 20)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare function fs(x: string): void; +>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 9, 20)) + +declare function fx(f: (x: "def") => void): void; +>fx : Symbol(fx, Decl(strictFunctionTypes1.ts, 9, 37)) +>f : Symbol(f, Decl(strictFunctionTypes1.ts, 10, 20)) +>x : Symbol(x, Decl(strictFunctionTypes1.ts, 10, 24)) + +const x1 = f1(fo, fs); // (x: string) => void +>x1 : Symbol(x1, Decl(strictFunctionTypes1.ts, 12, 5)) +>f1 : Symbol(f1, Decl(strictFunctionTypes1.ts, 0, 0)) +>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58)) +>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37)) + +const x2 = f2("abc", fo, fs); // "abc" +>x2 : Symbol(x2, Decl(strictFunctionTypes1.ts, 13, 5)) +>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 0, 79)) +>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58)) +>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37)) + +const x3 = f3("abc", fo, fx); // "abc" | "def" +>x3 : Symbol(x3, Decl(strictFunctionTypes1.ts, 14, 5)) +>f3 : Symbol(f3, Decl(strictFunctionTypes1.ts, 1, 74)) +>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58)) +>fx : Symbol(fx, Decl(strictFunctionTypes1.ts, 9, 37)) + +const x4 = f4(fo, fs); // Func +>x4 : Symbol(x4, Decl(strictFunctionTypes1.ts, 15, 5)) +>f4 : Symbol(f4, Decl(strictFunctionTypes1.ts, 4, 34)) +>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58)) +>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37)) + diff --git a/tests/baselines/reference/strictFunctionTypes1.types b/tests/baselines/reference/strictFunctionTypes1.types new file mode 100644 index 0000000000000..9701d78cff0e3 --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypes1.types @@ -0,0 +1,102 @@ +=== tests/cases/compiler/strictFunctionTypes1.ts === +declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; +>f1 : (f1: (x: T) => void, f2: (x: T) => void) => (x: T) => void +>T : T +>f1 : (x: T) => void +>x : T +>T : T +>f2 : (x: T) => void +>x : T +>T : T +>x : T +>T : T + +declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; +>f2 : (obj: T, f1: (x: T) => void, f2: (x: T) => void) => T +>T : T +>obj : T +>T : T +>f1 : (x: T) => void +>x : T +>T : T +>f2 : (x: T) => void +>x : T +>T : T +>T : T + +declare function f3(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T; +>f3 : (obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void) => T +>T : T +>obj : T +>T : T +>f1 : (x: T) => void +>x : T +>T : T +>f2 : (f: (x: T) => void) => void +>f : (x: T) => void +>x : T +>T : T +>T : T + +interface Func { (x: T): void } +>Func : Func +>T : T +>x : T +>T : T + +declare function f4(f1: Func, f2: Func): Func; +>f4 : (f1: Func, f2: Func) => Func +>T : T +>f1 : Func +>Func : Func +>T : T +>f2 : Func +>Func : Func +>T : T +>Func : Func +>T : T + +declare function fo(x: Object): void; +>fo : (x: Object) => void +>x : Object +>Object : Object + +declare function fs(x: string): void; +>fs : (x: string) => void +>x : string + +declare function fx(f: (x: "def") => void): void; +>fx : (f: (x: "def") => void) => void +>f : (x: "def") => void +>x : "def" + +const x1 = f1(fo, fs); // (x: string) => void +>x1 : (x: string) => void +>f1(fo, fs) : (x: string) => void +>f1 : (f1: (x: T) => void, f2: (x: T) => void) => (x: T) => void +>fo : (x: Object) => void +>fs : (x: string) => void + +const x2 = f2("abc", fo, fs); // "abc" +>x2 : "abc" +>f2("abc", fo, fs) : "abc" +>f2 : (obj: T, f1: (x: T) => void, f2: (x: T) => void) => T +>"abc" : "abc" +>fo : (x: Object) => void +>fs : (x: string) => void + +const x3 = f3("abc", fo, fx); // "abc" | "def" +>x3 : "def" | "abc" +>f3("abc", fo, fx) : "def" | "abc" +>f3 : (obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void) => T +>"abc" : "abc" +>fo : (x: Object) => void +>fx : (f: (x: "def") => void) => void + +const x4 = f4(fo, fs); // Func +>x4 : Func +>f4(fo, fs) : Func +>f4 : (f1: Func, f2: Func) => Func +>fo : (x: Object) => void +>fs : (x: string) => void + diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt new file mode 100644 index 0000000000000..3ff71ea26e7ff --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -0,0 +1,271 @@ +tests/cases/compiler/strictFunctionTypesErrors.ts(10,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: Object) => Object'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(11,1): error TS2322: Type '(x: string) => string' is not assignable to type '(x: Object) => Object'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(13,1): error TS2322: Type '(x: Object) => Object' is not assignable to type '(x: Object) => string'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(14,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: Object) => string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(15,1): error TS2322: Type '(x: string) => string' is not assignable to type '(x: Object) => string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(21,1): error TS2322: Type '(x: Object) => Object' is not assignable to type '(x: string) => string'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(23,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(33,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(34,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(36,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(37,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(38,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(44,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(46,1): error TS2322: Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(57,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(58,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(61,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. + Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(62,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(65,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(66,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(67,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(74,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(75,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(76,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(79,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(80,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Object' is not assignable to type 'string'. +tests/cases/compiler/strictFunctionTypesErrors.ts(83,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. + Type 'Func' is not assignable to type 'Func'. +tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. + Type 'Animal' is not assignable to type 'Dog'. + + +==== tests/cases/compiler/strictFunctionTypesErrors.ts (29 errors) ==== + export {} + + + declare let f1: (x: Object) => Object; + declare let f2: (x: Object) => string; + declare let f3: (x: string) => Object; + declare let f4: (x: string) => string; + + f1 = f2; // Ok + f1 = f3; // Error + ~~ +!!! error TS2322: Type '(x: string) => Object' is not assignable to type '(x: Object) => Object'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + f1 = f4; // Error + ~~ +!!! error TS2322: Type '(x: string) => string' is not assignable to type '(x: Object) => Object'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + f2 = f1; // Error + ~~ +!!! error TS2322: Type '(x: Object) => Object' is not assignable to type '(x: Object) => string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + f2 = f3; // Error + ~~ +!!! error TS2322: Type '(x: string) => Object' is not assignable to type '(x: Object) => string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + f2 = f4; // Error + ~~ +!!! error TS2322: Type '(x: string) => string' is not assignable to type '(x: Object) => string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + f3 = f1; // Ok + f3 = f2; // Ok + f3 = f4; // Ok + + f4 = f1; // Error + ~~ +!!! error TS2322: Type '(x: Object) => Object' is not assignable to type '(x: string) => string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + f4 = f2; // Ok + f4 = f3; // Error + ~~ +!!! error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + interface Func { (x: T): U } + + declare let g1: Func; + declare let g2: Func; + declare let g3: Func; + declare let g4: Func; + + g1 = g2; // Ok + g1 = g3; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + g1 = g4; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + g2 = g1; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + g2 = g3; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + g2 = g4; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + g3 = g1; // Ok + g3 = g2; // Ok + g3 = g4; // Ok + + g4 = g1; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + g4 = g2; // Ok + g4 = g3; // Error + ~~ +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + declare let h1: Func, Object>; + declare let h2: Func, string>; + declare let h3: Func, Object>; + declare let h4: Func, string>; + + h1 = h2; // Ok + h1 = h3; // Ok + h1 = h4; // Ok + + h2 = h1; // Error + ~~ +!!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + h2 = h3; // Error + ~~ +!!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + h2 = h4; // Ok + + h3 = h1; // Error + ~~ +!!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + h3 = h2; // Error + ~~ +!!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + h3 = h4; // Ok + + h4 = h1; // Error + ~~ +!!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + h4 = h2; // Error + ~~ +!!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + h4 = h3; // Error + ~~ +!!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + declare let i1: Func>; + declare let i2: Func>; + declare let i3: Func>; + declare let i4: Func>; + + i1 = i2; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + i1 = i3; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + i1 = i4; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + i2 = i1; // Ok + i2 = i3; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + i2 = i4; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. + + i3 = i1; // Ok + i3 = i2; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + i3 = i4; // Error + ~~ +!!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. + + i4 = i1; // Ok + i4 = i2; // Ok + i4 = i3; // Ok + + interface Animal { animal: void } + interface Dog extends Animal { dog: void } + interface Cat extends Animal { cat: void } + + interface Comparer1 { + compare(a: T, b: T): number; + } + + declare let animalComparer1: Comparer1; + declare let dogComparer1: Comparer1; + + animalComparer1 = dogComparer1; // Ok + dogComparer1 = animalComparer1; // Ok + + interface Comparer2 { + compare: (a: T, b: T) => number; + } + + declare let animalComparer2: Comparer2; + declare let dogComparer2: Comparer2; + + animalComparer2 = dogComparer2; // Error + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. + dogComparer2 = animalComparer2; // Ok + \ No newline at end of file diff --git a/tests/baselines/reference/strictFunctionTypesErrors.js b/tests/baselines/reference/strictFunctionTypesErrors.js new file mode 100644 index 0000000000000..af41c9395f91a --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypesErrors.js @@ -0,0 +1,170 @@ +//// [strictFunctionTypesErrors.ts] +export {} + + +declare let f1: (x: Object) => Object; +declare let f2: (x: Object) => string; +declare let f3: (x: string) => Object; +declare let f4: (x: string) => string; + +f1 = f2; // Ok +f1 = f3; // Error +f1 = f4; // Error + +f2 = f1; // Error +f2 = f3; // Error +f2 = f4; // Error + +f3 = f1; // Ok +f3 = f2; // Ok +f3 = f4; // Ok + +f4 = f1; // Error +f4 = f2; // Ok +f4 = f3; // Error + +interface Func { (x: T): U } + +declare let g1: Func; +declare let g2: Func; +declare let g3: Func; +declare let g4: Func; + +g1 = g2; // Ok +g1 = g3; // Error +g1 = g4; // Error + +g2 = g1; // Error +g2 = g3; // Error +g2 = g4; // Error + +g3 = g1; // Ok +g3 = g2; // Ok +g3 = g4; // Ok + +g4 = g1; // Error +g4 = g2; // Ok +g4 = g3; // Error + +declare let h1: Func, Object>; +declare let h2: Func, string>; +declare let h3: Func, Object>; +declare let h4: Func, string>; + +h1 = h2; // Ok +h1 = h3; // Ok +h1 = h4; // Ok + +h2 = h1; // Error +h2 = h3; // Error +h2 = h4; // Ok + +h3 = h1; // Error +h3 = h2; // Error +h3 = h4; // Ok + +h4 = h1; // Error +h4 = h2; // Error +h4 = h3; // Error + +declare let i1: Func>; +declare let i2: Func>; +declare let i3: Func>; +declare let i4: Func>; + +i1 = i2; // Error +i1 = i3; // Error +i1 = i4; // Error + +i2 = i1; // Ok +i2 = i3; // Error +i2 = i4; // Error + +i3 = i1; // Ok +i3 = i2; // Error +i3 = i4; // Error + +i4 = i1; // Ok +i4 = i2; // Ok +i4 = i3; // Ok + +interface Animal { animal: void } +interface Dog extends Animal { dog: void } +interface Cat extends Animal { cat: void } + +interface Comparer1 { + compare(a: T, b: T): number; +} + +declare let animalComparer1: Comparer1; +declare let dogComparer1: Comparer1; + +animalComparer1 = dogComparer1; // Ok +dogComparer1 = animalComparer1; // Ok + +interface Comparer2 { + compare: (a: T, b: T) => number; +} + +declare let animalComparer2: Comparer2; +declare let dogComparer2: Comparer2; + +animalComparer2 = dogComparer2; // Error +dogComparer2 = animalComparer2; // Ok + + +//// [strictFunctionTypesErrors.js] +"use strict"; +exports.__esModule = true; +f1 = f2; // Ok +f1 = f3; // Error +f1 = f4; // Error +f2 = f1; // Error +f2 = f3; // Error +f2 = f4; // Error +f3 = f1; // Ok +f3 = f2; // Ok +f3 = f4; // Ok +f4 = f1; // Error +f4 = f2; // Ok +f4 = f3; // Error +g1 = g2; // Ok +g1 = g3; // Error +g1 = g4; // Error +g2 = g1; // Error +g2 = g3; // Error +g2 = g4; // Error +g3 = g1; // Ok +g3 = g2; // Ok +g3 = g4; // Ok +g4 = g1; // Error +g4 = g2; // Ok +g4 = g3; // Error +h1 = h2; // Ok +h1 = h3; // Ok +h1 = h4; // Ok +h2 = h1; // Error +h2 = h3; // Error +h2 = h4; // Ok +h3 = h1; // Error +h3 = h2; // Error +h3 = h4; // Ok +h4 = h1; // Error +h4 = h2; // Error +h4 = h3; // Error +i1 = i2; // Error +i1 = i3; // Error +i1 = i4; // Error +i2 = i1; // Ok +i2 = i3; // Error +i2 = i4; // Error +i3 = i1; // Ok +i3 = i2; // Error +i3 = i4; // Error +i4 = i1; // Ok +i4 = i2; // Ok +i4 = i3; // Ok +animalComparer1 = dogComparer1; // Ok +dogComparer1 = animalComparer1; // Ok +animalComparer2 = dogComparer2; // Error +dogComparer2 = animalComparer2; // Ok diff --git a/tests/cases/compiler/strictFunctionTypes1.ts b/tests/cases/compiler/strictFunctionTypes1.ts new file mode 100644 index 0000000000000..7d8ffc689ff3d --- /dev/null +++ b/tests/cases/compiler/strictFunctionTypes1.ts @@ -0,0 +1,18 @@ +// @strict: true + +declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; +declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; +declare function f3(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T; + +interface Func { (x: T): void } + +declare function f4(f1: Func, f2: Func): Func; + +declare function fo(x: Object): void; +declare function fs(x: string): void; +declare function fx(f: (x: "def") => void): void; + +const x1 = f1(fo, fs); // (x: string) => void +const x2 = f2("abc", fo, fs); // "abc" +const x3 = f3("abc", fo, fx); // "abc" | "def" +const x4 = f4(fo, fs); // Func diff --git a/tests/cases/compiler/strictFunctionTypesErrors.ts b/tests/cases/compiler/strictFunctionTypesErrors.ts new file mode 100644 index 0000000000000..5c6909e68060e --- /dev/null +++ b/tests/cases/compiler/strictFunctionTypesErrors.ts @@ -0,0 +1,113 @@ +export {} + +// @strict: true + +declare let f1: (x: Object) => Object; +declare let f2: (x: Object) => string; +declare let f3: (x: string) => Object; +declare let f4: (x: string) => string; + +f1 = f2; // Ok +f1 = f3; // Error +f1 = f4; // Error + +f2 = f1; // Error +f2 = f3; // Error +f2 = f4; // Error + +f3 = f1; // Ok +f3 = f2; // Ok +f3 = f4; // Ok + +f4 = f1; // Error +f4 = f2; // Ok +f4 = f3; // Error + +interface Func { (x: T): U } + +declare let g1: Func; +declare let g2: Func; +declare let g3: Func; +declare let g4: Func; + +g1 = g2; // Ok +g1 = g3; // Error +g1 = g4; // Error + +g2 = g1; // Error +g2 = g3; // Error +g2 = g4; // Error + +g3 = g1; // Ok +g3 = g2; // Ok +g3 = g4; // Ok + +g4 = g1; // Error +g4 = g2; // Ok +g4 = g3; // Error + +declare let h1: Func, Object>; +declare let h2: Func, string>; +declare let h3: Func, Object>; +declare let h4: Func, string>; + +h1 = h2; // Ok +h1 = h3; // Ok +h1 = h4; // Ok + +h2 = h1; // Error +h2 = h3; // Error +h2 = h4; // Ok + +h3 = h1; // Error +h3 = h2; // Error +h3 = h4; // Ok + +h4 = h1; // Error +h4 = h2; // Error +h4 = h3; // Error + +declare let i1: Func>; +declare let i2: Func>; +declare let i3: Func>; +declare let i4: Func>; + +i1 = i2; // Error +i1 = i3; // Error +i1 = i4; // Error + +i2 = i1; // Ok +i2 = i3; // Error +i2 = i4; // Error + +i3 = i1; // Ok +i3 = i2; // Error +i3 = i4; // Error + +i4 = i1; // Ok +i4 = i2; // Ok +i4 = i3; // Ok + +interface Animal { animal: void } +interface Dog extends Animal { dog: void } +interface Cat extends Animal { cat: void } + +interface Comparer1 { + compare(a: T, b: T): number; +} + +declare let animalComparer1: Comparer1; +declare let dogComparer1: Comparer1; + +animalComparer1 = dogComparer1; // Ok +dogComparer1 = animalComparer1; // Ok + +interface Comparer2 { + compare: (a: T, b: T) => number; +} + +declare let animalComparer2: Comparer2; +declare let dogComparer2: Comparer2; + +animalComparer2 = dogComparer2; // Error +dogComparer2 = animalComparer2; // Ok From 91691f6079edaf77dce77df5e0c0d1176bc0a7b8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 25 Sep 2017 16:59:18 -0700 Subject: [PATCH 15/24] Strict function type checking only for certain function types --- src/compiler/checker.ts | 120 +++++++++++++++++++++++++++++----------- src/compiler/types.ts | 2 + 2 files changed, 91 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25dc303055684..5d3957652d8f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -285,6 +285,7 @@ namespace ts { const markerSuperType = createType(TypeFlags.TypeParameter); const markerSubType = createType(TypeFlags.TypeParameter); markerSubType.constraint = markerSuperType; + const markerOtherType = createType(TypeFlags.TypeParameter); const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -3548,7 +3549,7 @@ namespace ts { return; } - if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { + if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length && isStrictSignature(resolved.callSignatures[0])) { const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags); if (parenthesizeSignature) { writePunctuation(writer, SyntaxKind.OpenParenToken); @@ -3559,7 +3560,7 @@ namespace ts { } return; } - if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { + if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length && isStrictSignature(resolved.constructSignatures[0])) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } @@ -8521,6 +8522,17 @@ namespace ts { /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False; } + // A signature is considered strict if it is declared in a function type literal, a constructor type + // literal, a function expression, an arrow function, or a function declaration with no overloads. A + // strict signature is subject to strict checking in strictFunctionTypes mode. + function isStrictSignature(signature: Signature) { + const declaration = signature.declaration; + const kind = declaration ? declaration.kind : SyntaxKind.Unknown; + return kind === SyntaxKind.FunctionType || kind === SyntaxKind.ConstructorType || + kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction || + (kind === SyntaxKind.FunctionDeclaration && getSingleCallSignature(getTypeOfSymbol(getSymbolOfNode(declaration)))); + } + type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; /** @@ -8546,9 +8558,7 @@ namespace ts { source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } - const targetKind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - const strictVariance = strictFunctionTypes && targetKind !== SyntaxKind.MethodDeclaration && targetKind !== SyntaxKind.MethodSignature; - + const strictVariance = strictFunctionTypes && isStrictSignature(target); let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -9215,15 +9225,41 @@ namespace ts { // in the process of computing variance information for recursive types and when // comparing 'this' type arguments. const variance = i < variances.length ? variances[i] : Variance.Covariant; - const s = sources[i]; - const t = targets[i]; - const related = variance === Variance.Covariant ? isRelatedTo(s, t, reportErrors) : - variance === Variance.Contravariant ? isRelatedTo(t, s, reportErrors) : - Ternary.False; - if (!related) { - return Ternary.False; + // We ignore arguments for independent type parameters (because they're never witnessed). + if (variance !== Variance.Independent) { + const s = sources[i]; + const t = targets[i]; + let related = Ternary.True; + if (variance === Variance.Covariant) { + related = isRelatedTo(s, t, reportErrors); + } + else if (variance === Variance.Contravariant) { + related = isRelatedTo(t, s, reportErrors); + } + else if (variance === Variance.Bivariant) { + // In the bivariant case we first compare contravariantly without reporting + // errors. Then, if that doesn't succeed, we compare covariantly with error + // reporting. Thus, error elaboration will be based on the the covariant check, + // which is generally easier to reason about. + related = isRelatedTo(t, s, /*reportErrors*/ false); + if (!related) { + related = isRelatedTo(s, t, reportErrors); + } + } + else { + // In the invariant case we first compare covariantly, and only when that + // succeeds do we proceed to compare contravariantly. Thus, error elaboration + // will typically be based on the covariant check. + related = isRelatedTo(s, t, reportErrors); + if (related) { + related &= isRelatedTo(t, s, reportErrors); + } + } + if (!related) { + return Ternary.False; + } + result &= related; } - result &= related; } return result; } @@ -9388,14 +9424,21 @@ namespace ts { !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance - // information for the type parameters and relate the type arguments accordingly. If we do - // not succeed, fall through and do a structural comparison instead (there are instances - // where the variance information isn't accurate, e.g. when type parameters are used only - // in bivariant positions or when a type argument is 'any' or 'void'.) + // information for the type parameters and relate the type arguments accordingly. const variances = getVariances((source).target); if (result = typeArgumentsRelatedTo(source, target, variances, reportErrors)) { return result; } + // The type arguments did not relate appropriately, but it may be because we have no variance + // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type + // arguments). It might also be the case that the target type has a 'void' type argument for + // a covariant type parameter that is only used in return positions within the generic type + // (in which case any type argument is permitted on the source side). In those cases we proceed + // with a structural comparison. Otherwise, we know for certain the instantiations aren't + // related and we can return here. + if (variances !== emptyArray && !hasCovariantVoidArgument(target, variances)) { + return Ternary.False; + } } // Even if relationship doesn't hold for unions, intersections, or generic type references, // it may hold in a structural comparison. @@ -9814,14 +9857,12 @@ namespace ts { return result; } - // Return an array containing the variance of each type parameter. The variance information is - // computed by comparing instantiations of the generic type for type arguments with known relations. - // A type parameter is marked as covariant if a covariant comparison succeeds; otherwise, it is - // marked contravariant if a contravarint comparison succeeds; otherwise, it is marked invariant. - // One form of variance doesn't exclude another, so this information simply serves to indicate - // a "primary" relationship that can be checked as an optimization ahead of a full structural - // comparison. The function returns the emptyArray singleton if we're not in strictFunctionTypes - // mode or if the function has been invoked recursively for the given generic type. + // Return an array containing the variance of each type parameter. The variance is effectively + // a digest of the type comparisons that occur for each type argument when instantiations of the + // generic type are structurally compared. We infer the variance information by comparing + // instantiations of the generic type for type arguments with known relations. The function + // returns the emptyArray singleton if we're not in strictFunctionTypes mode or if the function + // has been invoked recursively for the given generic type. function getVariances(type: GenericType): Variance[] { if (!strictFunctionTypes) { return emptyArray; @@ -9838,14 +9879,20 @@ namespace ts { type.variances = emptyArray; variances = []; for (const tp of typeParameters) { - // We compare instantiations where the type parameter is replaced with marker types - // that have a known subtype relationship. From this we infer covariance, contravariance - // or invariance. + // We first compare instantiations where the type parameter is replaced with + // marker types that have a known subtype relationship. From this we can infer + // invariance, covariance, contravariance or bivariance. const typeWithSuper = getMarkerTypeReference(type, tp, markerSuperType); const typeWithSub = getMarkerTypeReference(type, tp, markerSubType); - const variance = isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : - isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : - Variance.Invariant; + let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : 0) | + (isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : 0); + // If the instantiations appear to be related bivariantly it may be because the + // type parameter is independent (i.e. it isn't witnessed anywhere in the generic + // type). To determine this we compare instantiations where the type parameter is + // replaced with marker types that are known to be unrelated. + if (variance === Variance.Bivariant && isTypeAssignableTo(getMarkerTypeReference(type, tp, markerOtherType), typeWithSuper)) { + variance = Variance.Independent; + } variances.push(variance); } } @@ -9854,6 +9901,17 @@ namespace ts { return variances; } + // Return true if the given type reference has a 'void' type argument for a covariant type parameter. + // See comment at call in recursiveTypeRelatedTo for when this case matters. + function hasCovariantVoidArgument(type: TypeReference, variances: Variance[]): boolean { + for (let i = 0; i < variances.length; i++) { + if (variances[i] === Variance.Covariant && type.typeArguments[i].flags & TypeFlags.Void) { + return true; + } + } + return false; + } + function isUnconstrainedTypeParameter(type: Type) { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8ab999032bc79..a867d9ebe2a09 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3348,6 +3348,8 @@ namespace ts { Invariant = 0, // Neither covariant nor contravariant Covariant = 1, // Covariant Contravariant = 2, // Contravariant + Bivariant = 3, // Both covariant and contravariant + Independent = 4, // Unwitnessed type parameter } // Generic class and interface types From 6a481e8ddc1431924b67c7d17216f3d96d0b7db7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 25 Sep 2017 16:59:39 -0700 Subject: [PATCH 16/24] Update tests --- .../strictFunctionTypesErrors.errors.txt | 90 +++++++++++++------ .../reference/strictFunctionTypesErrors.js | 2 +- .../compiler/strictFunctionTypesErrors.ts | 2 +- 3 files changed, 65 insertions(+), 29 deletions(-) diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt index 3ff71ea26e7ff..eb0c2d00233cd 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -17,15 +17,19 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(21,1): error TS2322: Type '(x: tests/cases/compiler/strictFunctionTypesErrors.ts(23,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(33,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(34,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(36,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(37,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(38,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(44,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(46,1): error TS2322: Type 'Func' is not assignable to type 'Func'. @@ -35,32 +39,46 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(57,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(58,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(61,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. - Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(62,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(65,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(66,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(67,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(74,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(75,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(76,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(79,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(80,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(83,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. Type 'Animal' is not assignable to type 'Dog'. + Property 'dog' is missing in type 'Animal'. ==== tests/cases/compiler/strictFunctionTypesErrors.ts (29 errors) ==== @@ -113,7 +131,7 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co !!! error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. !!! error TS2322: Type 'Object' is not assignable to type 'string'. - interface Func { (x: T): U } + type Func = (x: T) => U; declare let g1: Func; declare let g2: Func; @@ -124,11 +142,13 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co g1 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g1 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g1; // Error ~~ @@ -137,11 +157,13 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co g2 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g3 = g1; // Ok g3 = g2; // Ok @@ -179,22 +201,29 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co h3 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h3 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h3 = h4; // Ok h4 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h4 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h4 = h3; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. @@ -209,24 +238,30 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. !!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i1; // Ok i2 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i3 = i1; // Ok i3 = i2; // Error @@ -267,5 +302,6 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co ~~~~~~~~~~~~~~~ !!! error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. !!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. +!!! error TS2322: Property 'dog' is missing in type 'Animal'. dogComparer2 = animalComparer2; // Ok \ No newline at end of file diff --git a/tests/baselines/reference/strictFunctionTypesErrors.js b/tests/baselines/reference/strictFunctionTypesErrors.js index af41c9395f91a..0049fe970ce65 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.js +++ b/tests/baselines/reference/strictFunctionTypesErrors.js @@ -23,7 +23,7 @@ f4 = f1; // Error f4 = f2; // Ok f4 = f3; // Error -interface Func { (x: T): U } +type Func = (x: T) => U; declare let g1: Func; declare let g2: Func; diff --git a/tests/cases/compiler/strictFunctionTypesErrors.ts b/tests/cases/compiler/strictFunctionTypesErrors.ts index 5c6909e68060e..32029364d76a0 100644 --- a/tests/cases/compiler/strictFunctionTypesErrors.ts +++ b/tests/cases/compiler/strictFunctionTypesErrors.ts @@ -23,7 +23,7 @@ f4 = f1; // Error f4 = f2; // Ok f4 = f3; // Error -interface Func { (x: T): U } +type Func = (x: T) => U; declare let g1: Func; declare let g2: Func; From 1795614c415264834b1b8552d1fac5607ed7dda0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 25 Sep 2017 17:06:09 -0700 Subject: [PATCH 17/24] Accept new baselines --- .../reference/commentsClassMembers.js | 8 +++-- .../baselines/reference/commentsInterface.js | 8 +++-- tests/baselines/reference/jsDocTypeTag2.js | 30 +++++++++++++++---- .../typeGuardFunctionOfFormThisErrors.js | 4 ++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/commentsClassMembers.js b/tests/baselines/reference/commentsClassMembers.js index f53c64060a3d0..d5cee0e195007 100644 --- a/tests/baselines/reference/commentsClassMembers.js +++ b/tests/baselines/reference/commentsClassMembers.js @@ -548,11 +548,15 @@ declare class c1 { } declare var i1: c1; declare var i1_p: number; -declare var i1_f: (b: number) => number; +declare var i1_f: { + (b: number): number; +}; declare var i1_r: number; declare var i1_prop: number; declare var i1_nc_p: number; -declare var i1_ncf: (b: number) => number; +declare var i1_ncf: { + (b: number): number; +}; declare var i1_ncr: number; declare var i1_ncprop: number; declare var i1_s_p: number; diff --git a/tests/baselines/reference/commentsInterface.js b/tests/baselines/reference/commentsInterface.js index 3deac9871f183..b7ceffa58afa5 100644 --- a/tests/baselines/reference/commentsInterface.js +++ b/tests/baselines/reference/commentsInterface.js @@ -142,9 +142,13 @@ declare var i2_i_nc_x: number; declare var i2_i_nc_foo: (b: number) => string; declare var i2_i_nc_foo_r: string; declare var i2_i_r: number; -declare var i2_i_fnfoo: (b: number) => string; +declare var i2_i_fnfoo: { + (b: number): string; +}; declare var i2_i_fnfoo_r: string; -declare var i2_i_nc_fnfoo: (b: number) => string; +declare var i2_i_nc_fnfoo: { + (b: number): string; +}; declare var i2_i_nc_fnfoo_r: string; interface i3 { /** Comment i3 x*/ diff --git a/tests/baselines/reference/jsDocTypeTag2.js b/tests/baselines/reference/jsDocTypeTag2.js index d54b4557f06ea..bde3f3f9c1e60 100644 --- a/tests/baselines/reference/jsDocTypeTag2.js +++ b/tests/baselines/reference/jsDocTypeTag2.js @@ -472,6 +472,18 @@ "text": " ", "kind": "space" }, + { + "text": "{", + "kind": "punctuation" + }, + { + "text": "\n", + "kind": "lineBreak" + }, + { + "text": " ", + "kind": "space" + }, { "text": "(", "kind": "punctuation" @@ -497,11 +509,7 @@ "kind": "punctuation" }, { - "text": " ", - "kind": "space" - }, - { - "text": "=>", + "text": ":", "kind": "punctuation" }, { @@ -511,6 +519,18 @@ { "text": "number", "kind": "keyword" + }, + { + "text": ";", + "kind": "punctuation" + }, + { + "text": "\n", + "kind": "lineBreak" + }, + { + "text": "}", + "kind": "punctuation" } ], "documentation": [], diff --git a/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js b/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js index 84db5d4a4a9c6..6ba90de54f1c3 100644 --- a/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js +++ b/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js @@ -154,4 +154,6 @@ declare let c: number | number[]; declare let holder: { invalidGuard: (c: any) => this is number; }; -declare let detached: () => this is FollowerGuard; +declare let detached: { + (): this is FollowerGuard; +}; From 5613be4907aab27f2669658570f17a1e64ecccce Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 28 Sep 2017 14:33:35 -0700 Subject: [PATCH 18/24] Only methods and constructors are bivariant in --strictFunctionTypes mode --- src/compiler/checker.ts | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d3957652d8f3..ceb9d70847f35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3549,7 +3549,7 @@ namespace ts { return; } - if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length && isStrictSignature(resolved.callSignatures[0])) { + if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags); if (parenthesizeSignature) { writePunctuation(writer, SyntaxKind.OpenParenToken); @@ -3560,7 +3560,7 @@ namespace ts { } return; } - if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length && isStrictSignature(resolved.constructSignatures[0])) { + if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } @@ -8522,17 +8522,6 @@ namespace ts { /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False; } - // A signature is considered strict if it is declared in a function type literal, a constructor type - // literal, a function expression, an arrow function, or a function declaration with no overloads. A - // strict signature is subject to strict checking in strictFunctionTypes mode. - function isStrictSignature(signature: Signature) { - const declaration = signature.declaration; - const kind = declaration ? declaration.kind : SyntaxKind.Unknown; - return kind === SyntaxKind.FunctionType || kind === SyntaxKind.ConstructorType || - kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction || - (kind === SyntaxKind.FunctionDeclaration && getSingleCallSignature(getTypeOfSymbol(getSymbolOfNode(declaration)))); - } - type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; /** @@ -8558,7 +8547,9 @@ namespace ts { source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } - const strictVariance = strictFunctionTypes && isStrictSignature(target); + const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; + const strictVariance = strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && + kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); From 1609196b22a4590039da899b57cabdc5ef7869ce Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 28 Sep 2017 14:34:03 -0700 Subject: [PATCH 19/24] Accept new baselines --- .../reference/commentsClassMembers.js | 8 ++--- .../baselines/reference/commentsInterface.js | 8 ++--- tests/baselines/reference/jsDocTypeTag2.js | 30 ++++--------------- .../typeGuardFunctionOfFormThisErrors.js | 4 +-- 4 files changed, 10 insertions(+), 40 deletions(-) diff --git a/tests/baselines/reference/commentsClassMembers.js b/tests/baselines/reference/commentsClassMembers.js index d5cee0e195007..f53c64060a3d0 100644 --- a/tests/baselines/reference/commentsClassMembers.js +++ b/tests/baselines/reference/commentsClassMembers.js @@ -548,15 +548,11 @@ declare class c1 { } declare var i1: c1; declare var i1_p: number; -declare var i1_f: { - (b: number): number; -}; +declare var i1_f: (b: number) => number; declare var i1_r: number; declare var i1_prop: number; declare var i1_nc_p: number; -declare var i1_ncf: { - (b: number): number; -}; +declare var i1_ncf: (b: number) => number; declare var i1_ncr: number; declare var i1_ncprop: number; declare var i1_s_p: number; diff --git a/tests/baselines/reference/commentsInterface.js b/tests/baselines/reference/commentsInterface.js index b7ceffa58afa5..3deac9871f183 100644 --- a/tests/baselines/reference/commentsInterface.js +++ b/tests/baselines/reference/commentsInterface.js @@ -142,13 +142,9 @@ declare var i2_i_nc_x: number; declare var i2_i_nc_foo: (b: number) => string; declare var i2_i_nc_foo_r: string; declare var i2_i_r: number; -declare var i2_i_fnfoo: { - (b: number): string; -}; +declare var i2_i_fnfoo: (b: number) => string; declare var i2_i_fnfoo_r: string; -declare var i2_i_nc_fnfoo: { - (b: number): string; -}; +declare var i2_i_nc_fnfoo: (b: number) => string; declare var i2_i_nc_fnfoo_r: string; interface i3 { /** Comment i3 x*/ diff --git a/tests/baselines/reference/jsDocTypeTag2.js b/tests/baselines/reference/jsDocTypeTag2.js index bde3f3f9c1e60..d54b4557f06ea 100644 --- a/tests/baselines/reference/jsDocTypeTag2.js +++ b/tests/baselines/reference/jsDocTypeTag2.js @@ -472,18 +472,6 @@ "text": " ", "kind": "space" }, - { - "text": "{", - "kind": "punctuation" - }, - { - "text": "\n", - "kind": "lineBreak" - }, - { - "text": " ", - "kind": "space" - }, { "text": "(", "kind": "punctuation" @@ -508,29 +496,21 @@ "text": ")", "kind": "punctuation" }, - { - "text": ":", - "kind": "punctuation" - }, { "text": " ", "kind": "space" }, { - "text": "number", - "kind": "keyword" - }, - { - "text": ";", + "text": "=>", "kind": "punctuation" }, { - "text": "\n", - "kind": "lineBreak" + "text": " ", + "kind": "space" }, { - "text": "}", - "kind": "punctuation" + "text": "number", + "kind": "keyword" } ], "documentation": [], diff --git a/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js b/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js index 6ba90de54f1c3..84db5d4a4a9c6 100644 --- a/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js +++ b/tests/baselines/reference/typeGuardFunctionOfFormThisErrors.js @@ -154,6 +154,4 @@ declare let c: number | number[]; declare let holder: { invalidGuard: (c: any) => this is number; }; -declare let detached: { - (): this is FollowerGuard; -}; +declare let detached: () => this is FollowerGuard; From c626d9d47cc8e070a7d92ece1e39aacdaf80f425 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 28 Sep 2017 15:44:17 -0700 Subject: [PATCH 20/24] Accept new baselines --- .../strictFunctionTypesErrors.symbols | 366 +++++++++++++++ .../reference/strictFunctionTypesErrors.types | 418 ++++++++++++++++++ 2 files changed, 784 insertions(+) create mode 100644 tests/baselines/reference/strictFunctionTypesErrors.symbols create mode 100644 tests/baselines/reference/strictFunctionTypesErrors.types diff --git a/tests/baselines/reference/strictFunctionTypesErrors.symbols b/tests/baselines/reference/strictFunctionTypesErrors.symbols new file mode 100644 index 0000000000000..ce3a81f524f8a --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypesErrors.symbols @@ -0,0 +1,366 @@ +=== tests/cases/compiler/strictFunctionTypesErrors.ts === +export {} + + +declare let f1: (x: Object) => Object; +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) +>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 3, 17)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let f2: (x: Object) => string; +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) +>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 4, 17)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let f3: (x: string) => Object; +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) +>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 5, 17)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let f4: (x: string) => string; +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) +>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 6, 17)) + +f1 = f2; // Ok +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) + +f1 = f3; // Error +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) + +f1 = f4; // Error +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) + +f2 = f1; // Error +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) + +f2 = f3; // Error +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) + +f2 = f4; // Error +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) + +f3 = f1; // Ok +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) + +f3 = f2; // Ok +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) + +f3 = f4; // Ok +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) + +f4 = f1; // Error +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) +>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 3, 11)) + +f4 = f2; // Ok +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) +>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 4, 11)) + +f4 = f3; // Error +>f4 : Symbol(f4, Decl(strictFunctionTypesErrors.ts, 6, 11)) +>f3 : Symbol(f3, Decl(strictFunctionTypesErrors.ts, 5, 11)) + +type Func = (x: T) => U; +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 24, 10)) +>U : Symbol(U, Decl(strictFunctionTypesErrors.ts, 24, 12)) +>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 24, 19)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 24, 10)) +>U : Symbol(U, Decl(strictFunctionTypesErrors.ts, 24, 12)) + +declare let g1: Func; +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let g2: Func; +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let g3: Func; +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let g4: Func; +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) + +g1 = g2; // Ok +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) + +g1 = g3; // Error +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) + +g1 = g4; // Error +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) + +g2 = g1; // Error +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) + +g2 = g3; // Error +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) + +g2 = g4; // Error +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) + +g3 = g1; // Ok +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) + +g3 = g2; // Ok +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) + +g3 = g4; // Ok +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) + +g4 = g1; // Error +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) +>g1 : Symbol(g1, Decl(strictFunctionTypesErrors.ts, 26, 11)) + +g4 = g2; // Ok +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) +>g2 : Symbol(g2, Decl(strictFunctionTypesErrors.ts, 27, 11)) + +g4 = g3; // Error +>g4 : Symbol(g4, Decl(strictFunctionTypesErrors.ts, 29, 11)) +>g3 : Symbol(g3, Decl(strictFunctionTypesErrors.ts, 28, 11)) + +declare let h1: Func, Object>; +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let h2: Func, string>; +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let h3: Func, Object>; +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let h4: Func, string>; +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) + +h1 = h2; // Ok +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) + +h1 = h3; // Ok +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) + +h1 = h4; // Ok +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) + +h2 = h1; // Error +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) + +h2 = h3; // Error +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) + +h2 = h4; // Ok +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) + +h3 = h1; // Error +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) + +h3 = h2; // Error +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) + +h3 = h4; // Ok +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) + +h4 = h1; // Error +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) +>h1 : Symbol(h1, Decl(strictFunctionTypesErrors.ts, 47, 11)) + +h4 = h2; // Error +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) +>h2 : Symbol(h2, Decl(strictFunctionTypesErrors.ts, 48, 11)) + +h4 = h3; // Error +>h4 : Symbol(h4, Decl(strictFunctionTypesErrors.ts, 50, 11)) +>h3 : Symbol(h3, Decl(strictFunctionTypesErrors.ts, 49, 11)) + +declare let i1: Func>; +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let i2: Func>; +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) + +declare let i3: Func>; +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +declare let i4: Func>; +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) +>Func : Symbol(Func, Decl(strictFunctionTypesErrors.ts, 22, 8)) + +i1 = i2; // Error +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) + +i1 = i3; // Error +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) + +i1 = i4; // Error +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) + +i2 = i1; // Ok +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) + +i2 = i3; // Error +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) + +i2 = i4; // Error +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) + +i3 = i1; // Ok +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) + +i3 = i2; // Error +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) + +i3 = i4; // Error +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) + +i4 = i1; // Ok +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) +>i1 : Symbol(i1, Decl(strictFunctionTypesErrors.ts, 68, 11)) + +i4 = i2; // Ok +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) +>i2 : Symbol(i2, Decl(strictFunctionTypesErrors.ts, 69, 11)) + +i4 = i3; // Ok +>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11)) +>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11)) + +interface Animal { animal: void } +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) +>animal : Symbol(Animal.animal, Decl(strictFunctionTypesErrors.ts, 89, 18)) + +interface Dog extends Animal { dog: void } +>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33)) +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) +>dog : Symbol(Dog.dog, Decl(strictFunctionTypesErrors.ts, 90, 30)) + +interface Cat extends Animal { cat: void } +>Cat : Symbol(Cat, Decl(strictFunctionTypesErrors.ts, 90, 42)) +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) +>cat : Symbol(Cat.cat, Decl(strictFunctionTypesErrors.ts, 91, 30)) + +interface Comparer1 { +>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 93, 20)) + + compare(a: T, b: T): number; +>compare : Symbol(Comparer1.compare, Decl(strictFunctionTypesErrors.ts, 93, 24)) +>a : Symbol(a, Decl(strictFunctionTypesErrors.ts, 94, 12)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 93, 20)) +>b : Symbol(b, Decl(strictFunctionTypesErrors.ts, 94, 17)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 93, 20)) +} + +declare let animalComparer1: Comparer1; +>animalComparer1 : Symbol(animalComparer1, Decl(strictFunctionTypesErrors.ts, 97, 11)) +>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42)) +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) + +declare let dogComparer1: Comparer1; +>dogComparer1 : Symbol(dogComparer1, Decl(strictFunctionTypesErrors.ts, 98, 11)) +>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42)) +>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33)) + +animalComparer1 = dogComparer1; // Ok +>animalComparer1 : Symbol(animalComparer1, Decl(strictFunctionTypesErrors.ts, 97, 11)) +>dogComparer1 : Symbol(dogComparer1, Decl(strictFunctionTypesErrors.ts, 98, 11)) + +dogComparer1 = animalComparer1; // Ok +>dogComparer1 : Symbol(dogComparer1, Decl(strictFunctionTypesErrors.ts, 98, 11)) +>animalComparer1 : Symbol(animalComparer1, Decl(strictFunctionTypesErrors.ts, 97, 11)) + +interface Comparer2 { +>Comparer2 : Symbol(Comparer2, Decl(strictFunctionTypesErrors.ts, 101, 31)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 103, 20)) + + compare: (a: T, b: T) => number; +>compare : Symbol(Comparer2.compare, Decl(strictFunctionTypesErrors.ts, 103, 24)) +>a : Symbol(a, Decl(strictFunctionTypesErrors.ts, 104, 14)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 103, 20)) +>b : Symbol(b, Decl(strictFunctionTypesErrors.ts, 104, 19)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 103, 20)) +} + +declare let animalComparer2: Comparer2; +>animalComparer2 : Symbol(animalComparer2, Decl(strictFunctionTypesErrors.ts, 107, 11)) +>Comparer2 : Symbol(Comparer2, Decl(strictFunctionTypesErrors.ts, 101, 31)) +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) + +declare let dogComparer2: Comparer2; +>dogComparer2 : Symbol(dogComparer2, Decl(strictFunctionTypesErrors.ts, 108, 11)) +>Comparer2 : Symbol(Comparer2, Decl(strictFunctionTypesErrors.ts, 101, 31)) +>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33)) + +animalComparer2 = dogComparer2; // Error +>animalComparer2 : Symbol(animalComparer2, Decl(strictFunctionTypesErrors.ts, 107, 11)) +>dogComparer2 : Symbol(dogComparer2, Decl(strictFunctionTypesErrors.ts, 108, 11)) + +dogComparer2 = animalComparer2; // Ok +>dogComparer2 : Symbol(dogComparer2, Decl(strictFunctionTypesErrors.ts, 108, 11)) +>animalComparer2 : Symbol(animalComparer2, Decl(strictFunctionTypesErrors.ts, 107, 11)) + diff --git a/tests/baselines/reference/strictFunctionTypesErrors.types b/tests/baselines/reference/strictFunctionTypesErrors.types new file mode 100644 index 0000000000000..f2d3b52a5b9b0 --- /dev/null +++ b/tests/baselines/reference/strictFunctionTypesErrors.types @@ -0,0 +1,418 @@ +=== tests/cases/compiler/strictFunctionTypesErrors.ts === +export {} + + +declare let f1: (x: Object) => Object; +>f1 : (x: Object) => Object +>x : Object +>Object : Object +>Object : Object + +declare let f2: (x: Object) => string; +>f2 : (x: Object) => string +>x : Object +>Object : Object + +declare let f3: (x: string) => Object; +>f3 : (x: string) => Object +>x : string +>Object : Object + +declare let f4: (x: string) => string; +>f4 : (x: string) => string +>x : string + +f1 = f2; // Ok +>f1 = f2 : (x: Object) => string +>f1 : (x: Object) => Object +>f2 : (x: Object) => string + +f1 = f3; // Error +>f1 = f3 : (x: string) => Object +>f1 : (x: Object) => Object +>f3 : (x: string) => Object + +f1 = f4; // Error +>f1 = f4 : (x: string) => string +>f1 : (x: Object) => Object +>f4 : (x: string) => string + +f2 = f1; // Error +>f2 = f1 : (x: Object) => Object +>f2 : (x: Object) => string +>f1 : (x: Object) => Object + +f2 = f3; // Error +>f2 = f3 : (x: string) => Object +>f2 : (x: Object) => string +>f3 : (x: string) => Object + +f2 = f4; // Error +>f2 = f4 : (x: string) => string +>f2 : (x: Object) => string +>f4 : (x: string) => string + +f3 = f1; // Ok +>f3 = f1 : (x: Object) => Object +>f3 : (x: string) => Object +>f1 : (x: Object) => Object + +f3 = f2; // Ok +>f3 = f2 : (x: Object) => string +>f3 : (x: string) => Object +>f2 : (x: Object) => string + +f3 = f4; // Ok +>f3 = f4 : (x: string) => string +>f3 : (x: string) => Object +>f4 : (x: string) => string + +f4 = f1; // Error +>f4 = f1 : (x: Object) => Object +>f4 : (x: string) => string +>f1 : (x: Object) => Object + +f4 = f2; // Ok +>f4 = f2 : (x: Object) => string +>f4 : (x: string) => string +>f2 : (x: Object) => string + +f4 = f3; // Error +>f4 = f3 : (x: string) => Object +>f4 : (x: string) => string +>f3 : (x: string) => Object + +type Func = (x: T) => U; +>Func : (x: T) => U +>T : T +>U : U +>x : T +>T : T +>U : U + +declare let g1: Func; +>g1 : (x: Object) => Object +>Func : (x: T) => U +>Object : Object +>Object : Object + +declare let g2: Func; +>g2 : (x: Object) => string +>Func : (x: T) => U +>Object : Object + +declare let g3: Func; +>g3 : (x: string) => Object +>Func : (x: T) => U +>Object : Object + +declare let g4: Func; +>g4 : (x: string) => string +>Func : (x: T) => U + +g1 = g2; // Ok +>g1 = g2 : (x: Object) => string +>g1 : (x: Object) => Object +>g2 : (x: Object) => string + +g1 = g3; // Error +>g1 = g3 : (x: string) => Object +>g1 : (x: Object) => Object +>g3 : (x: string) => Object + +g1 = g4; // Error +>g1 = g4 : (x: string) => string +>g1 : (x: Object) => Object +>g4 : (x: string) => string + +g2 = g1; // Error +>g2 = g1 : (x: Object) => Object +>g2 : (x: Object) => string +>g1 : (x: Object) => Object + +g2 = g3; // Error +>g2 = g3 : (x: string) => Object +>g2 : (x: Object) => string +>g3 : (x: string) => Object + +g2 = g4; // Error +>g2 = g4 : (x: string) => string +>g2 : (x: Object) => string +>g4 : (x: string) => string + +g3 = g1; // Ok +>g3 = g1 : (x: Object) => Object +>g3 : (x: string) => Object +>g1 : (x: Object) => Object + +g3 = g2; // Ok +>g3 = g2 : (x: Object) => string +>g3 : (x: string) => Object +>g2 : (x: Object) => string + +g3 = g4; // Ok +>g3 = g4 : (x: string) => string +>g3 : (x: string) => Object +>g4 : (x: string) => string + +g4 = g1; // Error +>g4 = g1 : (x: Object) => Object +>g4 : (x: string) => string +>g1 : (x: Object) => Object + +g4 = g2; // Ok +>g4 = g2 : (x: Object) => string +>g4 : (x: string) => string +>g2 : (x: Object) => string + +g4 = g3; // Error +>g4 = g3 : (x: string) => Object +>g4 : (x: string) => string +>g3 : (x: string) => Object + +declare let h1: Func, Object>; +>h1 : (x: Func) => Object +>Func : (x: T) => U +>Func : (x: T) => U +>Object : Object +>Object : Object + +declare let h2: Func, string>; +>h2 : (x: Func) => string +>Func : (x: T) => U +>Func : (x: T) => U +>Object : Object + +declare let h3: Func, Object>; +>h3 : (x: Func) => Object +>Func : (x: T) => U +>Func : (x: T) => U +>Object : Object + +declare let h4: Func, string>; +>h4 : (x: Func) => string +>Func : (x: T) => U +>Func : (x: T) => U + +h1 = h2; // Ok +>h1 = h2 : (x: Func) => string +>h1 : (x: Func) => Object +>h2 : (x: Func) => string + +h1 = h3; // Ok +>h1 = h3 : (x: Func) => Object +>h1 : (x: Func) => Object +>h3 : (x: Func) => Object + +h1 = h4; // Ok +>h1 = h4 : (x: Func) => string +>h1 : (x: Func) => Object +>h4 : (x: Func) => string + +h2 = h1; // Error +>h2 = h1 : (x: Func) => Object +>h2 : (x: Func) => string +>h1 : (x: Func) => Object + +h2 = h3; // Error +>h2 = h3 : (x: Func) => Object +>h2 : (x: Func) => string +>h3 : (x: Func) => Object + +h2 = h4; // Ok +>h2 = h4 : (x: Func) => string +>h2 : (x: Func) => string +>h4 : (x: Func) => string + +h3 = h1; // Error +>h3 = h1 : (x: Func) => Object +>h3 : (x: Func) => Object +>h1 : (x: Func) => Object + +h3 = h2; // Error +>h3 = h2 : (x: Func) => string +>h3 : (x: Func) => Object +>h2 : (x: Func) => string + +h3 = h4; // Ok +>h3 = h4 : (x: Func) => string +>h3 : (x: Func) => Object +>h4 : (x: Func) => string + +h4 = h1; // Error +>h4 = h1 : (x: Func) => Object +>h4 : (x: Func) => string +>h1 : (x: Func) => Object + +h4 = h2; // Error +>h4 = h2 : (x: Func) => string +>h4 : (x: Func) => string +>h2 : (x: Func) => string + +h4 = h3; // Error +>h4 = h3 : (x: Func) => Object +>h4 : (x: Func) => string +>h3 : (x: Func) => Object + +declare let i1: Func>; +>i1 : (x: Object) => Func +>Func : (x: T) => U +>Object : Object +>Func : (x: T) => U +>Object : Object + +declare let i2: Func>; +>i2 : (x: Object) => Func +>Func : (x: T) => U +>Object : Object +>Func : (x: T) => U + +declare let i3: Func>; +>i3 : (x: string) => Func +>Func : (x: T) => U +>Func : (x: T) => U +>Object : Object + +declare let i4: Func>; +>i4 : (x: string) => Func +>Func : (x: T) => U +>Func : (x: T) => U + +i1 = i2; // Error +>i1 = i2 : (x: Object) => Func +>i1 : (x: Object) => Func +>i2 : (x: Object) => Func + +i1 = i3; // Error +>i1 = i3 : (x: string) => Func +>i1 : (x: Object) => Func +>i3 : (x: string) => Func + +i1 = i4; // Error +>i1 = i4 : (x: string) => Func +>i1 : (x: Object) => Func +>i4 : (x: string) => Func + +i2 = i1; // Ok +>i2 = i1 : (x: Object) => Func +>i2 : (x: Object) => Func +>i1 : (x: Object) => Func + +i2 = i3; // Error +>i2 = i3 : (x: string) => Func +>i2 : (x: Object) => Func +>i3 : (x: string) => Func + +i2 = i4; // Error +>i2 = i4 : (x: string) => Func +>i2 : (x: Object) => Func +>i4 : (x: string) => Func + +i3 = i1; // Ok +>i3 = i1 : (x: Object) => Func +>i3 : (x: string) => Func +>i1 : (x: Object) => Func + +i3 = i2; // Error +>i3 = i2 : (x: Object) => Func +>i3 : (x: string) => Func +>i2 : (x: Object) => Func + +i3 = i4; // Error +>i3 = i4 : (x: string) => Func +>i3 : (x: string) => Func +>i4 : (x: string) => Func + +i4 = i1; // Ok +>i4 = i1 : (x: Object) => Func +>i4 : (x: string) => Func +>i1 : (x: Object) => Func + +i4 = i2; // Ok +>i4 = i2 : (x: Object) => Func +>i4 : (x: string) => Func +>i2 : (x: Object) => Func + +i4 = i3; // Ok +>i4 = i3 : (x: string) => Func +>i4 : (x: string) => Func +>i3 : (x: string) => Func + +interface Animal { animal: void } +>Animal : Animal +>animal : void + +interface Dog extends Animal { dog: void } +>Dog : Dog +>Animal : Animal +>dog : void + +interface Cat extends Animal { cat: void } +>Cat : Cat +>Animal : Animal +>cat : void + +interface Comparer1 { +>Comparer1 : Comparer1 +>T : T + + compare(a: T, b: T): number; +>compare : (a: T, b: T) => number +>a : T +>T : T +>b : T +>T : T +} + +declare let animalComparer1: Comparer1; +>animalComparer1 : Comparer1 +>Comparer1 : Comparer1 +>Animal : Animal + +declare let dogComparer1: Comparer1; +>dogComparer1 : Comparer1 +>Comparer1 : Comparer1 +>Dog : Dog + +animalComparer1 = dogComparer1; // Ok +>animalComparer1 = dogComparer1 : Comparer1 +>animalComparer1 : Comparer1 +>dogComparer1 : Comparer1 + +dogComparer1 = animalComparer1; // Ok +>dogComparer1 = animalComparer1 : Comparer1 +>dogComparer1 : Comparer1 +>animalComparer1 : Comparer1 + +interface Comparer2 { +>Comparer2 : Comparer2 +>T : T + + compare: (a: T, b: T) => number; +>compare : (a: T, b: T) => number +>a : T +>T : T +>b : T +>T : T +} + +declare let animalComparer2: Comparer2; +>animalComparer2 : Comparer2 +>Comparer2 : Comparer2 +>Animal : Animal + +declare let dogComparer2: Comparer2; +>dogComparer2 : Comparer2 +>Comparer2 : Comparer2 +>Dog : Dog + +animalComparer2 = dogComparer2; // Error +>animalComparer2 = dogComparer2 : Comparer2 +>animalComparer2 : Comparer2 +>dogComparer2 : Comparer2 + +dogComparer2 = animalComparer2; // Ok +>dogComparer2 = animalComparer2 : Comparer2 +>dogComparer2 : Comparer2 +>animalComparer2 : Comparer2 + From 936f98d9adca8530da7af3f7ccbb4ce1b27b6a93 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 29 Sep 2017 16:01:14 -0700 Subject: [PATCH 21/24] Addressing CR feedback --- src/compiler/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c34f0ad54990e..010368629809d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3344,6 +3344,7 @@ namespace ts { typeArguments?: Type[]; // Type reference type arguments (undefined if none) } + /* @internal */ export const enum Variance { Invariant = 0, // Neither covariant nor contravariant Covariant = 1, // Covariant @@ -3356,6 +3357,7 @@ namespace ts { export interface GenericType extends InterfaceType, TypeReference { /* @internal */ instantiations: Map; // Generic instantiation cache + /* @internal */ variances?: Variance[]; // Variance of each type parameter } From bf75a3f4ac391bd4c928b84d5a660c89151dfc5e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Oct 2017 12:54:04 -0700 Subject: [PATCH 22/24] Emit .d.ts file in test --- .../baselines/reference/strictFunctionTypes1.js | 17 +++++++++++++++++ tests/cases/compiler/strictFunctionTypes1.ts | 1 + 2 files changed, 18 insertions(+) diff --git a/tests/baselines/reference/strictFunctionTypes1.js b/tests/baselines/reference/strictFunctionTypes1.js index 28a7a7f61d607..e802c4435616d 100644 --- a/tests/baselines/reference/strictFunctionTypes1.js +++ b/tests/baselines/reference/strictFunctionTypes1.js @@ -23,3 +23,20 @@ var x1 = f1(fo, fs); // (x: string) => void var x2 = f2("abc", fo, fs); // "abc" var x3 = f3("abc", fo, fx); // "abc" | "def" var x4 = f4(fo, fs); // Func + + +//// [strictFunctionTypes1.d.ts] +declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; +declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; +declare function f3(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T; +interface Func { + (x: T): void; +} +declare function f4(f1: Func, f2: Func): Func; +declare function fo(x: Object): void; +declare function fs(x: string): void; +declare function fx(f: (x: "def") => void): void; +declare const x1: (x: string) => void; +declare const x2 = "abc"; +declare const x3: string; +declare const x4: Func; diff --git a/tests/cases/compiler/strictFunctionTypes1.ts b/tests/cases/compiler/strictFunctionTypes1.ts index 7d8ffc689ff3d..6c07bc51ffed2 100644 --- a/tests/cases/compiler/strictFunctionTypes1.ts +++ b/tests/cases/compiler/strictFunctionTypes1.ts @@ -1,4 +1,5 @@ // @strict: true +// @declaration: true declare function f1(f1: (x: T) => void, f2: (x: T) => void): (x: T) => void; declare function f2(obj: T, f1: (x: T) => void, f2: (x: T) => void): T; From bff843a9c9def253257a0290cb590d4e89897e25 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Oct 2017 13:39:55 -0700 Subject: [PATCH 23/24] Improve error elaboration for invariant generic types --- src/compiler/checker.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de1b28f6a56f4..92abee8b9d113 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9415,7 +9415,16 @@ namespace ts { // with a structural comparison. Otherwise, we know for certain the instantiations aren't // related and we can return here. if (variances !== emptyArray && !hasCovariantVoidArgument(target, variances)) { - return Ternary.False; + // In some cases generic types that are covariant in regular type checking mode become + // invariant in --strictFunctionTypes mode because one or more type parameters are used in + // both co- and contravariant positions. In order to make it easier to diagnose *why* such + // types are invariant, if any of the type parameters are invariant we reset the reported + // errors and instead force a structural comparison (which will include elaborations that + // reveal the reason). + if (!(reportErrors && some(variances, v => v === Variance.Invariant))) { + return Ternary.False; + } + errorInfo = saveErrorInfo; } } // Even if relationship doesn't hold for unions, intersections, or generic type references, From c2344e07a4d02d5cc453c6e7cc5eda6d0d373de6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Oct 2017 13:40:26 -0700 Subject: [PATCH 24/24] Add error elaboration test --- .../strictFunctionTypesErrors.errors.txt | 35 ++++++++++++++++- .../reference/strictFunctionTypesErrors.js | 18 +++++++++ .../strictFunctionTypesErrors.symbols | 36 ++++++++++++++++++ .../reference/strictFunctionTypesErrors.types | 38 +++++++++++++++++++ .../compiler/strictFunctionTypesErrors.ts | 15 ++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt index eb0c2d00233cd..2827983bd5ae1 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -79,9 +79,17 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. Type 'Animal' is not assignable to type 'Dog'. Property 'dog' is missing in type 'Animal'. +tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. + Types of property 'onSetItem' are incompatible. + Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. + Types of parameters 'item' and 'item' are incompatible. + Type 'Animal' is not assignable to type 'Dog'. +tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. + Types of property 'item' are incompatible. + Type 'Animal' is not assignable to type 'Dog'. -==== tests/cases/compiler/strictFunctionTypesErrors.ts (29 errors) ==== +==== tests/cases/compiler/strictFunctionTypesErrors.ts (31 errors) ==== export {} @@ -304,4 +312,29 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Co !!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. !!! error TS2322: Property 'dog' is missing in type 'Animal'. dogComparer2 = animalComparer2; // Ok + + // Crate is invariant in --strictFunctionTypes mode + + interface Crate { + item: T; + onSetItem: (item: T) => void; + } + + declare let animalCrate: Crate; + declare let dogCrate: Crate; + + // Errors below should elaborate the reason for invariance + + animalCrate = dogCrate; // Error + ~~~~~~~~~~~ +!!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. +!!! error TS2322: Types of property 'onSetItem' are incompatible. +!!! error TS2322: Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. +!!! error TS2322: Types of parameters 'item' and 'item' are incompatible. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. + dogCrate = animalCrate; // Error + ~~~~~~~~ +!!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. +!!! error TS2322: Types of property 'item' are incompatible. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. \ No newline at end of file diff --git a/tests/baselines/reference/strictFunctionTypesErrors.js b/tests/baselines/reference/strictFunctionTypesErrors.js index 0049fe970ce65..2be598f0ef9c3 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.js +++ b/tests/baselines/reference/strictFunctionTypesErrors.js @@ -111,6 +111,21 @@ declare let dogComparer2: Comparer2; animalComparer2 = dogComparer2; // Error dogComparer2 = animalComparer2; // Ok + +// Crate is invariant in --strictFunctionTypes mode + +interface Crate { + item: T; + onSetItem: (item: T) => void; +} + +declare let animalCrate: Crate; +declare let dogCrate: Crate; + +// Errors below should elaborate the reason for invariance + +animalCrate = dogCrate; // Error +dogCrate = animalCrate; // Error //// [strictFunctionTypesErrors.js] @@ -168,3 +183,6 @@ animalComparer1 = dogComparer1; // Ok dogComparer1 = animalComparer1; // Ok animalComparer2 = dogComparer2; // Error dogComparer2 = animalComparer2; // Ok +// Errors below should elaborate the reason for invariance +animalCrate = dogCrate; // Error +dogCrate = animalCrate; // Error diff --git a/tests/baselines/reference/strictFunctionTypesErrors.symbols b/tests/baselines/reference/strictFunctionTypesErrors.symbols index ce3a81f524f8a..30faf83d87e25 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.symbols +++ b/tests/baselines/reference/strictFunctionTypesErrors.symbols @@ -364,3 +364,39 @@ dogComparer2 = animalComparer2; // Ok >dogComparer2 : Symbol(dogComparer2, Decl(strictFunctionTypesErrors.ts, 108, 11)) >animalComparer2 : Symbol(animalComparer2, Decl(strictFunctionTypesErrors.ts, 107, 11)) +// Crate is invariant in --strictFunctionTypes mode + +interface Crate { +>Crate : Symbol(Crate, Decl(strictFunctionTypesErrors.ts, 111, 31)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 115, 16)) + + item: T; +>item : Symbol(Crate.item, Decl(strictFunctionTypesErrors.ts, 115, 20)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 115, 16)) + + onSetItem: (item: T) => void; +>onSetItem : Symbol(Crate.onSetItem, Decl(strictFunctionTypesErrors.ts, 116, 12)) +>item : Symbol(item, Decl(strictFunctionTypesErrors.ts, 117, 16)) +>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 115, 16)) +} + +declare let animalCrate: Crate; +>animalCrate : Symbol(animalCrate, Decl(strictFunctionTypesErrors.ts, 120, 11)) +>Crate : Symbol(Crate, Decl(strictFunctionTypesErrors.ts, 111, 31)) +>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8)) + +declare let dogCrate: Crate; +>dogCrate : Symbol(dogCrate, Decl(strictFunctionTypesErrors.ts, 121, 11)) +>Crate : Symbol(Crate, Decl(strictFunctionTypesErrors.ts, 111, 31)) +>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33)) + +// Errors below should elaborate the reason for invariance + +animalCrate = dogCrate; // Error +>animalCrate : Symbol(animalCrate, Decl(strictFunctionTypesErrors.ts, 120, 11)) +>dogCrate : Symbol(dogCrate, Decl(strictFunctionTypesErrors.ts, 121, 11)) + +dogCrate = animalCrate; // Error +>dogCrate : Symbol(dogCrate, Decl(strictFunctionTypesErrors.ts, 121, 11)) +>animalCrate : Symbol(animalCrate, Decl(strictFunctionTypesErrors.ts, 120, 11)) + diff --git a/tests/baselines/reference/strictFunctionTypesErrors.types b/tests/baselines/reference/strictFunctionTypesErrors.types index f2d3b52a5b9b0..e4372d4b8fa20 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.types +++ b/tests/baselines/reference/strictFunctionTypesErrors.types @@ -416,3 +416,41 @@ dogComparer2 = animalComparer2; // Ok >dogComparer2 : Comparer2 >animalComparer2 : Comparer2 +// Crate is invariant in --strictFunctionTypes mode + +interface Crate { +>Crate : Crate +>T : T + + item: T; +>item : T +>T : T + + onSetItem: (item: T) => void; +>onSetItem : (item: T) => void +>item : T +>T : T +} + +declare let animalCrate: Crate; +>animalCrate : Crate +>Crate : Crate +>Animal : Animal + +declare let dogCrate: Crate; +>dogCrate : Crate +>Crate : Crate +>Dog : Dog + +// Errors below should elaborate the reason for invariance + +animalCrate = dogCrate; // Error +>animalCrate = dogCrate : Crate +>animalCrate : Crate +>dogCrate : Crate + +dogCrate = animalCrate; // Error +>dogCrate = animalCrate : Crate +>dogCrate : Crate +>animalCrate : Crate + diff --git a/tests/cases/compiler/strictFunctionTypesErrors.ts b/tests/cases/compiler/strictFunctionTypesErrors.ts index 32029364d76a0..fbf1c0fa6da92 100644 --- a/tests/cases/compiler/strictFunctionTypesErrors.ts +++ b/tests/cases/compiler/strictFunctionTypesErrors.ts @@ -111,3 +111,18 @@ declare let dogComparer2: Comparer2; animalComparer2 = dogComparer2; // Error dogComparer2 = animalComparer2; // Ok + +// Crate is invariant in --strictFunctionTypes mode + +interface Crate { + item: T; + onSetItem: (item: T) => void; +} + +declare let animalCrate: Crate; +declare let dogCrate: Crate; + +// Errors below should elaborate the reason for invariance + +animalCrate = dogCrate; // Error +dogCrate = animalCrate; // Error