diff --git a/internal/checker/jsx.go b/internal/checker/jsx.go index 27a4a67f486..c5093d570cc 100644 --- a/internal/checker/jsx.go +++ b/internal/checker/jsx.go @@ -225,7 +225,7 @@ func (c *Checker) getContextualTypeForJsxAttribute(attribute *ast.Node, contextF } func (c *Checker) getContextualJsxElementAttributesType(node *ast.Node, contextFlags ContextFlags) *Type { - if ast.IsJsxOpeningElement(node) && contextFlags != ContextFlagsCompletions { + if ast.IsJsxOpeningElement(node) && contextFlags != ContextFlagsIgnoreNodeInferences { index := c.findContextualNode(node.Parent, contextFlags == ContextFlagsNone) if index >= 0 { // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit diff --git a/internal/checker/services.go b/internal/checker/services.go index d4120fd22f9..111bec90458 100644 --- a/internal/checker/services.go +++ b/internal/checker/services.go @@ -314,7 +314,7 @@ func (c *Checker) shouldTreatPropertiesOfExternalModuleAsExports(resolvedExterna } func (c *Checker) GetContextualType(node *ast.Expression, contextFlags ContextFlags) *Type { - if contextFlags&ContextFlagsCompletions != 0 { + if contextFlags&ContextFlagsIgnoreNodeInferences != 0 { return runWithInferenceBlockedFromSourceNode(c, node, func() *Type { return c.getContextualType(node, contextFlags) }) } return c.getContextualType(node, contextFlags) @@ -891,27 +891,6 @@ func (c *Checker) GetTypeParameterAtPosition(s *Signature, pos int) *Type { return t } -func (c *Checker) GetContextualDeclarationsForObjectLiteralElement(objectLiteral *ast.Node, name string) []*ast.Node { - var result []*ast.Node - if t := c.getApparentTypeOfContextualType(objectLiteral, ContextFlagsNone); t != nil { - for _, t := range t.Distributed() { - prop := c.getPropertyOfType(t, name) - if prop != nil { - for _, declaration := range prop.Declarations { - result = core.AppendIfUnique(result, declaration) - } - } else { - for _, info := range c.getApplicableIndexInfos(t, c.getStringLiteralType(name)) { - if info.declaration != nil { - result = core.AppendIfUnique(result, info.declaration) - } - } - } - } - } - return result -} - // GetContextualTypeForArrayLiteralAtPosition returns the contextual type for an element at the given position // in an array with the given contextual type. func (c *Checker) GetContextualTypeForArrayLiteralAtPosition(contextualArrayType *Type, arrayLiteral *ast.Node, position int) *Type { diff --git a/internal/checker/types.go b/internal/checker/types.go index 8900314987d..80003c2d95f 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -35,11 +35,11 @@ const ( type ContextFlags uint32 const ( - ContextFlagsNone ContextFlags = 0 - ContextFlagsSignature ContextFlags = 1 << 0 // Obtaining contextual signature - ContextFlagsNoConstraints ContextFlags = 1 << 1 // Don't obtain type variable constraints - ContextFlagsCompletions ContextFlags = 1 << 2 // Ignore inference to current node and parent nodes out to the containing call for completions - ContextFlagsSkipBindingPatterns ContextFlags = 1 << 3 // Ignore contextual types applied by binding patterns + ContextFlagsNone ContextFlags = 0 + ContextFlagsSignature ContextFlags = 1 << 0 // Obtaining contextual signature + ContextFlagsNoConstraints ContextFlags = 1 << 1 // Don't obtain type variable constraints + ContextFlagsIgnoreNodeInferences ContextFlags = 1 << 2 // Ignore inference to current node and parent nodes out to the containing call for, for example, completions + ContextFlagsSkipBindingPatterns ContextFlags = 1 << 3 // Ignore contextual types applied by binding patterns ) type TypeFormatFlags uint32 diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 753a99df2e3..b0017989ac1 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -972,7 +972,7 @@ func (l *LanguageService) getCompletionData( } return globalsSearchContinue, nil } - completionsType := typeChecker.GetContextualType(objectLikeContainer, checker.ContextFlagsCompletions) + completionsType := typeChecker.GetContextualType(objectLikeContainer, checker.ContextFlagsIgnoreNodeInferences) t := core.IfElse(completionsType != nil, completionsType, instantiatedType) stringIndexType := typeChecker.GetStringIndexType(t) numberIndexType := typeChecker.GetNumberIndexType(t) @@ -1389,7 +1389,7 @@ func (l *LanguageService) getCompletionData( if attrsType == nil { return globalsSearchContinue, nil } - completionsType := typeChecker.GetContextualType(jsxContainer.Attributes(), checker.ContextFlagsCompletions) + completionsType := typeChecker.GetContextualType(jsxContainer.Attributes(), checker.ContextFlagsIgnoreNodeInferences) filteredSymbols, spreadMemberNames := filterJsxAttributes( getPropertiesForObjectExpression(attrsType, completionsType, jsxContainer.Attributes(), typeChecker), jsxContainer.Attributes().Properties(), @@ -2797,7 +2797,7 @@ func getContextualTypeForConditionalExpression(conditionalExpr *ast.Node, positi return typeChecker.GetContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex) } // Fall through to regular contextual type logic if not in an argument - contextualType := typeChecker.GetContextualType(conditionalExpr, checker.ContextFlagsCompletions) + contextualType := typeChecker.GetContextualType(conditionalExpr, checker.ContextFlagsIgnoreNodeInferences) if contextualType != nil { return contextualType } @@ -2885,7 +2885,7 @@ func getContextualType(previousToken *ast.Node, position int, file *ast.SourceFi // completion at `x ===/**/` return typeChecker.GetTypeAtLocation(parent.AsBinaryExpression().Left) } else { - contextualType := typeChecker.GetContextualType(previousToken, checker.ContextFlagsCompletions) + contextualType := typeChecker.GetContextualType(previousToken, checker.ContextFlagsIgnoreNodeInferences) if contextualType != nil { return contextualType } diff --git a/internal/ls/definition.go b/internal/ls/definition.go index 8e49d610243..732e5e6f664 100644 --- a/internal/ls/definition.go +++ b/internal/ls/definition.go @@ -227,12 +227,9 @@ func getDeclarationsFromLocation(c *checker.Checker, node *ast.Node) []*ast.Node symbol = resolved } } - if symbol.Flags&(ast.SymbolFlagsProperty|ast.SymbolFlagsMethod|ast.SymbolFlagsAccessor) != 0 && symbol.Parent != nil && symbol.Parent.Flags&ast.SymbolFlagsObjectLiteral != 0 { - if objectLiteral := core.FirstOrNil(symbol.Parent.Declarations); objectLiteral != nil { - if declarations := c.GetContextualDeclarationsForObjectLiteralElement(objectLiteral, symbol.Name); len(declarations) != 0 { - return declarations - } - } + objectLiteralElementDeclarations := getDeclarationsFromObjectLiteralElement(c, node) + if len(objectLiteralElementDeclarations) > 0 { + return objectLiteralElementDeclarations } return symbol.Declarations } @@ -250,19 +247,27 @@ func getDeclarationsFromObjectLiteralElement(c *checker.Checker, node *ast.Node) return nil } - // Get the contextual type of the object literal - objectLiteral := element.Parent - if objectLiteral == nil || !ast.IsObjectLiteralExpression(objectLiteral) { + contextualType := c.GetContextualType(element.Parent, checker.ContextFlagsNone) + if contextualType == nil { return nil } - // Get the name of the property - name := ast.GetTextOfPropertyName(element.Name()) - if name == "" { - return nil + properties := c.GetPropertySymbolsFromContextualType(element, contextualType, false /*unionSymbolOk*/) + if core.Some(properties, func(p *ast.Symbol) bool { + return p.ValueDeclaration != nil && ast.IsObjectLiteralExpression(p.ValueDeclaration.Parent) && ast.IsObjectLiteralElement(p.ValueDeclaration) && p.ValueDeclaration.Name() == node + }) { + if withoutNodeInferencesType := c.GetContextualType(element.Parent, checker.ContextFlagsIgnoreNodeInferences); withoutNodeInferencesType != nil { + if withoutNodeInferencesProperties := c.GetPropertySymbolsFromContextualType(element, withoutNodeInferencesType, false /*unionSymbolOk*/); len(withoutNodeInferencesProperties) > 0 { + properties = withoutNodeInferencesProperties + } + } } - return c.GetContextualDeclarationsForObjectLiteralElement(objectLiteral, name) + var result []*ast.Node + for _, prop := range properties { + result = append(result, prop.Declarations...) + } + return result } // Returns a CallLikeExpression where `node` is the target being invoked. diff --git a/internal/ls/string_completions.go b/internal/ls/string_completions.go index b69674aa73a..291deea8482 100644 --- a/internal/ls/string_completions.go +++ b/internal/ls/string_completions.go @@ -285,7 +285,7 @@ func (l *LanguageService) getStringLiteralCompletionEntries( uniques := &collections.Set[string]{} stringLiteralTypes := append( getStringLiteralTypes(typeChecker.GetContextualType(node, checker.ContextFlagsNone), uniques, typeChecker), - getStringLiteralTypes(typeChecker.GetContextualType(node, checker.ContextFlagsCompletions), uniques, typeChecker)..., + getStringLiteralTypes(typeChecker.GetContextualType(node, checker.ContextFlagsIgnoreNodeInferences), uniques, typeChecker)..., ) return toStringLiteralCompletionsFromTypes(stringLiteralTypes) } @@ -345,7 +345,7 @@ func (l *LanguageService) getStringLiteralCompletionEntries( return l.getStringLiteralCompletionsFromModuleNames(file, node, l.GetProgram(), typeChecker) case ast.KindCaseClause: tracker := newCaseClauseTracker(typeChecker, parent.Parent.AsCaseBlock().Clauses.Nodes) - contextualTypes := fromContextualType(checker.ContextFlagsCompletions, node, typeChecker) + contextualTypes := fromContextualType(checker.ContextFlagsIgnoreNodeInferences, node, typeChecker) if contextualTypes == nil { return nil } @@ -408,7 +408,7 @@ func (l *LanguageService) getStringLiteralCompletionEntries( fromTypes: fromContextualType(checker.ContextFlagsNone, node, typeChecker), } default: - result := fromContextualType(checker.ContextFlagsCompletions, node, typeChecker) + result := fromContextualType(checker.ContextFlagsIgnoreNodeInferences, node, typeChecker) if result != nil { return &stringLiteralCompletions{ fromTypes: result, @@ -543,7 +543,7 @@ func stringLiteralCompletionsForObjectLiteral( return nil } - completionsType := typeChecker.GetContextualType(objectLiteralExpression, checker.ContextFlagsCompletions) + completionsType := typeChecker.GetContextualType(objectLiteralExpression, checker.ContextFlagsIgnoreNodeInferences) symbols := getPropertiesForObjectExpression( contextualType, completionsType, diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc index 818d0381532..26eadd91106 100644 --- a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc +++ b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc @@ -37,11 +37,18 @@ // === goToDefinition === // === /goToDefinitionObjectLiteralProperties2.ts === +// type C = { +// <|[|foo|]: string;|> +// bar: number; +// }; +// +// --- (line: 6) skipped --- + // --- (line: 10) skipped --- // }); // // const result = fn({ -// <|[|foo|]/*GOTO DEF*/: ""|>, +// foo/*GOTO DEF*/: "", // bar: 1, // }); // @@ -52,11 +59,19 @@ // === goToDefinition === // === /goToDefinitionObjectLiteralProperties2.ts === +// type C = { +// foo: string; +// <|[|bar|]: number;|> +// }; +// +// declare function fn(arg: T): T; +// --- (line: 7) skipped --- + // --- (line: 11) skipped --- // // const result = fn({ // foo: "", -// <|[|bar|]/*GOTO DEF*/: 1|>, +// bar/*GOTO DEF*/: 1, // }); // // // this one shouldn't go to the constraint type diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc.diff deleted file mode 100644 index f0519212c83..00000000000 --- a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties2.baseline.jsonc.diff +++ /dev/null @@ -1,43 +0,0 @@ ---- old.goToDefinitionObjectLiteralProperties2.baseline.jsonc -+++ new.goToDefinitionObjectLiteralProperties2.baseline.jsonc -@@= skipped -36, +36 lines =@@ - - // === goToDefinition === - // === /goToDefinitionObjectLiteralProperties2.ts === --// type C = { --// <|[|foo|]: string;|> --// bar: number; --// }; --// --// --- (line: 6) skipped --- -- - // --- (line: 10) skipped --- - // }); - // - // const result = fn({ --// foo/*GOTO DEF*/: "", -+// <|[|foo|]/*GOTO DEF*/: ""|>, - // bar: 1, - // }); - // -@@= skipped -22, +15 lines =@@ - - // === goToDefinition === - // === /goToDefinitionObjectLiteralProperties2.ts === --// type C = { --// foo: string; --// <|[|bar|]: number;|> --// }; --// --// declare function fn(arg: T): T; --// --- (line: 7) skipped --- -- - // --- (line: 11) skipped --- - // - // const result = fn({ - // foo: "", --// bar/*GOTO DEF*/: 1, -+// <|[|bar|]/*GOTO DEF*/: 1|>, - // }); - // - // // this one shouldn't go to the constraint type \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc index 8bdd19a63b6..02596c81af2 100644 --- a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc +++ b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc @@ -23,7 +23,7 @@ // === goToDefinition === // === /goToDefinitionObjectLiteralProperties3.ts === // type A = { -// foo: unknown; +// <|[|foo|]: unknown;|> // }; // // type B = { @@ -37,5 +37,5 @@ // function test2(arg: T | B) {} // // test2({ -// <|[|foo|]/*GOTO DEF*/: 2|>, +// foo/*GOTO DEF*/: 2, // }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc.diff deleted file mode 100644 index cc0f356a38c..00000000000 --- a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToDefinitionObjectLiteralProperties3.baseline.jsonc.diff +++ /dev/null @@ -1,18 +0,0 @@ ---- old.goToDefinitionObjectLiteralProperties3.baseline.jsonc -+++ new.goToDefinitionObjectLiteralProperties3.baseline.jsonc -@@= skipped -22, +22 lines =@@ - // === goToDefinition === - // === /goToDefinitionObjectLiteralProperties3.ts === - // type A = { --// <|[|foo|]: unknown;|> -+// foo: unknown; - // }; - // - // type B = { -@@= skipped -14, +14 lines =@@ - // function test2(arg: T | B) {} - // - // test2({ --// foo/*GOTO DEF*/: 2, -+// <|[|foo|]/*GOTO DEF*/: 2|>, - // }); \ No newline at end of file