Skip to content

Commit d080a3b

Browse files
committed
Add call tree logs
1 parent e411381 commit d080a3b

File tree

1 file changed

+152
-2
lines changed

1 file changed

+152
-2
lines changed

src/compiler/checker.ts

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
/* @internal */
22
namespace ts {
3+
function ternaryToString(ret: Ternary) {
4+
return ret === Ternary.True
5+
? "True"
6+
: ret === Ternary.False
7+
? "False"
8+
: ret === Ternary.Maybe
9+
? "Maybe"
10+
: "Error";
11+
}
12+
313
const ambientModuleSymbolRegex = /^".+"$/;
414

515
let nextSymbolId = 1;
@@ -44,6 +54,52 @@ namespace ts {
4454
let requestedExternalEmitHelpers: ExternalEmitHelpers;
4555
let externalHelpersModule: Symbol;
4656

57+
// @ts-ignore
58+
const logEnable = process.env.CALL_TREE && process.env.CALL_TREE.match(/full_steam/gi);
59+
const excludes = (process.env.CALL_TREE || "").split("-").slice(1);
60+
61+
// Log stuff
62+
let level = 0;
63+
let currentFnNames: string[] = [];
64+
const log = (...args: any[]) => {
65+
const fnName = currentFnNames[currentFnNames.length-1]
66+
// @ts-ignore
67+
if (logEnable && !excludes.includes(fnName)) {
68+
// @ts-ignore
69+
console.log(" → ".repeat(level) + args.join(" "));
70+
}
71+
};
72+
73+
const callsToBreakOn = ["propertiesRelatedTo(C<T>,A,true)"];
74+
75+
const wrapLogCustom = <M extends any[], T>(printArgs: (...args: M) => string, printRet: (ret: T) => string) => {
76+
return (fn: (...args: M) => T) => {
77+
const functionName = fn.name;
78+
return (...args: M) => {
79+
const fnCallString = `${functionName}(${printArgs(...args)})`;
80+
currentFnNames.push(functionName);
81+
log(`${fnCallString}`);
82+
level += 1;
83+
if (callsToBreakOn.indexOf(fnCallString) !== -1) {
84+
debugger;
85+
}
86+
const ret = fn(...args);
87+
level -= 1;
88+
log(`${fnCallString} = ${printRet(ret)}`);
89+
currentFnNames.pop();
90+
return ret;
91+
};
92+
};
93+
};
94+
95+
const wrapLogUsual = wrapLogCustom(
96+
(type: Type, ...args: any[]) => `${typeToString(type)}${args.length > 0 ? "," + args.join(",") : ""}`,
97+
(ret: Type | undefined) => `${ret && typeToString(ret)}`
98+
);
99+
const wrapLog = <M extends any[], A extends Type | undefined>(fn: (type: Type, ...args: M) => A): (type: Type, ...args: M) => A => {
100+
return wrapLogUsual(fn as any) as any;
101+
};
102+
47103
// tslint:disable variable-name
48104
const Symbol = objectAllocator.getSymbolConstructor();
49105
const Type = objectAllocator.getTypeConstructor();
@@ -81,6 +137,29 @@ namespace ts {
81137
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
82138
let apparentArgumentCount: number | undefined;
83139

140+
// @ts-ignore
141+
getBaseConstraintOfType = wrapLog(getBaseConstraintOfType)
142+
// @ts-ignore
143+
getConstraintOfType = wrapLog(getConstraintOfType)
144+
// @ts-ignore
145+
getConstraintOfDistributiveConditionalType = wrapLog(getConstraintOfDistributiveConditionalType)
146+
// @ts-ignore
147+
getResolvedBaseConstraint = wrapLog(getResolvedBaseConstraint)
148+
149+
const wrapIsDeeplyNestedType = wrapLogCustom(
150+
(type: Type) => `${typeToString(type)}`,
151+
(ret: boolean) => `${ret}`
152+
)
153+
// @ts-ignore
154+
isDeeplyNestedType = wrapIsDeeplyNestedType(isDeeplyNestedType)
155+
156+
const wrapCheckTypeRelatedTo = wrapLogCustom(
157+
(source: Type, target: Type, ..._rest: any[]) => `${typeToString(source)}, ${typeToString(target)}`,
158+
(ret: boolean) => ret ? "true" : "false"
159+
);
160+
// @ts-ignore
161+
checkTypeRelatedTo = wrapCheckTypeRelatedTo(checkTypeRelatedTo)
162+
84163
// for public members that accept a Node or one of its subtypes, we must guard against
85164
// synthetic nodes created during transformations by calling `getParseTreeNode`.
86165
// for most of these, we perform the guard only on `checker` to avoid any possible
@@ -3035,7 +3114,11 @@ namespace ts {
30353114
if (maxLength && result && result.length >= maxLength) {
30363115
return result.substr(0, maxLength - "...".length) + "...";
30373116
}
3038-
return result;
3117+
function toZeroOne(str: "Z" | "O") { return str === "O" ? 1 : 0 }
3118+
return result.replace(
3119+
/(Z|O), (Z|O), (Z|O), (Z|O)/gi,
3120+
(_a: any, ...match: any[]) => `${toZeroOne(match[0])*1 + toZeroOne(match[1])*2 + toZeroOne(match[2])*4 + toZeroOne(match[3])*8}`
3121+
);
30393122
}
30403123

30413124
function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags {
@@ -6921,12 +7004,14 @@ namespace ts {
69217004
// over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T'
69227005
// removes 'undefined' from T.
69237006
if (type.root.isDistributive) {
7007+
log(`ConditionalType ${typeToString(type)} isDistributive`);
69247008
const simplified = getSimplifiedType(type.checkType);
69257009
const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
69267010
if (constraint) {
69277011
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
69287012
const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
69297013
if (!(instantiated.flags & TypeFlags.Never)) {
7014+
log(`getConditionalTypeInstantiation(${typeToString(type)}, combineTypeMappers(makeUnaryTypeMapper(${typeToString(type.root.checkType)}, ${typeToString(constraint)}), type.mapper)) = ${typeToString(instantiated)}`);
69307015
return instantiated;
69317016
}
69327017
}
@@ -6981,9 +7066,11 @@ namespace ts {
69817066

69827067
function getBaseConstraintOfType(type: Type): Type | undefined {
69837068
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) {
7069+
log(`(getResolvedBaseConstraint/undefined path)`);
69847070
const constraint = getResolvedBaseConstraint(<InstantiableType | UnionOrIntersectionType>type);
69857071
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
69867072
}
7073+
log(`(keyofConstraintType/undefined path)`);
69877074
return type.flags & TypeFlags.Index ? keyofConstraintType : undefined;
69887075
}
69897076

@@ -7005,6 +7092,13 @@ namespace ts {
70057092
* circularly references the type variable.
70067093
*/
70077094
function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type {
7095+
// @ts-ignore
7096+
getImmediateBaseConstraint = wrapLog(getImmediateBaseConstraint)
7097+
// @ts-ignore
7098+
getBaseConstraint = wrapLog(getBaseConstraint)
7099+
// @ts-ignore
7100+
computeBaseConstraint = wrapLog(computeBaseConstraint)
7101+
70087102
let nonTerminating = false;
70097103
return type.resolvedBaseConstraint ||
70107104
(type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type));
@@ -7045,11 +7139,18 @@ namespace ts {
70457139
constraint :
70467140
getBaseConstraint(constraint);
70477141
}
7142+
const UNIA = TypeFlags.Union;
7143+
const INTERSECTIA = TypeFlags.Intersection;
70487144
if (t.flags & TypeFlags.UnionOrIntersection) {
7145+
if (typeToString(t) === "any[] & T") {
7146+
log(UNIA + " " + INTERSECTIA);
7147+
debugger;
7148+
}
70497149
const types = (<UnionOrIntersectionType>t).types;
70507150
const baseTypes: Type[] = [];
70517151
for (const type of types) {
70527152
const baseType = getBaseConstraint(type);
7153+
log(`getBaseConstraint(${typeToString(type)}) = ${baseType && typeToString(baseType)}`);
70537154
if (baseType) {
70547155
baseTypes.push(baseType);
70557156
}
@@ -11002,6 +11103,27 @@ namespace ts {
1100211103
errorOutputContainer?: { error?: Diagnostic }
1100311104
): boolean {
1100411105

11106+
const wrapIsRelatedTo = wrapLogCustom(
11107+
(source: Type, target: Type, ..._rest: any[]) => `${typeToString(source)},${typeToString(target)}`,
11108+
ternaryToString
11109+
);
11110+
// @ts-ignore
11111+
isRelatedTo = wrapIsRelatedTo(isRelatedTo)
11112+
11113+
const wrapStructuredTypeRelatedTo = wrapLogCustom(
11114+
(source: Type, target: Type, reportErrors: boolean) => `${typeToString(source)},${typeToString(target)},${reportErrors}`,
11115+
ternaryToString
11116+
);
11117+
// @ts-ignore
11118+
structuredTypeRelatedTo = wrapStructuredTypeRelatedTo(structuredTypeRelatedTo)
11119+
11120+
const wrapPropertiesRelatedTo = wrapLogCustom(
11121+
(source: Type, target: Type, reportErrors: boolean) => `${typeToString(source)},${typeToString(target)},${reportErrors}`,
11122+
ternaryToString
11123+
);
11124+
// @ts-ignore
11125+
propertiesRelatedTo = wrapPropertiesRelatedTo(propertiesRelatedTo)
11126+
1100511127
let errorInfo: DiagnosticMessageChain | undefined;
1100611128
let maybeKeys: string[];
1100711129
let sourceStack: Type[];
@@ -11114,6 +11236,26 @@ namespace ts {
1111411236
* * Ternary.False if they are not related.
1111511237
*/
1111611238
function isRelatedTo(source: Type, target: Type, reportErrors = false, headMessage?: DiagnosticMessage): Ternary {
11239+
const relationType =
11240+
relation === assignableRelation
11241+
? "assignable"
11242+
: relation === identityRelation
11243+
? "identical"
11244+
: relation === comparableRelation
11245+
? "comparable"
11246+
: relation === definitelyAssignableRelation
11247+
? "definitely assignable"
11248+
: relation === subtypeRelation
11249+
? "subtype"
11250+
: relation === enumRelation
11251+
? "enum"
11252+
: "unknown relation";
11253+
log(relationType + ": " + typeToString(source) + " -> " + typeToString(target));
11254+
// @ts-ignore
11255+
if (process.env.BREAK_ON && typeToString(source) === process.env.BREAK_ON) {
11256+
debugger;
11257+
}
11258+
1111711259
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
1111811260
source = (<LiteralType>source).regularType;
1111911261
}
@@ -11749,13 +11891,19 @@ namespace ts {
1174911891
}
1175011892
else if (relation !== definitelyAssignableRelation) {
1175111893
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
11894+
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
11895+
11896+
log("distributive constraint of", typeToString(source), "is", distributiveConstraint && typeToString(distributiveConstraint));
11897+
log("default constraint of", typeToString(source), "is", defaultConstraint && typeToString(defaultConstraint));
11898+
1175211899
if (distributiveConstraint) {
11900+
log("distributive constraint of", typeToString(source), "is", typeToString(distributiveConstraint));
1175311901
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
1175411902
errorInfo = saveErrorInfo;
1175511903
return result;
1175611904
}
1175711905
}
11758-
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
11906+
1175911907
if (defaultConstraint) {
1176011908
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
1176111909
errorInfo = saveErrorInfo;
@@ -11923,6 +12071,7 @@ namespace ts {
1192312071
const properties = getPropertiesOfObjectType(target);
1192412072
for (const targetProp of properties) {
1192512073
if (!(targetProp.flags & SymbolFlags.Prototype)) {
12074+
log(`Verifying: `, targetProp.escapedName)
1192612075
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
1192712076
if (sourceProp && sourceProp !== targetProp) {
1192812077
if (isIgnoredJsxProperty(source, sourceProp, getTypeOfSymbol(targetProp))) {
@@ -12443,6 +12592,7 @@ namespace ts {
1244312592
if (count >= 5) return true;
1244412593
}
1244512594
}
12595+
log(`nesting depth ${typeToString(type)}: ${count}`);
1244612596
}
1244712597
}
1244812598
return false;

0 commit comments

Comments
 (0)