Repository navigation
Block inference from array literals when computing completion contextual types - #65361
Open
Yusuf YILDIZ (yusufyildiz34) wants to merge 1 commit into
Open
Yusuf YILDIZ (yusufyildiz34) wants to merge 1 commit into
Yusuf YILDIZ (yusufyildiz34) wants to merge 1 commit into
Conversation
…ual types
When the language service asks for a contextual type with inference blocked
from the node being edited (e.g. object literal completions), the checker
marks the node and its ancestors up to the containing call as skipped, and
isFromInferenceBlockedSource checks whether a source type's symbol is
declared by one of those nodes. Array literal types have no such symbol, so
`f([{ /*|*/ }])` with `f<T extends [X]>(x: T)` still inferred `T` from the
array literal itself and completions were drawn from `{}` instead of `X`.
Give array literals that are blocked from direct inference a distinct type
and recognize it in isFromInferenceBlockedSource.
Fixes microsoft#63785
Contributor
Author
|
@microsoft-github-policy-service agree |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues require further changes.
No open issues 🎉
What changed in this PR
Fixes #63785 by preventing array literals from driving inference during completion contextual-type queries, restoring property suggestions for generic tuple and array constraints.
Changes:
- Creates distinct array literal types for blocked inference sources and tracks them explicitly.
- Recognizes those types during inference and clears tracking after the query.
- Adds fourslash coverage for tuple constraints, array constraints, and arrays nested in object arguments.
| File | Description |
|---|---|
tsc/internal/fourslash/tests/completionsObjectLiteralInGenericTupleConstraint_test.go |
Tests property completions across eight constraint scenarios. |
tsc/internal/checker/services.go |
Clears blocked-type tracking after contextual-type queries. |
tsc/internal/checker/inference.go |
Recognizes explicitly tracked types as blocked inference sources. |
tsc/internal/checker/checker.go |
Creates and tracks distinct types for inference-blocked array literals. |
Review effort: Balanced
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #63785
Analysis
When the language service needs a contextual type for completions, it calls
GetContextualTypewithContextFlagsIgnoreNodeInferences. That marks the node being edited and its ancestors up to the containing call as "skip direct inference".isFromInferenceBlockedSourcethen decides whether a source type is blocked by checking whether the type's symbol is declared by one of those nodes.That works for object literals, but array literal types have no symbol pointing back to their node. They are also cached and shared between array literals that have identical element types. So in
the array literal
[{}]is still used as an inference source forExtensions. The "completions" contextual type therefore becomes{}instead of the constraintAllPartialObject, andcomponentis not offered.The cases from the issue that already worked did so by accident:
extendTheme3([{}]):[{}]is not assignable to the constraint (it is missingrequiredField), so inference falls back to the constraint.extendTheme5: the parameter is[Extensions], so inference goes through the element{}, which does have a symbol.Once
requiredField: 'foo'is filled in, the inferred type satisfies the constraint and completions regress again. The same happens with plain array constraints such asT extends X[], and with arrays nested in object arguments (f({ items: [{ /*|*/ }] })withf<T extends X[]>(o: { items: T })).Fix
createArrayLiteralType, if the array literal node is inskipDirectInferenceNodes, create a distinct (uncached) array literal type and record it in a newskipDirectInferenceTypesset.isFromInferenceBlockedSourcealso treats types in that set as blocked.runWithInferenceBlockedFromSourceNodeclears the set together withskipDirectInferenceNodes.This only has an effect while the language service is running a query with inference blocked. Regular type checking is unchanged, and no compiler or fourslash baselines changed.
I also considered blocking an array literal type when one of its element types comes from a blocked source. That approach is fragile: it misses union-reduced element types and non-object elements. It also wouldn't handle arrays nested in object literals as directly as recording the type.
A new fourslash test,
completionsObjectLiteralInGenericTupleConstraint, covers all the cases from the issue, a plain array constraint, and an array nested in an object argument.Checklist
mainbranchnpx hereby testnpx hereby validate(build, test, lint, format)