@zzzen/pyright-internal 1.2.0-dev.20260712 → 1.2.0-dev.20260726

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -145,6 +145,8 @@ export declare class Checker extends ParseTreeWalker {
145
145
  private _validateOverrideDecoratorPresent;
146
146
  private _isMethodExemptFromLsp;
147
147
  private _validateOverrideDecoratorNotPresent;
148
+ private _getCallableVariableOverrideComparison;
149
+ private _markFunctionStatic;
148
150
  private _validateBaseClassOverride;
149
151
  private _isFinalFunction;
150
152
  private _validatePropertyOverride;
@@ -4121,7 +4121,17 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4121
4121
  if ((0, types_1.isFunctionOrOverloaded)(overriddenType)) {
4122
4122
  const diagAddendum = new diagnostic_1.DiagnosticAddendum();
4123
4123
  if ((0, types_1.isFunctionOrOverloaded)(overrideType)) {
4124
- if (!this._evaluator.validateOverrideMethod(overriddenType, overrideType,
4124
+ // If one base defines the member as a plain callable variable and a
4125
+ // sibling base overrides it with a real method, bind the method's "self"
4126
+ // so the two are compared as plain callables (mirrors the single-base
4127
+ // override handling in `_validateBaseClassOverride`). This is
4128
+ // load-bearing for parametered callables (e.g. `Callable[[int], None]`
4129
+ // vs `def cb(self, value: int)`): without binding, the method's extra
4130
+ // "self" causes a spurious arity mismatch. See the `DiamondParam*`
4131
+ // samples in methodOverride7.py.
4132
+ const childClassSelf = types_1.ClassType.cloneAsInstance((0, typeUtils_1.selfSpecializeClass)(childClassType, { useBoundTypeVars: true }));
4133
+ const { baseType: overriddenTypeForComparison, overrideType: overrideTypeForComparison } = this._getCallableVariableOverrideComparison(overriddenClassAndSymbol.symbol, overrideClassAndSymbol.symbol, overriddenType, overrideType, childClassType, childClassSelf);
4134
+ if (!this._evaluator.validateOverrideMethod(overriddenTypeForComparison, overrideTypeForComparison,
4125
4135
  /* baseClass */ undefined, diagAddendum,
4126
4136
  /* enforceParamNameMatch */ true)) {
4127
4137
  if (overrideDecl && overrideDecl.type === 5 /* DeclarationType.Function */) {
@@ -4242,6 +4252,10 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4242
4252
  // Is the method present on the base class but missing in the subclass?
4243
4253
  if (baseClassPropMethod) {
4244
4254
  const baseClassMethodType = (0, typeUtils_1.partiallySpecializeType)(baseClassPropMethod, overriddenClassType, this._evaluator.getTypeClassType());
4255
+ // Overloaded accessors (e.g. overloaded property setters) are
4256
+ // represented as an OverloadedType rather than a FunctionType.
4257
+ // Override-compatibility checking for overloaded accessors is not
4258
+ // yet performed; only single-function accessors are validated here.
4245
4259
  if ((0, types_1.isFunction)(baseClassMethodType)) {
4246
4260
  if (!subclassPropMethod) {
4247
4261
  // The method is missing.
@@ -4513,7 +4527,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4513
4527
  }
4514
4528
  }
4515
4529
  else if ((0, types_1.isClassInstance)(overrideType) && types_1.ClassType.isPropertyClass(overrideType)) {
4516
- if (overrideType.priv.fgetInfo) {
4530
+ if (overrideType.priv.fgetInfo && (0, types_1.isFunction)(overrideType.priv.fgetInfo.methodType)) {
4517
4531
  overrideFunction = overrideType.priv.fgetInfo.methodType;
4518
4532
  }
4519
4533
  }
@@ -4566,7 +4580,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4566
4580
  }
4567
4581
  }
4568
4582
  else if ((0, types_1.isClassInstance)(overrideType) && types_1.ClassType.isPropertyClass(overrideType)) {
4569
- if (overrideType.priv.fgetInfo) {
4583
+ if (overrideType.priv.fgetInfo && (0, types_1.isFunction)(overrideType.priv.fgetInfo.methodType)) {
4570
4584
  overrideFunction = overrideType.priv.fgetInfo.methodType;
4571
4585
  }
4572
4586
  }
@@ -4581,6 +4595,65 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4581
4595
  const funcNode = overrideFunction.shared.declaration.node;
4582
4596
  this._evaluator.addDiagnostic(diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.LocMessage.overriddenMethodNotFound().format({ name: funcNode.d.name.d.value }), funcNode.d.name);
4583
4597
  }
4598
+ // If a base class member is a plain callable variable (e.g. `x: Callable[..., None]`)
4599
+ // and the override is a real method, accessing the override on an instance binds its
4600
+ // "self" parameter, leaving a signature that should be compared against the base
4601
+ // callable. This helper detects that asymmetry and returns adjusted types: the bound
4602
+ // override and the base callable, both marked static so the override comparison does
4603
+ // not skip the first parameter as an unbound "self". All other cases are returned
4604
+ // unchanged. This matches the behavior of other type checkers, which allow overriding
4605
+ // a callable attribute with a method.
4606
+ //
4607
+ // Note: this validates only the read direction (the bound override is compatible with
4608
+ // the base callable). A method is effectively read-only, so this intentionally does not
4609
+ // attempt to preserve assignability of the mutable callable attribute; that asymmetry
4610
+ // matches other type checkers and does not trigger `reportIncompatibleVariableOverride`
4611
+ // because the override is a function, not a variable.
4612
+ _getCallableVariableOverrideComparison(baseSymbol, overrideSymbol, baseType, overrideType, childClassType, childClassSelf) {
4613
+ const baseDecls = baseSymbol.getDeclarations();
4614
+ const baseIsCallableVariable = baseDecls.length > 0 && baseDecls.every((decl) => decl.type === 1 /* DeclarationType.Variable */);
4615
+ const overrideIsMethod = overrideSymbol
4616
+ .getDeclarations()
4617
+ .some((decl) => decl.type === 5 /* DeclarationType.Function */);
4618
+ if (!baseIsCallableVariable || !overrideIsMethod) {
4619
+ return { baseType, overrideType };
4620
+ }
4621
+ const boundOverrideType = this._evaluator.bindFunctionToClassOrObject(childClassSelf, overrideType, childClassType);
4622
+ if (!boundOverrideType) {
4623
+ return { baseType, overrideType };
4624
+ }
4625
+ // Mark both the base callable and the bound override as static so the
4626
+ // override comparison does not skip the first parameter as an unbound
4627
+ // "self" (see the `i === 0` self/cls skip in typeEvaluator's
4628
+ // `validateOverrideMethodInternal`). Without this, the bound override
4629
+ // keeps its instance-method flag and its first real parameter would be
4630
+ // silently dropped during the comparison.
4631
+ const staticBaseType = (0, types_1.isFunction)(baseType) ? this._markFunctionStatic(baseType) : baseType;
4632
+ if ((0, types_1.isFunction)(boundOverrideType)) {
4633
+ return {
4634
+ baseType: staticBaseType,
4635
+ overrideType: this._markFunctionStatic(boundOverrideType),
4636
+ };
4637
+ }
4638
+ if ((0, types_1.isOverloaded)(boundOverrideType)) {
4639
+ // An overloaded method binds to an overloaded callable. Apply the
4640
+ // same static normalization to every overload (and the
4641
+ // implementation, if present) so an incompatible first parameter in
4642
+ // an overloaded override is still caught rather than skipped as
4643
+ // "self".
4644
+ const staticOverloads = types_1.OverloadedType.getOverloads(boundOverrideType).map((overload) => this._markFunctionStatic(overload));
4645
+ const impl = types_1.OverloadedType.getImplementation(boundOverrideType);
4646
+ const staticImpl = impl && (0, types_1.isFunction)(impl) ? this._markFunctionStatic(impl) : impl;
4647
+ return {
4648
+ baseType: staticBaseType,
4649
+ overrideType: types_1.OverloadedType.create(staticOverloads, staticImpl),
4650
+ };
4651
+ }
4652
+ return { baseType, overrideType: boundOverrideType };
4653
+ }
4654
+ _markFunctionStatic(functionType) {
4655
+ return types_1.FunctionType.cloneWithNewFlags(functionType, functionType.shared.flags | 4 /* FunctionTypeFlags.StaticMethod */);
4656
+ }
4584
4657
  _validateBaseClassOverride(baseClassAndSymbol, overrideSymbol, overrideType, childClassType, memberName) {
4585
4658
  if (!(0, types_1.isInstantiableClass)(baseClassAndSymbol.classType)) {
4586
4659
  return;
@@ -4643,7 +4716,15 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4643
4716
  // are misnamed in typeshed stubs, so this would result in many
4644
4717
  // false positives.
4645
4718
  const enforceParamNameMatch = !SymbolNameUtils.isDunderName(memberName);
4646
- if (this._evaluator.validateOverrideMethod(baseType, overrideType, childClassType, diagAddendum, enforceParamNameMatch)) {
4719
+ // If the base class member is a plain callable variable
4720
+ // (e.g. `x: Callable[..., None]`) rather than an actual method,
4721
+ // bind the override method's "self" so the two are compared as
4722
+ // plain callables. The declaration scans needed to detect this
4723
+ // are computed inside this helper, so the common method-vs-method
4724
+ // path and the exempt/private/TypedDict early-returns above pay
4725
+ // nothing extra.
4726
+ const { baseType: baseTypeForComparison, overrideType: overrideTypeForComparison } = this._getCallableVariableOverrideComparison(baseClassAndSymbol.symbol, overrideSymbol, baseType, overrideType, childClassType, childClassSelf);
4727
+ if (this._evaluator.validateOverrideMethod(baseTypeForComparison, overrideTypeForComparison, childClassType, diagAddendum, enforceParamNameMatch)) {
4647
4728
  return;
4648
4729
  }
4649
4730
  const decl = (0, symbolUtils_1.getLastTypedDeclarationForSymbol)(overrideSymbol);
@@ -4867,6 +4948,10 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
4867
4948
  // Is the method present on the base class but missing in the subclass?
4868
4949
  if (baseClassPropMethod) {
4869
4950
  const baseClassMethodType = (0, typeUtils_1.partiallySpecializeType)(baseClassPropMethod, baseClassType, this._evaluator.getTypeClassType());
4951
+ // Overloaded accessors (e.g. overloaded property setters) are
4952
+ // represented as an OverloadedType rather than a FunctionType.
4953
+ // Override-compatibility checking for overloaded accessors is not
4954
+ // yet performed; skip them rather than misreporting.
4870
4955
  if (!(0, types_1.isFunction)(baseClassMethodType)) {
4871
4956
  return;
4872
4957
  }