@@ -13503,7 +13503,52 @@ export function createTypeEvaluator(
1350313503 const paramName = paramNameNode ? paramNameNode.d.value : undefined;
1350413504
1350513505 if (paramName) {
13506- if (paramName === 'default') {
13506+ if (paramName === 'covariant') {
13507+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13508+ if (
13509+ typeVar.shared.declaredVariance === Variance.Contravariant ||
13510+ typeVar.shared.declaredVariance === Variance.Auto
13511+ ) {
13512+ addDiagnostic(
13513+ DiagnosticRule.reportGeneralTypeIssues,
13514+ LocMessage.typeVarVariance(),
13515+ argList[i].valueExpression!
13516+ );
13517+ } else {
13518+ typeVar.shared.declaredVariance = Variance.Covariant;
13519+ }
13520+ }
13521+ } else if (paramName === 'contravariant') {
13522+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13523+ if (
13524+ typeVar.shared.declaredVariance === Variance.Covariant ||
13525+ typeVar.shared.declaredVariance === Variance.Auto
13526+ ) {
13527+ addDiagnostic(
13528+ DiagnosticRule.reportGeneralTypeIssues,
13529+ LocMessage.typeVarVariance(),
13530+ argList[i].valueExpression!
13531+ );
13532+ } else {
13533+ typeVar.shared.declaredVariance = Variance.Contravariant;
13534+ }
13535+ }
13536+ } else if (paramName === 'infer_variance') {
13537+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13538+ if (
13539+ typeVar.shared.declaredVariance === Variance.Covariant ||
13540+ typeVar.shared.declaredVariance === Variance.Contravariant
13541+ ) {
13542+ addDiagnostic(
13543+ DiagnosticRule.reportGeneralTypeIssues,
13544+ LocMessage.typeVarVariance(),
13545+ argList[i].valueExpression!
13546+ );
13547+ } else {
13548+ typeVar.shared.declaredVariance = Variance.Auto;
13549+ }
13550+ }
13551+ } else if (paramName === 'default') {
1350713552 const expr = argList[i].valueExpression;
1350813553 if (expr) {
1350913554 const defaultType = getTypeVarTupleDefaultType(expr, /* isPep695Syntax */ false);
@@ -13593,7 +13638,52 @@ export function createTypeEvaluator(
1359313638 const paramName = paramNameNode ? paramNameNode.d.value : undefined;
1359413639
1359513640 if (paramName) {
13596- if (paramName === 'default') {
13641+ if (paramName === 'covariant') {
13642+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13643+ if (
13644+ paramSpec.shared.declaredVariance === Variance.Contravariant ||
13645+ paramSpec.shared.declaredVariance === Variance.Auto
13646+ ) {
13647+ addDiagnostic(
13648+ DiagnosticRule.reportGeneralTypeIssues,
13649+ LocMessage.typeVarVariance(),
13650+ argList[i].valueExpression!
13651+ );
13652+ } else {
13653+ paramSpec.shared.declaredVariance = Variance.Covariant;
13654+ }
13655+ }
13656+ } else if (paramName === 'contravariant') {
13657+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13658+ if (
13659+ paramSpec.shared.declaredVariance === Variance.Covariant ||
13660+ paramSpec.shared.declaredVariance === Variance.Auto
13661+ ) {
13662+ addDiagnostic(
13663+ DiagnosticRule.reportGeneralTypeIssues,
13664+ LocMessage.typeVarVariance(),
13665+ argList[i].valueExpression!
13666+ );
13667+ } else {
13668+ paramSpec.shared.declaredVariance = Variance.Contravariant;
13669+ }
13670+ }
13671+ } else if (paramName === 'infer_variance') {
13672+ if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
13673+ if (
13674+ paramSpec.shared.declaredVariance === Variance.Covariant ||
13675+ paramSpec.shared.declaredVariance === Variance.Contravariant
13676+ ) {
13677+ addDiagnostic(
13678+ DiagnosticRule.reportGeneralTypeIssues,
13679+ LocMessage.typeVarVariance(),
13680+ argList[i].valueExpression!
13681+ );
13682+ } else {
13683+ paramSpec.shared.declaredVariance = Variance.Auto;
13684+ }
13685+ }
13686+ } else if (paramName === 'default') {
1359713687 const expr = argList[i].valueExpression;
1359813688 if (expr) {
1359913689 const defaultType = getParamSpecDefaultType(expr, /* isPep695Syntax */ false);
@@ -18690,24 +18780,33 @@ export function createTypeEvaluator(
1869018780 undefined
1869118781 );
1869218782
18693- classType.shared.typeParams.forEach((param, paramIndex) => {
18694- // Skip TypeVarTuples and ParamSpecs.
18695- if (isTypeVarTuple(param) || isParamSpec(param)) {
18696- return;
18697- }
18783+ // A scopeless ParamSpec used as the "top type" substitute for ParamSpec parameters
18784+ // during variance inference. It has no scope ID so makeTypeVarsBound leaves it free,
18785+ // giving us the needed asymmetry:
18786+ // - as src in assignBoundTypeVar: fails (not the gradual `...` form) → covariant check fails
18787+ // - as dest in assignTypeVar: returns true immediately (no scopeId) → contravariant check passes
18788+ const dummyParamSpec = TypeVarType.createInstantiable('__varianceDummyP', TypeVarKind.ParamSpec);
18789+ const dummyTypeVarTuple = TypeVarType.createInstantiable('__varianceDummyTs', TypeVarKind.TypeVarTuple);
1869818790
18791+ classType.shared.typeParams.forEach((param, paramIndex) => {
1869918792 // Skip type variables without auto-variance.
1870018793 if (param.shared.declaredVariance !== Variance.Auto) {
1870118794 return;
1870218795 }
1870318796
1870418797 // Replace all type arguments with a dummy type except for the
18705- // TypeVar of interest, which is replaced with an object instance.
18798+ // TypeVar of interest. For regular TypeVars use an object instance;
18799+ // for ParamSpec/TypeVarTuple use a scopeless dummy (object would become
18800+ // the gradual `...` form, making both checks pass; TypeVarTuple at paramIndex
18801+ // was previously returned as itself, making srcTypeArgs === destTypeArgs).
1870618802 const srcTypeArgs = classType.shared.typeParams.map((p, i) => {
18707- if (isTypeVarTuple(p)) {
18708- return p;
18803+ if (i === paramIndex) {
18804+ if (isParamSpec(p)) return dummyParamSpec;
18805+ if (isTypeVarTuple(p)) return dummyTypeVarTuple;
18806+ return getObjectType();
1870918807 }
18710- return i === paramIndex ? getObjectType() : dummyTypeObject;
18808+ if (isTypeVarTuple(p)) return p;
18809+ return dummyTypeObject;
1871118810 });
1871218811
1871318812 // Replace all type arguments with a dummy type except for the
@@ -23062,16 +23161,14 @@ export function createTypeEvaluator(
2306223161 if (scopeNode.nodeType === ParseNodeType.Class) {
2306323162 scopeType = TypeVarScopeType.Class;
2306423163
23065- // Set the variance to "auto" for class-scoped TypeVars.
23066- typeVar.shared.declaredVariance =
23067- isParamSpec(typeVar) || isTypeVarTuple(typeVar) ? Variance.Invariant : Variance.Auto;
23164+ // Set the variance to "auto" for class-scoped type variables
23165+ typeVar.shared.declaredVariance = Variance.Auto;
2306823166 } else if (scopeNode.nodeType === ParseNodeType.Function) {
2306923167 scopeType = TypeVarScopeType.Function;
2307023168 } else {
2307123169 assert(scopeNode.nodeType === ParseNodeType.TypeAlias);
2307223170 scopeType = TypeVarScopeType.TypeAlias;
23073- typeVar.shared.declaredVariance =
23074- isParamSpec(typeVar) || isTypeVarTuple(typeVar) ? Variance.Invariant : Variance.Auto;
23171+ typeVar.shared.declaredVariance = Variance.Auto;
2307523172 }
2307623173
2307723174 typeVar = TypeVarType.cloneForScopeId(
0 commit comments