Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable JS emit for noCheck and noCheck for transpileModule #58364

Merged
merged 7 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 190 additions & 25 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
showInSimplifiedHelpView: false,
category: Diagnostics.Compiler_Diagnostics,
description: Diagnostics.Disable_full_type_checking_only_critical_parse_and_emit_errors_will_be_reported,
transpileOptionValue: undefined,
transpileOptionValue: true,
defaultValueDescription: false,
affectsSemanticDiagnostics: true,
affectsBuildInfo: true,
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
ModifierFlags,
Node,
NodeArray,
NodeCheckFlags,
NodeFlags,
nodeIsSynthesized,
noop,
Expand Down Expand Up @@ -455,6 +456,10 @@ export namespace Debug {
return formatEnum(flags, (ts as any).NodeFlags, /*isFlags*/ true);
}

export function formatNodeCheckFlags(flags: NodeCheckFlags | undefined): string {
return formatEnum(flags, (ts as any).NodeCheckFlags, /*isFlags*/ true);
}

export function formatModifierFlags(flags: ModifierFlags | undefined): string {
return formatEnum(flags, (ts as any).ModifierFlags, /*isFlags*/ true);
}
Expand Down
17 changes: 16 additions & 1 deletion src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ import {
isGeneratedPrivateIdentifier,
isIdentifier,
isImportAttributes,
isImportEqualsDeclaration,
isIncrementalCompilation,
isInJsonFile,
isJSDocLikeText,
Expand Down Expand Up @@ -793,6 +794,11 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
emitSkipped = true;
return;
}

if (compilerOptions.noCheck) {
(isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : filter(sourceFileOrBundle.sourceFiles, isSourceFileNotJson)).forEach(markLinkedReferences);
}

// Transform the source files
const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);

Expand Down Expand Up @@ -924,6 +930,14 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
forEachChild(node, collectLinkedAliases);
}

function markLinkedReferences(file: SourceFile) {
ts.forEachChildRecursively(file, n => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this instead check if file doesnt have TypeChecked flag and do this work and then we can get rid of getDiagnostics all together from getEmitResolver()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite - the TypeChecked flag is, ironically, set on files whose type checking is skipped. Maybe it's a misnomer, but it really just means "Has checkSourceFile been called on this node?". I get your drift though and, yeah, we could probably do a bit of refactoring to use a node flag to track the diagnostic walk state of the containing file. I'll probably put that up as a separate cleanup, though. I also think I want to move around/refactor the API logic for collectLinkedAliases so the API is harder to misuse, and will probably change markLinkedReferences to match, so I'll put all those nonfunctional changes in a separate PR (which should have a 0-test diff).

if (isImportEqualsDeclaration(n) && !(ts.getSyntacticModifierFlags(n) & ts.ModifierFlags.Export)) return "skip"; // These are deferred and marked in a chain when referenced
if (ts.isImportDeclaration(n)) return "skip"; // likewise, these are ultimately what get marked by calls on other nodes - we want to skip them
resolver.markLinkedReferences(n);
});
}

function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, transform: TransformationResult<SourceFile | Bundle>, printer: Printer, mapOptions: SourceMapOptions) {
const sourceFileOrBundle = transform.transformed[0];
const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined;
Expand Down Expand Up @@ -1090,10 +1104,11 @@ export const notImplementedResolver: EmitResolver = {
isValueAliasDeclaration: notImplemented,
isReferencedAliasDeclaration: notImplemented,
isTopLevelValueImportEqualsWithEntityName: notImplemented,
getNodeCheckFlags: notImplemented,
hasNodeCheckFlag: notImplemented,
isDeclarationVisible: notImplemented,
isLateBound: (_node): _node is LateBoundDeclaration => false,
collectLinkedAliases: notImplemented,
markLinkedReferences: notImplemented,
isImplementationOfOverload: notImplemented,
requiresAddingImplicitUndefined: notImplemented,
isExpandoFunctionDeclaration: notImplemented,
Expand Down
3 changes: 0 additions & 3 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4454,9 +4454,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (options.noEmit) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noCheck", "noEmit");
}
if (!options.emitDeclarationOnly) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "noCheck", "emitDeclarationOnly");
}
}

if (
Expand Down
15 changes: 7 additions & 8 deletions src/compiler/transformers/classFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1755,7 +1755,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
}
else if (isPrivateIdentifierClassElementDeclaration(member)) {
containsInstancePrivateElements = true;
if (resolver.getNodeCheckFlags(member) & NodeCheckFlags.ContainsConstructorReference) {
if (resolver.hasNodeCheckFlag(member, NodeCheckFlags.ContainsConstructorReference)) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
}
Expand Down Expand Up @@ -1889,7 +1889,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
getClassLexicalEnvironment().classThis = node.emitNode.classThis;
}

const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsConstructorReference;
const isClassWithConstructorReference = resolver.hasNodeCheckFlag(node, NodeCheckFlags.ContainsConstructorReference);
const isExport = hasSyntacticModifier(node, ModifierFlags.Export);
const isDefault = hasSyntacticModifier(node, ModifierFlags.Default);
let modifiers = visitNodes(node.modifiers, modifierVisitor, isModifier);
Expand Down Expand Up @@ -1965,8 +1965,8 @@ export function transformClassFields(context: TransformationContext): (x: Source
// these statements after the class expression variable statement.
const isDecoratedClassDeclaration = !!(facts & ClassFacts.ClassWasDecorated);
const staticPropertiesOrClassStaticBlocks = getStaticPropertiesAndClassStaticBlock(node);
const classCheckFlags = resolver.getNodeCheckFlags(node);
const isClassWithConstructorReference = classCheckFlags & NodeCheckFlags.ContainsConstructorReference;
const isClassWithConstructorReference = resolver.hasNodeCheckFlag(node, NodeCheckFlags.ContainsConstructorReference);
const requiresBlockScopedVar = resolver.hasNodeCheckFlag(node, NodeCheckFlags.BlockScopedBindingInLoop);

let temp: Identifier | undefined;
function createClassTempVar() {
Expand All @@ -1983,7 +1983,6 @@ export function transformClassFields(context: TransformationContext): (x: Source
return getClassLexicalEnvironment().classConstructor = node.emitNode.classThis;
}

const requiresBlockScopedVar = classCheckFlags & NodeCheckFlags.BlockScopedBindingInLoop;
const temp = factory.createTempVariable(requiresBlockScopedVar ? addBlockScopedVariable : hoistVariableDeclaration, /*reservedInNestedScopes*/ true);
getClassLexicalEnvironment().classConstructor = factory.cloneNode(temp);
return temp;
Expand Down Expand Up @@ -2712,7 +2711,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
const alreadyTransformed = !!cacheAssignment || isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left);
if (!alreadyTransformed && !inlinable && shouldHoist) {
const generatedName = factory.getGeneratedNameForNode(name);
if (resolver.getNodeCheckFlags(name) & NodeCheckFlags.BlockScopedBindingInLoop) {
if (resolver.hasNodeCheckFlag(name, NodeCheckFlags.BlockScopedBindingInLoop)) {
addBlockScopedVariable(generatedName);
}
else {
Expand Down Expand Up @@ -2960,7 +2959,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
typeof name === "string" ? factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic, prefix, suffix) :
factory.createTempVariable(/*recordTempVariable*/ undefined, /*reservedInNestedScopes*/ true, prefix, suffix);

if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BlockScopedBindingInLoop) {
if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.BlockScopedBindingInLoop)) {
addBlockScopedVariable(identifier);
}
else {
Expand Down Expand Up @@ -3295,7 +3294,7 @@ export function transformClassFields(context: TransformationContext): (x: Source

function trySubstituteClassAlias(node: Identifier): Expression | undefined {
if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReference) {
if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.ConstructorReference)) {
// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
Expand Down
15 changes: 7 additions & 8 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2867,9 +2867,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
// * Why loop initializer is excluded?
// - Since we've introduced a fresh name it already will be undefined.

const flags = resolver.getNodeCheckFlags(node);
const isCapturedInFunction = flags & NodeCheckFlags.CapturedBlockScopedBinding;
const isDeclaredInLoop = flags & NodeCheckFlags.BlockScopedBindingInLoop;
const isCapturedInFunction = resolver.hasNodeCheckFlag(node, NodeCheckFlags.CapturedBlockScopedBinding);
const isDeclaredInLoop = resolver.hasNodeCheckFlag(node, NodeCheckFlags.BlockScopedBindingInLoop);
const emittedAsTopLevel = (hierarchyFacts & HierarchyFacts.TopLevel) !== 0
|| (isCapturedInFunction
&& isDeclaredInLoop
Expand Down Expand Up @@ -3373,7 +3372,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
}

function shouldConvertPartOfIterationStatement(node: Node) {
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0;
return resolver.hasNodeCheckFlag(node, NodeCheckFlags.ContainsCapturedBlockScopeBinding);
}

function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer {
Expand All @@ -3394,7 +3393,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
}

function shouldConvertBodyOfIterationStatement(node: IterationStatement): boolean {
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LoopWithCapturedBlockScopedBinding) !== 0;
return resolver.hasNodeCheckFlag(node, NodeCheckFlags.LoopWithCapturedBlockScopedBinding);
}

/**
Expand Down Expand Up @@ -4057,11 +4056,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
}
else {
loopParameters.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
const checkFlags = resolver.getNodeCheckFlags(decl);
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForHead) {
const needsOutParam = resolver.hasNodeCheckFlag(decl, NodeCheckFlags.NeedsLoopOutParameter);
if (needsOutParam || hasCapturedBindingsInForHead) {
const outParamName = factory.createUniqueName("out_" + idText(name));
let flags = LoopOutParameterFlags.None;
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
if (needsOutParam) {
flags |= LoopOutParameterFlags.Body;
}
if (isForStatement(container)) {
Expand Down
18 changes: 9 additions & 9 deletions src/compiler/transformers/es2017.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
// This step isn't needed if we eventually transform this to ES5.
const originalMethod = getOriginalNode(node, isFunctionLikeDeclaration);
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 &&
resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) &&
(resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) || resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAccessInAsync)) &&
(getFunctionFlags(originalMethod) & FunctionFlags.AsyncGenerator) !== FunctionFlags.AsyncGenerator;

if (emitSuperHelpers) {
Expand All @@ -675,10 +675,10 @@ export function transformES2017(context: TransformationContext): (x: SourceFile

if (hasSuperElementAccess) {
// Emit helpers for super element access expressions (`super[x]`).
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) {
if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync)) {
addEmitHelper(updated, advancedAsyncSuperHelper);
}
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) {
else if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAccessInAsync)) {
addEmitHelper(updated, asyncSuperHelper);
}
}
Expand Down Expand Up @@ -743,7 +743,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined;
const isArrowFunction = node.kind === SyntaxKind.ArrowFunction;
const savedLexicalArgumentsBinding = lexicalArgumentsBinding;
const hasLexicalArguments = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureArguments) !== 0;
const hasLexicalArguments = resolver.hasNodeCheckFlag(node, NodeCheckFlags.CaptureArguments);
const captureLexicalArguments = hasLexicalArguments && !lexicalArgumentsBinding;
if (captureLexicalArguments) {
lexicalArgumentsBinding = factory.createUniqueName("arguments");
Expand Down Expand Up @@ -816,7 +816,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile

// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync);
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) || resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAccessInAsync));

if (emitSuperHelpers) {
enableSubstitutionForAsyncMethodsWithSuper();
Expand All @@ -836,10 +836,10 @@ export function transformES2017(context: TransformationContext): (x: SourceFile

if (emitSuperHelpers && hasSuperElementAccess) {
// Emit helpers for super element access expressions (`super[x]`).
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) {
if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync)) {
addEmitHelper(block, advancedAsyncSuperHelper);
}
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) {
else if (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAccessInAsync)) {
addEmitHelper(block, asyncSuperHelper);
}
}
Expand Down Expand Up @@ -926,7 +926,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
// If we need to support substitutions for `super` in an async method,
// we should track it here.
if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync);
const superContainerFlags = (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) ? NodeCheckFlags.MethodWithSuperPropertyAccessInAsync : 0) | (resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) ? NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync : 0);
if (superContainerFlags !== enclosingSuperContainerFlags) {
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
enclosingSuperContainerFlags = superContainerFlags;
Expand Down Expand Up @@ -1058,7 +1058,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
export function createSuperAccessVariableStatement(factory: NodeFactory, resolver: EmitResolver, node: FunctionLikeDeclaration, names: Set<__String>) {
// Create a variable declaration with a getter/setter (if binding) definition for each name:
// const _super = Object.create(null, { x: { get: () => super.x, set: (v) => super.x = v }, ... });
const hasBinding = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) !== 0;
const hasBinding = resolver.hasNodeCheckFlag(node, NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync);
const accessors: PropertyAssignment[] = [];
names.forEach((_, key) => {
const name = unescapeLeadingUnderscores(key);
Expand Down
Loading