Skip to content

Commit d4da199

Browse files
committed
Merge branch 'main' into goToDefContext
2 parents 0b89ce4 + a89f416 commit d4da199

28 files changed

+1396
-271
lines changed

package-lock.json

Lines changed: 264 additions & 264 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler/checker.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10519,7 +10519,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1051910519
// function/class/{} initializers are themselves containers, so they won't merge in the same way as other initializers
1052010520
const container = getAssignedExpandoInitializer(symbol.valueDeclaration);
1052110521
if (container) {
10522-
const tag = getJSDocTypeTag(container);
10522+
const tag = isInJSFile(container) ? getJSDocTypeTag(container) : undefined;
1052310523
if (tag && tag.typeExpression) {
1052410524
return getTypeFromTypeNode(tag.typeExpression);
1052510525
}
@@ -22927,7 +22927,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2292722927
return propType;
2292822928
}
2292922929
if (everyType(type, isTupleType)) {
22930-
return mapType(type, t => getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType);
22930+
return mapType(type, t => {
22931+
const tupleType = t as TupleTypeReference;
22932+
const restType = getRestTypeOfTupleType(tupleType);
22933+
if (!restType) {
22934+
return undefinedType;
22935+
}
22936+
if (compilerOptions.noUncheckedIndexedAccess &&
22937+
index >= tupleType.target.fixedLength + getEndElementCount(tupleType.target, ElementFlags.Fixed)) {
22938+
return getUnionType([restType, undefinedType]);
22939+
}
22940+
return restType;
22941+
});
2293122942
}
2293222943
return undefined;
2293322944
}
@@ -26273,7 +26284,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2627326284
return declaredType;
2627426285
}
2627526286
// for (const _ in ref) acts as a nonnull on ref
26276-
if (isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement && isMatchingReference(reference, node.parent.parent.expression)) {
26287+
if (
26288+
isVariableDeclaration(node) &&
26289+
node.parent.parent.kind === SyntaxKind.ForInStatement &&
26290+
(isMatchingReference(reference, node.parent.parent.expression) || optionalChainContainsReference(node.parent.parent.expression, reference))
26291+
) {
2627726292
return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent))));
2627826293
}
2627926294
// Assignment doesn't affect reference

src/compiler/program.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,14 +961,14 @@ export function createModuleResolutionLoader(
961961
): ResolutionLoader<StringLiteralLike, ResolvedModuleWithFailedLookupLocations, SourceFile> {
962962
return {
963963
nameAndMode: moduleResolutionNameAndModeGetter,
964-
resolve: (moduleName, resoluionMode) => resolveModuleName(
964+
resolve: (moduleName, resolutionMode) => resolveModuleName(
965965
moduleName,
966966
containingFile,
967967
options,
968968
host,
969969
cache,
970970
redirectedReference,
971-
resoluionMode,
971+
resolutionMode,
972972
),
973973
};
974974
}

src/compiler/transformers/module/module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,9 @@ export function transformModule(context: TransformationContext): (x: SourceFile
850850
}
851851

852852
function visitImportCallExpression(node: ImportCall): Expression {
853+
if (moduleKind === ModuleKind.None && languageVersion >= ScriptTarget.ES2020) {
854+
return visitEachChild(node, visitor, context);
855+
}
853856
const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions);
854857
const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression);
855858
// Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output.

src/server/session.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,12 @@ function getPerProjectReferences<TResult>(
730730
if (resultsMap.has(project)) continue;
731731
if (isLocationProjectReferenceRedirect(project, location)) continue;
732732

733+
// The project could be dirty and could no longer contain the location's file after it's updated,
734+
// so we need to update the project and check if it still contains the file.
735+
updateProjectIfDirty(project);
736+
if (!project.containsFile(toNormalizedPath(location.fileName))) {
737+
continue;
738+
}
733739
const projectResults = searchPosition(project, location);
734740
resultsMap.set(project, projectResults ?? emptyArray);
735741
searchedProjectKeys.add(getProjectKey(project));

src/testRunner/tests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import "./unittests/services/extract/constants";
5353
import "./unittests/services/extract/functions";
5454
import "./unittests/services/extract/symbolWalker";
5555
import "./unittests/services/extract/ranges";
56+
import "./unittests/services/findAllReferences";
5657
import "./unittests/services/hostNewLineSupport";
5758
import "./unittests/services/languageService";
5859
import "./unittests/services/organizeImports";
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { protocol } from "../../_namespaces/ts.server";
2+
import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession } from "../tsserver/helpers";
3+
import { createServerHost, File } from "../virtualFileSystemWithWatch";
4+
5+
describe("unittests:: services:: findAllReferences", () => {
6+
it("does not try to open a file in a project that was updated and no longer has the file", () => {
7+
const files: File[] = [
8+
{
9+
path: "/packages/babel-loader/tsconfig.json",
10+
content:
11+
`
12+
{
13+
"compilerOptions": {
14+
"target": "ES2018",
15+
"module": "commonjs",
16+
"strict": true,
17+
"esModuleInterop": true,
18+
"composite": true,
19+
"rootDir": "src",
20+
"outDir": "dist"
21+
},
22+
"include": ["src"],
23+
"references": [{"path": "../core"}]
24+
}
25+
`
26+
},
27+
{
28+
path: "/packages/babel-loader/src/index.ts",
29+
content:
30+
`
31+
import type { Foo } from "../../core/src/index.js";
32+
`
33+
},
34+
{
35+
path: "/packages/core/tsconfig.json",
36+
content:
37+
`
38+
{
39+
"compilerOptions": {
40+
"target": "ES2018",
41+
"module": "commonjs",
42+
"strict": true,
43+
"esModuleInterop": true,
44+
"composite": true,
45+
"rootDir": "./src",
46+
"outDir": "./dist",
47+
},
48+
"include": ["./src"]
49+
}
50+
`
51+
},
52+
{
53+
path: "/packages/core/src/index.ts",
54+
content:
55+
`
56+
import { Bar } from "./loading-indicator.js";
57+
export type Foo = {};
58+
const bar: Bar = {
59+
prop: 0
60+
}
61+
`
62+
},
63+
{
64+
path: "/packages/core/src/loading-indicator.ts",
65+
content:
66+
`
67+
export interface Bar {
68+
prop: number;
69+
}
70+
const bar: Bar = {
71+
prop: 1
72+
}
73+
`
74+
},
75+
];
76+
const host = createServerHost(files);
77+
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
78+
// Open files in the two configured projects
79+
session.executeCommandSeq<protocol.UpdateOpenRequest>({
80+
command: protocol.CommandTypes.UpdateOpen,
81+
arguments: {
82+
openFiles: [
83+
{
84+
file: files[1].path, // babel-loader/src/index.ts
85+
fileContent: files[1].content,
86+
}
87+
]
88+
}
89+
});
90+
session.executeCommandSeq<protocol.UpdateOpenRequest>({
91+
command: protocol.CommandTypes.UpdateOpen,
92+
arguments: {
93+
openFiles: [
94+
{
95+
file: files[3].path, // core/src/index.ts
96+
fileContent: files[3].content,
97+
}
98+
]
99+
}
100+
});
101+
// Now change `babel-loader` project to no longer import `core` project
102+
session.executeCommandSeq<protocol.UpdateOpenRequest>({
103+
command: protocol.CommandTypes.UpdateOpen,
104+
arguments: {
105+
changedFiles: [
106+
{
107+
fileName: files[1].path,
108+
textChanges: [
109+
{
110+
start: {
111+
line: 1,
112+
offset: 26
113+
},
114+
end: {
115+
line: 1,
116+
offset: 26
117+
},
118+
newText: "// comment",
119+
}
120+
]
121+
}
122+
]
123+
}
124+
});
125+
const loadingIndicatorScriptInfo = session.getProjectService().getScriptInfo(files[3].path)!;
126+
// At this point, we haven't updated `babel-loader` project yet,
127+
// so `babel-loader` is still a containing project of `loading-indicator` file.
128+
assert(loadingIndicatorScriptInfo.containingProjects.find(p => p.projectName === "/packages/babel-loader/tsconfig.json"));
129+
// When calling find all references,
130+
// we shouldn't crash due to using outdated information on a file's containig projects.
131+
session.executeCommandSeq<protocol.ReferencesRequest>({
132+
command: protocol.CommandTypes.References,
133+
arguments: {
134+
file: files[3].path, // core/src/index.ts
135+
line: 5, // `prop`
136+
offset: 5,
137+
}
138+
});
139+
baselineTsserverLogs("findAllReferences", "does not try to open a file in a project that was updated and no longer has the file", session);
140+
});
141+
});

tests/baselines/reference/controlFlowOptionalChain.errors.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,4 +773,21 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(567,21): error T
773773
console.log("I should ALSO be reachable");
774774
}
775775
}
776-
776+
777+
778+
// Repro from #51941
779+
780+
type Test5 = {
781+
main?: {
782+
childs: Record<string, Test5>;
783+
};
784+
};
785+
786+
function f50(obj: Test5) {
787+
for (const key in obj.main?.childs) {
788+
if (obj.main.childs[key] === obj) {
789+
return obj;
790+
}
791+
}
792+
return null;
793+
}

tests/baselines/reference/controlFlowOptionalChain.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,24 @@ while (arr[i]?.tag === "left") {
588588
console.log("I should ALSO be reachable");
589589
}
590590
}
591-
591+
592+
593+
// Repro from #51941
594+
595+
type Test5 = {
596+
main?: {
597+
childs: Record<string, Test5>;
598+
};
599+
};
600+
601+
function f50(obj: Test5) {
602+
for (const key in obj.main?.childs) {
603+
if (obj.main.childs[key] === obj) {
604+
return obj;
605+
}
606+
}
607+
return null;
608+
}
592609

593610
//// [controlFlowOptionalChain.js]
594611
"use strict";
@@ -1091,3 +1108,12 @@ while (((_u = arr[i]) === null || _u === void 0 ? void 0 : _u.tag) === "left") {
10911108
console.log("I should ALSO be reachable");
10921109
}
10931110
}
1111+
function f50(obj) {
1112+
var _a;
1113+
for (var key in (_a = obj.main) === null || _a === void 0 ? void 0 : _a.childs) {
1114+
if (obj.main.childs[key] === obj) {
1115+
return obj;
1116+
}
1117+
}
1118+
return null;
1119+
}

tests/baselines/reference/controlFlowOptionalChain.symbols

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,3 +1832,48 @@ while (arr[i]?.tag === "left") {
18321832
}
18331833
}
18341834

1835+
1836+
// Repro from #51941
1837+
1838+
type Test5 = {
1839+
>Test5 : Symbol(Test5, Decl(controlFlowOptionalChain.ts, 588, 1))
1840+
1841+
main?: {
1842+
>main : Symbol(main, Decl(controlFlowOptionalChain.ts, 593, 14))
1843+
1844+
childs: Record<string, Test5>;
1845+
>childs : Symbol(childs, Decl(controlFlowOptionalChain.ts, 594, 10))
1846+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
1847+
>Test5 : Symbol(Test5, Decl(controlFlowOptionalChain.ts, 588, 1))
1848+
1849+
};
1850+
};
1851+
1852+
function f50(obj: Test5) {
1853+
>f50 : Symbol(f50, Decl(controlFlowOptionalChain.ts, 597, 2))
1854+
>obj : Symbol(obj, Decl(controlFlowOptionalChain.ts, 599, 13))
1855+
>Test5 : Symbol(Test5, Decl(controlFlowOptionalChain.ts, 588, 1))
1856+
1857+
for (const key in obj.main?.childs) {
1858+
>key : Symbol(key, Decl(controlFlowOptionalChain.ts, 600, 13))
1859+
>obj.main?.childs : Symbol(childs, Decl(controlFlowOptionalChain.ts, 594, 10))
1860+
>obj.main : Symbol(main, Decl(controlFlowOptionalChain.ts, 593, 14))
1861+
>obj : Symbol(obj, Decl(controlFlowOptionalChain.ts, 599, 13))
1862+
>main : Symbol(main, Decl(controlFlowOptionalChain.ts, 593, 14))
1863+
>childs : Symbol(childs, Decl(controlFlowOptionalChain.ts, 594, 10))
1864+
1865+
if (obj.main.childs[key] === obj) {
1866+
>obj.main.childs : Symbol(childs, Decl(controlFlowOptionalChain.ts, 594, 10))
1867+
>obj.main : Symbol(main, Decl(controlFlowOptionalChain.ts, 593, 14))
1868+
>obj : Symbol(obj, Decl(controlFlowOptionalChain.ts, 599, 13))
1869+
>main : Symbol(main, Decl(controlFlowOptionalChain.ts, 593, 14))
1870+
>childs : Symbol(childs, Decl(controlFlowOptionalChain.ts, 594, 10))
1871+
>key : Symbol(key, Decl(controlFlowOptionalChain.ts, 600, 13))
1872+
>obj : Symbol(obj, Decl(controlFlowOptionalChain.ts, 599, 13))
1873+
1874+
return obj;
1875+
>obj : Symbol(obj, Decl(controlFlowOptionalChain.ts, 599, 13))
1876+
}
1877+
}
1878+
return null;
1879+
}

0 commit comments

Comments
 (0)