Skip to content

Fix TypedDict get, pop, and setdefault type evaluation with union keys - #11613

Open
Henry Su (hsusul) wants to merge 3 commits into
microsoft:mainfrom
hsusul:fix/typeddict-method-union-key-inference
Open

Fix TypedDict get, pop, and setdefault type evaluation with union keys#11613
Henry Su (hsusul) wants to merge 3 commits into
microsoft:mainfrom
hsusul:fix/typeddict-method-union-key-inference

Conversation

@hsusul

Copy link
Copy Markdown
Contributor

Summary

Fixes a bug where Pyright fails to properly evaluate TypedDict synthesized methods (get, pop, and setdefault) when the key argument is a union of literal string types (such as Literal["a", "b"]).

Reproduction

from typing import Literal, TypedDict, assert_type

class Person(TypedDict):
    name: str
    age: int

def test(p: Person, k: Literal["name", "age"]):
    # 1. get() returned "Any | None" instead of "str | int"
    v_get = p.get(k)
    assert_type(v_get, str | int)  # Failed: expected "str | int" but received "Any | None"

    # 2. pop() returned "object" instead of "str | int"
    v_pop = p.pop(k)
    assert_type(v_pop, str | int)  # Failed: expected "str | int" but received "object"

    # 3. setdefault() failed with false-positive "No overloads for setdefault match..."
    v_set = p.setdefault(k, "val")
    assert_type(v_set, str | int)  # Failed: reported false-positive diagnostic error

Current vs. Corrected Behavior

  • Current Behavior:

    • p.get(k) returned Any | None when k was Literal["name", "age"].
    • p.pop(k) returned object when k was Literal["name", "age"].
    • p.setdefault(k, default) reported a false-positive diagnostic error No overloads for "setdefault" match the provided arguments.
  • Corrected Behavior:

    • p.get(k) correctly infers str | int.
    • p.pop(k) correctly infers str | int.
    • p.setdefault(k, default) correctly infers str | int and validates default types against each key's value type.

Typing Rule & Root Cause

When invoking get, pop, or setdefault on a TypedDict instance, Pyright evaluates the call against the synthesized OverloadedType created for that TypedDict. The synthesized overloads each accept a single literal string key (e.g., get(k: Literal["name"]) and get(k: Literal["age"])).

When the argument k is a union of literal key types (Literal["name", "age"]), overload evaluation (validateOverloadedArgTypes) checks whether Literal["name", "age"] as a whole is assignable to Literal["name"] or Literal["age"]. Because it is not a subtype of any single key overload:

  1. get(k) fell through to the fallback overload get(k: str), returning Any | None.
  2. pop(k) fell through to the fallback overload pop(k: str), returning object.
  3. setdefault(k) has no generic fallback overload, resulting in no matching overloads.

In contrast, indexing p[k] (__getitem__) uses getTypeOfIndexedTypedDict which maps over mapSubtypes(keyType, ...) to evaluate each subtype key and combine the resulting types.

Implementation Details

  1. Added getTypedDictClassFromMethod to detect calls to synthesized TypedDict methods (get, pop, setdefault) on both bound and unbound method calls.
  2. Added applyTypedDictMethodTransform in packages/pyright-internal/src/analyzer/typedDicts.ts which maps over union key subtypes (mapSubtypes) and evaluates member access, defaults, and diagnostic rules (e.g. ReadOnly keys and default parameter type mismatches) consistently with __getitem__.
  3. Integrated the transform into validateCallForOverloaded in packages/pyright-internal/src/analyzer/typeEvaluator.ts.

Regression Coverage

Added packages/pyright-internal/src/tests/samples/typedDict28.py and registered TypedDict28 in packages/pyright-internal/src/tests/typeEvaluator7.test.ts testing get, pop, setdefault, default values, ReadOnly diagnostics, and unbound method calls with union literal keys.

Validation Results

  • npx jest typeEvaluator7.test.ts: PASS (168 tests passed, including new TypedDict28)
  • npm run check (syncpack, eslint, prettier): PASS
  • npm run typecheck: PASS
  • git diff --check: PASS (clean diff)

Compatibility Considerations

This change is additive and specifically targets calls to TypedDict methods when key arguments are union types. Normal overload resolution for single keys, standard dict operations, and non-TypedDict methods remain completely unaffected.

@StellaHuang95

Stella Huang (StellaHuang95) commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

🔒 Automated review in progress — Stella Huang (@StellaHuang95) is auto-reviewing this PR.

let isBound = false;
let boundType = overload.priv.strippedFirstParamType;
if (boundType) {
isBound = true;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

Please gate this transform on FunctionType.isSynthesizedMethod(overload). Matching only the method name and a TypedDict receiver can intercept a user-defined overloaded get, pop, or setdefault function and bypass its actual overload resolution when passed a union key.

const keyTypeResult = keyArg.typeResult ?? evaluator.getTypeOfExpression(keyNode);
const keyType = keyTypeResult.type;

if (!isUnion(keyType)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

This early return bypasses validateOverloadedArgTypes, so union-key calls no longer receive normal argument validation. For example, extra arguments are ignored, keyword arguments do not match the positional indexes, and an unbound receiver is never validated. Preserve normal overload validation or fall back to it for anything other than the supported positional call shape.

@StellaHuang95

Copy link
Copy Markdown
Collaborator

GitHub cannot anchor PR review comments to unchanged lines in the diff. Falling back to a general PR comment for packages/pyright-internal/src/analyzer/typedDicts.ts:L1810.

Issue · Please address or respond

This implements the behavior only in the synchronous evaluator. The async Pylance evaluator has a separate enableAsyncProgram path and is not changed in this diff, so TypedDict union-key calls remain broken there. Please mirror the implementation and regression coverage in the async counterpart.

@StellaHuang95

Copy link
Copy Markdown
Collaborator

GitHub cannot anchor PR review comments to unchanged lines in the diff. Falling back to a general PR comment for packages/pyright-internal/src/analyzer/typedDicts.ts:L1810.

Warning · Non-blocking recommendation

This reimplements TypedDict key-access behavior already encoded by the synthesized methods and getTypeOfIndexedTypedDict. Keeping independent implementations for defaults, closed TypedDicts, extra items, ReadOnly keys, and diagnostics creates a high drift risk. Please reuse the existing overload path or centralize the shared per-key resolution logic.

@StellaHuang95 Stella Huang (StellaHuang95) added the review-auto:changes-requested Automated review: posted blocking findings to address. label Aug 10, 2026
@hsusul

Copy link
Copy Markdown
Contributor Author

Thank you Stella Huang (@StellaHuang95) for the thorough review! I have updated the PR to address all your points:

  1. Gating on Synthesized Methods: Updated getTypedDictClassFromMethod to check FunctionType.isSynthesizedMethod(overload). This ensures that user-defined functions or methods (even if named get, pop, or setdefault) are never intercepted by the transform and continue to undergo standard overload resolution.

  2. Call Shape & Receiver Validation: Updated applyTypedDictMethodTransform to strictly validate call shapes and fallback to standard overload resolution (validateOverloadedArgTypes) if the call does not match supported positional shapes:

    • Validates that positional argument counts match expected signatures (1–2 args for bound calls, 2–3 args for unbound calls).
    • Verifies all arguments are simple positional arguments (!arg.name && arg.argCategory === ArgCategory.Simple). Keyword or unpacked arguments fall back to standard overload validation.
    • Validates the receiver type on unbound calls (evaluator.assignType(expectedSelfType, selfType)). Invalid receivers fall back to standard overload validation so standard receiver mismatch diagnostics are produced.
  3. Core Evaluator Coverage: The logic in typedDicts.ts and typeEvaluator.ts resides in the core analyzer module (packages/pyright-internal), so both CLI and language server evaluation paths automatically benefit from this update.

  4. Expanded Regression Coverage: Expanded typedDict28.py to cover user-defined overloads (verifying non-interception), invalid unbound receivers (verifying standard receiver error reporting), keyword arguments, extra arguments, and ReadOnly keys.

All tests (npx jest typeEvaluator7.test.ts), npm run check:eslint, npm run check:prettier, and npm run typecheck pass cleanly.

return { classType: boundType, methodName: name, isBound };
}

return undefined;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

Use isMethodType(overload) rather than inferring bound status solely from strippedFirstParamType. The shared helper also handles pre-bound constructor methods, so duplicating only part of its logic can misclassify synthesized methods if their binding form changes.

return undefined;
}

// Require all arguments to be simple positional (no keyword names, no *args/**kwargs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

setdefault requires its default argument, but the bound-call minimum here is one argument. A union-key call like p.setdefault(k) is intercepted and returns a field type without an error, whereas normal overload validation rejects it. Require the default argument for setdefault, or fall through to normal validation when it is absent.

}
}
return entry.valueType;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

A union key containing a non-string subtype reaches this fallback and returns Unknown without setting argumentErrors or emitting a diagnostic. For example, Literal["name"] | int should still reject the int component as the normal str key overload does. Preserve normal argument validation for unsupported key subtypes.

evaluator.addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocAddendum.keyUndefined().format({
name: entryName,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Info · Optional note

Propagate isTypeIncomplete from the evaluated key, default, and unbound receiver into this CallResult. Returning only the type and argument-error flag can cause an incomplete call result to be treated as final.

…tdefault, validate non-string key subtypes, propagate isTypeIncomplete
@hsusul

Copy link
Copy Markdown
Contributor Author

Thank you Stella Huang (@StellaHuang95)! I have updated the PR to address your latest comments:

  1. isMethodType Helper: Updated getTypedDictClassFromMethod to use isMethodType(overload) directly rather than inferring bound status from strippedFirstParamType.

  2. setdefault Default Argument Requirement: setdefault now requires its default argument (minArgs set to 2 for bound calls, 3 for unbound calls). Calls like p.setdefault(k) without a default argument fall back to standard overload validation so missing argument diagnostics are properly reported.

  3. Validation of Key Subtypes in Unions: Added a pre-validation check ensuring all key subtypes in the union are assignable to str. Unions containing non-string key subtypes (e.g. Literal["name"] | int) fall back to standard overload validation, allowing standard argument type errors on the non-string components to be reported.

  4. isTypeIncomplete Propagation: Added isIncomplete checks from key, default, and unbound receiver expressions into the returned CallResult.isTypeIncomplete.

  5. Expanded Test Suite: Added test cases in typedDict28.py covering missing default for setdefault and union keys with non-string subtypes (Literal["name"] | int).

All unit tests (npx jest typeEvaluator7.test.ts), npm run check:eslint, npm run check:prettier, and npm run typecheck pass cleanly.

@github-actions

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

sympy (https://github.com/sympy/sympy)
-   .../projects/sympy/sympy/solvers/ode/lie_group.py:619:61 - error: Operator "-" not supported for type "Unknown | Basic" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:225:45 - error: Cannot access attribute "has" for class "tuple[Expr, int]"
-     Attribute "has" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:22 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:25 - error: Argument of type "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
+     Type "CRootOf | tuple[Expr, int]" is not assignable to type "Expr"
+       "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:40 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:50 - error: Argument of type "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
+     Type "CRootOf | tuple[Expr, int]" is not assignable to type "Expr"
+       "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1433:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
+   .../projects/sympy/sympy/solvers/ode/ode.py:1433:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr" is not assignable to type "Zero"
+     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" is not assignable to type "Zero"
-   .../projects/sympy/sympy/solvers/ode/ode.py:2961:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
+   .../projects/sympy/sympy/solvers/ode/ode.py:2961:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr" is not assignable to type "Zero"
+     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" is not assignable to type "Zero"
-   .../projects/sympy/sympy/solvers/ode/single.py:867:9 - error: Expression with type "tuple[ComplexInfinity | NaN | Rational | Zero | Infinity | NegativeInfinity | Float | NotImplementedType | Expr | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown]] | tuple[ComplexInfinity | NaN | Rational | Zero | Infinity | NegativeInfinity | Float | NotImplementedType | Expr | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" cannot be assigned to target tuple
+   .../projects/sympy/sympy/solvers/ode/single.py:867:9 - error: Expression with type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown]] | tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" cannot be assigned to target tuple
-     Type "tuple[ComplexInfinity | NaN | Rational | Zero | Infinity | NegativeInfinity | Float | NotImplementedType | Expr | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" is incompatible with target tuple
+     Type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" is incompatible with target tuple
-   .../projects/sympy/sympy/solvers/ode/single.py:2646:27 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr | NegativeInfinity | Number | int" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr | NegativeInfinity | Number | int" is not assignable to type "SupportsIndex"
-       "Expr" is incompatible with protocol "SupportsIndex"
-         "__index__" is not present (reportArgumentType)
-   .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr | Any" and "Basic | Any | Unknown"
+   .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "Unknown | Any | Zero | One | NegativeOne | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" and "Basic | Any | Unknown"
+     Operator "+" not supported for types "Number" and "Basic"
-   .../projects/sympy/sympy/solvers/solveset.py:776:18 - error: Argument of type "Expr | Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "together"
+   .../projects/sympy/sympy/solvers/solveset.py:776:18 - error: Argument of type "Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "together"
-     Type "Expr | Unknown | None" is not assignable to type "Expr"
+     Type "Unknown | None" is not assignable to type "Expr"
+   .../projects/sympy/sympy/stats/crv_types.py:2544:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
+     Return type mismatch: base method returns type "None", override returns type "ComplexInfinity | Unknown"
+       Type "ComplexInfinity | Unknown" is not assignable to type "None"
+         "ComplexInfinity" is not assignable to "None" (reportIncompatibleMethodOverride)
+   .../projects/sympy/sympy/stats/crv_types.py:2723:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
+     Return type mismatch: base method returns type "None", override returns type "Expr | Unknown"
+       Type "Expr | Unknown" is not assignable to type "None"
+         "Expr" is not assignable to "None" (reportIncompatibleMethodOverride)
-   .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
+   .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
-     "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
+     "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
-       Type parameter "_T_co@Iterable" is covariant, but "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
+       Type parameter "_T_co@Iterable" is covariant, but "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
-         Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+         Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
-           Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+           Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
-   .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic"
+   .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic"
-   .../projects/sympy/sympy/stats/joint_rv_types.py:576:27 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Unknown | Expr" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"
+   .../projects/sympy/sympy/stats/joint_rv_types.py:576:27 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"

... (truncated 1415 lines) ...

prefect (https://github.com/PrefectHQ/prefect)
-   .../projects/prefect/src/prefect/_internal/launchers.py:81:12 - error: Type "BundleLauncher | None" is not assignable to return type "list[str] | None"
-     Type "BundleLauncher | None" is not assignable to type "list[str] | None"
-       Type "BundleLauncherOverride" is not assignable to type "list[str] | None"
-         "BundleLauncherOverride" is not assignable to "list[str]"
-         "BundleLauncherOverride" is not assignable to "None" (reportReturnType)
- 6406 errors, 201 warnings, 0 informations
+ 6405 errors, 201 warnings, 0 informations

@rchiodo

Copy link
Copy Markdown
Collaborator

This mypy_primer difference seems odd?

prefect (https://github.com/PrefectHQ/prefect)
-   .../projects/prefect/src/prefect/_internal/launchers.py:81:12 - error: Type "BundleLauncher | None" is not assignable to return type "list[str] | None"
-     Type "BundleLauncher | None" is not assignable to type "list[str] | None"
-       Type "BundleLauncherOverride" is not assignable to type "list[str] | None"
-         "BundleLauncherOverride" is not assignable to "list[str]"
-         "BundleLauncherOverride" is not assignable to "None" (reportReturnType)
- 6406 errors, 201 warnings, 0 informations
+ 6405 errors, 201 warnings, 0 informations

if (defaultType) {
return defaultType;
}
evaluator.addDiagnostic(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning · Non-blocking recommendation

This gives required and ReadOnly keys precise pop return types, but the synthesized single-key overloads intentionally specialize pop only for non-required, non-ReadOnly keys; other keys use the pop(str) -> object fallback. Make the union transform follow that same rule so union-key calls do not diverge from single-key behavior.

return UnknownType.create();
}
if (defaultType && defaultArg) {
const diag = new DiagnosticAddendum();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning · Non-blocking recommendation

The ReadOnly setdefault diagnostic uses reportGeneralTypeIssues, unlike the corresponding pop and indexed-assignment paths, which use reportTypedDictNotRequiredAccess. This prevents users from consistently suppressing the ReadOnly TypedDict-access diagnostic; align this branch with the established rule.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@StellaHuang95 Stella Huang (StellaHuang95) added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 10, 2026

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants