mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Fix spurious circularity caused by removeOptionalityFromDeclaredType, cache result (#52696)
This commit is contained in:
@@ -1233,6 +1233,7 @@ const enum TypeSystemPropertyName {
|
||||
ResolvedTypeArguments,
|
||||
ResolvedBaseTypes,
|
||||
WriteType,
|
||||
ParameterInitializerContainsUndefined,
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -9983,6 +9984,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return !!(target as InterfaceType).baseTypesResolved;
|
||||
case TypeSystemPropertyName.WriteType:
|
||||
return !!getSymbolLinks(target as Symbol).writeType;
|
||||
case TypeSystemPropertyName.ParameterInitializerContainsUndefined:
|
||||
return getNodeLinks(target as ParameterDeclaration).parameterInitializerContainsUndefined !== undefined;
|
||||
}
|
||||
return Debug.assertNever(propertyName);
|
||||
}
|
||||
@@ -27295,22 +27298,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0;
|
||||
}
|
||||
|
||||
function parameterInitializerContainsUndefined(declaration: ParameterDeclaration): boolean {
|
||||
const links = getNodeLinks(declaration);
|
||||
|
||||
if (links.parameterInitializerContainsUndefined === undefined) {
|
||||
if (!pushTypeResolution(declaration, TypeSystemPropertyName.ParameterInitializerContainsUndefined)) {
|
||||
reportCircularityError(declaration.symbol);
|
||||
return true;
|
||||
}
|
||||
|
||||
const containsUndefined = !!(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined);
|
||||
|
||||
if (!popTypeResolution()) {
|
||||
reportCircularityError(declaration.symbol);
|
||||
return true;
|
||||
}
|
||||
|
||||
links.parameterInitializerContainsUndefined = containsUndefined;
|
||||
}
|
||||
|
||||
return links.parameterInitializerContainsUndefined;
|
||||
}
|
||||
|
||||
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
|
||||
function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
|
||||
if (pushTypeResolution(declaration.symbol, TypeSystemPropertyName.DeclaredType)) {
|
||||
const annotationIncludesUndefined = strictNullChecks &&
|
||||
declaration.kind === SyntaxKind.Parameter &&
|
||||
declaration.initializer &&
|
||||
getTypeFacts(declaredType) & TypeFacts.IsUndefined &&
|
||||
!(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined);
|
||||
popTypeResolution();
|
||||
const removeUndefined = strictNullChecks &&
|
||||
declaration.kind === SyntaxKind.Parameter &&
|
||||
declaration.initializer &&
|
||||
getTypeFacts(declaredType) & TypeFacts.IsUndefined &&
|
||||
!parameterInitializerContainsUndefined(declaration);
|
||||
|
||||
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
|
||||
}
|
||||
else {
|
||||
reportCircularityError(declaration.symbol);
|
||||
return declaredType;
|
||||
}
|
||||
return removeUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
|
||||
}
|
||||
|
||||
function isConstraintPosition(type: Type, node: Node) {
|
||||
|
||||
@@ -5997,6 +5997,7 @@ export interface NodeLinks {
|
||||
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
|
||||
serializedTypes?: Map<string, SerializedTypeEntry>; // Collection of types serialized at this location
|
||||
decoratorSignature?: Signature; // Signature for decorator as if invoked by the runtime.
|
||||
parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined".
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -38,4 +38,36 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor", () => {
|
||||
verifyGetErrRequest({ session, host, files: ["^/untitled/ts-nul-authority/Untitled-1"] });
|
||||
baselineTsserverLogs("inconsistentErrorInEditor", "should not error", session);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsserver:: inconsistentErrorInEditor2", () => {
|
||||
it("should not error", () => {
|
||||
const host = createServerHost([]);
|
||||
const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger: createLoggerWithInMemoryLogs(host) });
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [],
|
||||
closedFiles: [],
|
||||
openFiles: [
|
||||
{
|
||||
file: "^/untitled/ts-nul-authority/Untitled-1",
|
||||
fileContent: "function fn(Foo: number) {\r\n type Foo = typeof Foo;\r\n return 0 as any as {x: Foo};\r\n}",
|
||||
scriptKindName: "TS"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
session.executeCommandSeq<ts.server.protocol.EncodedSemanticClassificationsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.EncodedSemanticClassificationsFull,
|
||||
arguments: {
|
||||
file: "^/untitled/ts-nul-authority/Untitled-1",
|
||||
start: 0,
|
||||
length: 128,
|
||||
format: "2020"
|
||||
}
|
||||
});
|
||||
verifyGetErrRequest({ session, host, files: ["^/untitled/ts-nul-authority/Untitled-1"] });
|
||||
baselineTsserverLogs("inconsistentErrorInEditor2", "should not error", session);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
Info 0 [00:00:02.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Info 1 [00:00:03.000] request:
|
||||
{
|
||||
"command": "updateOpen",
|
||||
"arguments": {
|
||||
"changedFiles": [],
|
||||
"closedFiles": [],
|
||||
"openFiles": [
|
||||
{
|
||||
"file": "^/untitled/ts-nul-authority/Untitled-1",
|
||||
"fileContent": "function fn(Foo: number) {\r\n type Foo = typeof Foo;\r\n return 0 as any as {x: Foo};\r\n}",
|
||||
"scriptKindName": "TS"
|
||||
}
|
||||
]
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Before request
|
||||
|
||||
PolledWatches::
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 2 [00:00:04.000] Search path: ^/untitled/ts-nul-authority
|
||||
Info 3 [00:00:05.000] For info: ^/untitled/ts-nul-authority/Untitled-1 :: No config files found.
|
||||
Info 4 [00:00:06.000] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
|
||||
Info 5 [00:00:07.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file
|
||||
Info 6 [00:00:08.000] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 7 [00:00:09.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 8 [00:00:10.000] Files (1)
|
||||
^/untitled/ts-nul-authority/Untitled-1
|
||||
|
||||
|
||||
^/untitled/ts-nul-authority/Untitled-1
|
||||
Root file specified for compilation
|
||||
|
||||
Info 9 [00:00:11.000] -----------------------------------------------
|
||||
Info 10 [00:00:12.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 10 [00:00:13.000] Files (1)
|
||||
|
||||
Info 10 [00:00:14.000] -----------------------------------------------
|
||||
Info 10 [00:00:15.000] Open files:
|
||||
Info 10 [00:00:16.000] FileName: ^/untitled/ts-nul-authority/Untitled-1 ProjectRootPath: undefined
|
||||
Info 10 [00:00:17.000] Projects: /dev/null/inferredProject1*
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 10 [00:00:18.000] response:
|
||||
{
|
||||
"response": true,
|
||||
"responseRequired": true
|
||||
}
|
||||
Info 11 [00:00:19.000] request:
|
||||
{
|
||||
"command": "encodedSemanticClassifications-full",
|
||||
"arguments": {
|
||||
"file": "^/untitled/ts-nul-authority/Untitled-1",
|
||||
"start": 0,
|
||||
"length": 128,
|
||||
"format": "2020"
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Before request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 12 [00:00:20.000] response:
|
||||
{
|
||||
"response": {
|
||||
"spans": [
|
||||
9,
|
||||
2,
|
||||
2817,
|
||||
12,
|
||||
3,
|
||||
1536,
|
||||
38,
|
||||
3,
|
||||
1537,
|
||||
51,
|
||||
3,
|
||||
1536,
|
||||
81,
|
||||
1,
|
||||
2561,
|
||||
84,
|
||||
3,
|
||||
1536
|
||||
],
|
||||
"endOfLineState": 0
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
Info 13 [00:00:21.000] request:
|
||||
{
|
||||
"command": "geterr",
|
||||
"arguments": {
|
||||
"delay": 0,
|
||||
"files": [
|
||||
"^/untitled/ts-nul-authority/Untitled-1"
|
||||
]
|
||||
},
|
||||
"seq": 3,
|
||||
"type": "request"
|
||||
}
|
||||
Before request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 14 [00:00:22.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
Before checking timeout queue length (1) and running
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 15 [00:00:23.000] event:
|
||||
{"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[]}}
|
||||
After checking timeout queue length (1) and running
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Before running immediate callbacks and checking length (1)
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 16 [00:00:24.000] event:
|
||||
{"seq":0,"type":"event","event":"semanticDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[]}}
|
||||
Before running immediate callbacks and checking length (1)
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Before running immediate callbacks and checking length (1)
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Info 17 [00:00:25.000] event:
|
||||
{"seq":0,"type":"event","event":"suggestionDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[]}}
|
||||
Info 18 [00:00:26.000] event:
|
||||
{"seq":0,"type":"event","event":"requestCompleted","body":{"request_seq":3}}
|
||||
Before running immediate callbacks and checking length (1)
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
Reference in New Issue
Block a user