From 93f2d2b9a1b2f8861b49d76bb5e58f6e9f2b56ee Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 29 Jun 2022 16:30:57 -0700 Subject: [PATCH] Add variance results to tracing, capture variance verification on annotated type params (#49712) * Add variance results to tracing * Tweak format, prohibit `results` on `E` events --- src/compiler/checker.ts | 4 +++- src/compiler/debug.ts | 17 +++++++++++++++++ src/compiler/tracing.ts | 9 +++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cadf9799424..13c50d3b770 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20785,7 +20785,7 @@ namespace ts { variances.push(variance); } links.variances = variances; - tracing?.pop(); + tracing?.pop({ variances: variances.map(Debug.formatVariance) }); } return links.variances; } @@ -35055,12 +35055,14 @@ namespace ts { error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types); } else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) { + tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), id: getTypeId(typeParameter) }); const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck); const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck); const saveVarianceTypeParameter = typeParameter; varianceTypeParameter = typeParameter; checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation); varianceTypeParameter = saveVarianceTypeParameter; + tracing?.pop(); } } } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index d4644cd769b..f96e8441b0e 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -748,5 +748,22 @@ namespace ts { const deprecation = createDeprecation(options?.name ?? getFunctionName(func), options); return wrapFunction(deprecation, func); } + + export function formatVariance(varianceFlags: VarianceFlags) { + const variance = varianceFlags & VarianceFlags.VarianceMask; + let result = + variance === VarianceFlags.Invariant ? "in out" : + variance === VarianceFlags.Bivariant ? "[bivariant]" : + variance === VarianceFlags.Contravariant ? "in" : + variance === VarianceFlags.Covariant ? "out" : + variance === VarianceFlags.Independent ? "[independent]" : ""; + if (varianceFlags & VarianceFlags.Unmeasurable) { + result += " (unmeasurable)"; + } + else if (varianceFlags & VarianceFlags.Unreliable) { + result += " (unreliable)"; + } + return result; + } } } diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts index 4757ac72e1b..25765b7362a 100644 --- a/src/compiler/tracing.ts +++ b/src/compiler/tracing.ts @@ -131,9 +131,9 @@ namespace ts { // eslint-disable-line one-namespace-per-file } eventStack.push({ phase, name, args, time: 1000 * timestamp(), separateBeginAndEnd }); } - export function pop() { + export function pop(results?: Args) { Debug.assert(eventStack.length > 0); - writeStackEvent(eventStack.length - 1, 1000 * timestamp()); + writeStackEvent(eventStack.length - 1, 1000 * timestamp(), results); eventStack.length--; } export function popAll() { @@ -145,14 +145,15 @@ namespace ts { // eslint-disable-line one-namespace-per-file } // sample every 10ms const sampleInterval = 1000 * 10; - function writeStackEvent(index: number, endTime: number) { + function writeStackEvent(index: number, endTime: number, results?: Args) { const { phase, name, args, time, separateBeginAndEnd } = eventStack[index]; if (separateBeginAndEnd) { + Debug.assert(!results, "`results` are not supported for events with `separateBeginAndEnd`"); writeEvent("E", phase, name, args, /*extras*/ undefined, endTime); } // test if [time,endTime) straddles a sampling point else if (sampleInterval - (time % sampleInterval) <= endTime - time) { - writeEvent("X", phase, name, args, `"dur":${endTime - time}`, time); + writeEvent("X", phase, name, { ...args, results }, `"dur":${endTime - time}`, time); } }