Skip to content

Commit

Permalink
Merge pull request #129 from bloomberg/isolated-declarations-use-tsc-…
Browse files Browse the repository at this point in the history
…resolver

TSC in isolated declaration will still use the type checker to print types
  • Loading branch information
dragomirtitian authored Dec 5, 2023
2 parents 4554796 + 2c0bf81 commit d91c282
Show file tree
Hide file tree
Showing 297 changed files with 28,904 additions and 958 deletions.
25 changes: 2 additions & 23 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ import {
isAssignmentTarget,
isAutoAccessorPropertyDeclaration,
isAwaitExpression,
isBigIntLiteral,
isBinaryExpression,
isBindableObjectDefinePropertyCall,
isBindableStaticElementAccessExpression,
Expand Down Expand Up @@ -678,6 +677,7 @@ import {
isPartOfTypeQuery,
isPlainJsFile,
isPrefixUnaryExpression,
isPrimitiveLiteralValue,
isPrivateIdentifier,
isPrivateIdentifierClassElementDeclaration,
isPrivateIdentifierPropertyAccessExpression,
Expand Down Expand Up @@ -721,7 +721,6 @@ import {
isSuperCall,
isSuperProperty,
isTaggedTemplateExpression,
isTemplateExpression,
isTemplateSpan,
isThisContainerOrFunctionBlock,
isThisIdentifier,
Expand Down Expand Up @@ -47885,26 +47884,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return undefined;
}

function isPrimitiveLiteralValue(node: Expression): boolean {
if (isNumericLiteral(node) || isBigIntLiteral(node) || isStringLiteralLike(node)) return true;

if (node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) return true;

if (isPrefixUnaryExpression(node)) {
const operand = node.operand;
if (node.operator === SyntaxKind.MinusToken) {
return isNumericLiteral(operand) || isBigIntLiteral(operand);
}
if (node.operator === SyntaxKind.PlusToken) {
return isNumericLiteral(operand);
}
}
if (isTemplateExpression(node)) {
return node.templateSpans.every(t => isPrimitiveLiteralValue(t.expression));
}
return false;
}

function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean {
if (isDeclarationReadonly(node) || (isVariableDeclaration(node) && isVarConstLike(node)) || isEnumMember(node)) {
if (compilerOptions.isolatedDeclarations) {
Expand All @@ -47916,7 +47895,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function isLiteralComputedName(node: ComputedPropertyName) {
const expression = node.expression;
if (isPrimitiveLiteralValue(expression)) {
if (isPrimitiveLiteralValue(expression, /*includeBigInt*/ false)) {
return true;
}
const type = getTypeOfExpression(expression);
Expand Down
78 changes: 57 additions & 21 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals
*
* @internal
*/
export function transformDeclarations(context: TransformationContext) {
export function transformDeclarations(context: TransformationContext, _useTscEmit = true) {
const throwDiagnostic = () => Debug.fail("Diagnostic emitted without context");
let getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic = throwDiagnostic;
let needsDeclare = true;
Expand All @@ -318,20 +318,30 @@ export function transformDeclarations(context: TransformationContext) {
let refs: Map<NodeId, SourceFile>;
let libs: Map<string, boolean>;
let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass
const { localInferenceResolver, isolatedDeclarations, host, resolver, symbolTracker, ensureNoInitializer } = createTransformerServices();
const { localInferenceResolver, isolatedDeclarations, host, resolver, symbolTracker, ensureNoInitializer, useTscEmit } = createTransformerServices();
const options = context.getCompilerOptions();
const { noResolve, stripInternal } = options;
return transformRoot;

function createTransformerServices(): {
isolatedDeclarations: true;
useTscEmit: false;
resolver: IsolatedEmitResolver;
localInferenceResolver: LocalInferenceResolver;
host: undefined;
symbolTracker: undefined;
ensureNoInitializer: (node: CanHaveLiteralInitializer) => Expression | undefined;
} | {
isolatedDeclarations: true;
useTscEmit: true;
resolver: EmitResolver;
localInferenceResolver: LocalInferenceResolver;
host: EmitHost;
symbolTracker: SymbolTracker;
ensureNoInitializer: (node: CanHaveLiteralInitializer) => Expression | undefined;
} | {
isolatedDeclarations: false;
useTscEmit: false;
resolver: EmitResolver;
localInferenceResolver: undefined;
host: EmitHost;
Expand All @@ -353,30 +363,53 @@ export function transformDeclarations(context: TransformationContext) {
});

if (isolatedDeclarations) {
const resolver: IsolatedEmitResolver = context.getEmitResolver();
// Ideally nothing should require the symbol tracker in isolated declarations mode.
// createLiteralConstValue is teh one exception
const emptySymbolTracker = {};
return {
isolatedDeclarations,
resolver,
localInferenceResolver,
symbolTracker: undefined,
host: undefined,
ensureNoInitializer: (node: CanHaveLiteralInitializer) => {
if (shouldPrintWithInitializer(node)) {
return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, emptySymbolTracker); // TODO: Make safe
}
return undefined;
},
};
if (!_useTscEmit) {
const resolver: IsolatedEmitResolver = context.getEmitResolver();
// Ideally nothing should require the symbol tracker in isolated declarations mode.
// createLiteralConstValue is the one exception
const emptySymbolTracker = {};
return {
isolatedDeclarations,
useTscEmit: false,
resolver,
localInferenceResolver,
symbolTracker: undefined,
host: undefined,
ensureNoInitializer: (node: CanHaveLiteralInitializer) => {
if (shouldPrintWithInitializer(node)) {
return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, emptySymbolTracker); // TODO: Make safe
}
return undefined;
},
};
}
else {
const host = context.getEmitHost();
const resolver: EmitResolver = context.getEmitResolver();
const symbolTracker = createSymbolTracker(resolver, host);
return {
isolatedDeclarations,
useTscEmit: true,
resolver,
localInferenceResolver,
symbolTracker,
host,
ensureNoInitializer: (node: CanHaveLiteralInitializer) => {
if (shouldPrintWithInitializer(node)) {
return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe
}
return undefined;
},
};
}
}
else {
const host = context.getEmitHost();
const resolver = context.getEmitResolver();
const symbolTracker: SymbolTracker = createSymbolTracker(resolver, host);
return {
isolatedDeclarations,
useTscEmit: false,
localInferenceResolver,
resolver,
symbolTracker,
Expand Down Expand Up @@ -918,7 +951,10 @@ export function transformDeclarations(context: TransformationContext) {
return;
}
if (isolatedDeclarations) {
return localInferenceResolver.fromInitializer(node, type, currentSourceFile);
const { typeNode, isInvalid } = localInferenceResolver.fromInitializer(node, type, currentSourceFile);
if (!useTscEmit || isInvalid) {
return typeNode;
}
}
const shouldUseResolverType = node.kind === SyntaxKind.Parameter &&
(resolver.isRequiredInitializedParameter(node) ||
Expand Down Expand Up @@ -1571,7 +1607,7 @@ export function transformDeclarations(context: TransformationContext) {
});
errorFallbackNode = input;
const type = isolatedDeclarations ?
localInferenceResolver.fromInitializer(input, /*type*/ undefined, currentSourceFile) :
localInferenceResolver.fromInitializer(input, /*type*/ undefined, currentSourceFile).typeNode :
resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker);
const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, type, /*initializer*/ undefined);
errorFallbackNode = undefined;
Expand Down
Loading

0 comments on commit d91c282

Please sign in to comment.