Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Revert "Refactored node builder flags and tests"
This reverts commit 7d434b7.
  • Loading branch information
Armando Aguirre Sepulveda committed Jul 30, 2024
commit 585421025793d41dfdc71b196edcef44c530957b
18 changes: 10 additions & 8 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,6 @@ import {
WideningContext,
WithStatement,
YieldExpression,
NodeBuilderFlagsIgnoreErrors,
} from "./_namespaces/ts.js";
import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers.js";
import * as performance from "./_namespaces/ts.performance.js";
Expand Down Expand Up @@ -5911,7 +5910,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string {
let nodeFlags = NodeBuilderFlagsIgnoreErrors;
let nodeFlags = NodeBuilderFlags.IgnoreErrors;
if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) {
nodeFlags |= NodeBuilderFlags.UseOnlyExternalAliasing;
}
Expand Down Expand Up @@ -5953,7 +5952,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else {
sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature;
}
const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName);
const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName);
const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon();
const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration);
printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217
Expand All @@ -5962,8 +5961,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string {
const noTruncation = BigInt(compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation);
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlagsIgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : NodeBuilderFlags.None));
const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation;
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0));
if (typeNode === undefined) return Debug.fail("should always get typenode");
// The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`.
Copy link
Copy Markdown
Contributor Author

@armanio123 armanio123 Aug 8, 2024

Choose a reason for hiding this comment

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

This scenario seems weird to me as it depends on NoTruncation being set in TypeFormatFlags. Nonetheless, this is the current behavior, so I decided to change it but let me know if you disagree and I can rollback.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm, I think it's a little weird, though I guess it's also true that nobody would have ever intentionally set AllowUnresolvedNames here because that was never a valid TypeFormatFlag.

Sort of leaning towards not doing this one and seeing what happens? I assume no test changes here either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

They don't change. Actually, the latest commit doesn't change any of the tests. I'll rollback this line.

// Otherwise, we always strip comments out.
Expand Down Expand Up @@ -5998,7 +5997,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags {
return BigInt(flags & TypeFormatFlags.NodeBuilderFlagsMask);
return flags & TypeFormatFlags.NodeBuilderFlagsMask;
}

function isClassInstanceSide(type: Type) {
Expand Down Expand Up @@ -6157,7 +6156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function withContext<T>(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker: SymbolTracker | undefined, cb: (context: NodeBuilderContext) => T): T | undefined {
const moduleResolverHost = tracker?.trackSymbol ? tracker.moduleResolverHost :
(flags || NodeBuilderFlags.None) & NodeBuilderFlags.DoNotIncludeSymbolChain ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) :
flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) :
undefined;
const context: NodeBuilderContext = {
enclosingDeclaration,
Expand Down Expand Up @@ -10677,7 +10676,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker);

function typePredicateToStringWorker(writer: EmitTextWriter) {
const nodeBuilderFlags = toNodeBuilderFlags(flags) | NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName;
const nodeBuilderFlags = toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName;
const predicate = nodeBuilder.typePredicateToTypePredicateNode(typePredicate, enclosingDeclaration, nodeBuilderFlags)!; // TODO: GH#18217
const printer = createPrinterWithRemoveComments();
const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration);
Expand Down Expand Up @@ -27383,6 +27382,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function isFunctionObjectType(type: ObjectType): boolean {
if (getObjectFlags(type) & ObjectFlags.EvolvingArray) {
return false;
}
// We do a quick check for a "bind" property before performing the more expensive subtype
// check. This gives us a quicker out in the common case where an object type is not a function.
const resolved = resolveStructuredTypeMembers(type);
Expand Down
85 changes: 38 additions & 47 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5427,61 +5427,52 @@ export const enum ContextFlags {
SkipBindingPatterns = 1 << 3, // Ignore contextual types applied by binding patterns
}

export type NodeBuilderFlags = bigint;

// NOTE: If modifying this enum, must modify `TypeFormatFlags` too!
// dprint-ignore
export const NodeBuilderFlags = {
None : 0n,
export const enum NodeBuilderFlags {
None = 0,
// Options
NoTruncation : 1n << 0n, // Don't truncate result
WriteArrayAsGenericType : 1n << 1n, // Write Array<T> instead T[]
GenerateNamesForShadowedTypeParams : 1n << 2n, // When a type parameter T is shadowing another T, generate a name for it so it can still be referenced
UseStructuralFallback : 1n << 3n, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
ForbidIndexedAccessSymbolReferences : 1n << 4n, // Forbid references like `I["a"]["b"]` - print `typeof I.a<x>.b<y>` instead
WriteTypeArgumentsOfSignature : 1n << 5n, // Write the type arguments instead of type parameters of the signature
UseFullyQualifiedType : 1n << 6n, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
UseOnlyExternalAliasing : 1n << 7n, // Only use external aliases for a symbol
SuppressAnyReturnType : 1n << 8n, // If the return type is any-like and can be elided, don't offer a return type.
WriteTypeParametersInQualifiedName : 1n << 9n,
MultilineObjectLiterals : 1n << 10n, // Always write object literals across multiple lines
WriteClassExpressionAsTypeLiteral : 1n << 11n, // Write class {} as { new(): {} } - used for mixin declaration emit
UseTypeOfFunction : 1n << 12n, // Build using typeof instead of function type literal
OmitParameterModifiers : 1n << 13n, // Omit modifiers on parameters
UseAliasDefinedOutsideCurrentScope : 1n << 14n, // Allow non-visible aliases
UseSingleQuotesForStringLiteralType : 1n << 28n, // Use single quotes for string literal type
NoTypeReduction : 1n << 29n, // Don't call getReducedType
OmitThisParameter : 1n << 25n,
NoTruncation = 1 << 0, // Don't truncate result
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
GenerateNamesForShadowedTypeParams = 1 << 2, // When a type parameter T is shadowing another T, generate a name for it so it can still be referenced
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
ForbidIndexedAccessSymbolReferences = 1 << 4, // Forbid references like `I["a"]["b"]` - print `typeof I.a<x>.b<y>` instead
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
UseOnlyExternalAliasing = 1 << 7, // Only use external aliases for a symbol
SuppressAnyReturnType = 1 << 8, // If the return type is any-like and can be elided, don't offer a return type.
WriteTypeParametersInQualifiedName = 1 << 9,
MultilineObjectLiterals = 1 << 10, // Always write object literals across multiple lines
WriteClassExpressionAsTypeLiteral = 1 << 11, // Write class {} as { new(): {} } - used for mixin declaration emit
UseTypeOfFunction = 1 << 12, // Build using typeof instead of function type literal
OmitParameterModifiers = 1 << 13, // Omit modifiers on parameters
UseAliasDefinedOutsideCurrentScope = 1 << 14, // Allow non-visible aliases
UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type
NoTypeReduction = 1 << 29, // Don't call getReducedType
OmitThisParameter = 1 << 25,

// Error handling
AllowThisInObjectLiteral : 1n << 15n,
AllowQualifiedNameInPlaceOfIdentifier : 1n << 16n,
AllowAnonymousIdentifier : 1n << 17n,
AllowEmptyUnionOrIntersection : 1n << 18n,
AllowEmptyTuple : 1n << 19n,
AllowUniqueESSymbolType : 1n << 20n,
AllowEmptyIndexInfoType : 1n << 21n,
/** @internal */ WriteComputedProps : 1n << 30n, // { [E.A]: 1 }
/** @internal */ NoSyntacticPrinter : 1n << 31n,
AllowThisInObjectLiteral = 1 << 15,
AllowQualifiedNameInPlaceOfIdentifier = 1 << 16,
AllowAnonymousIdentifier = 1 << 17,
AllowEmptyUnionOrIntersection = 1 << 18,
AllowEmptyTuple = 1 << 19,
AllowUniqueESSymbolType = 1 << 20,
AllowEmptyIndexInfoType = 1 << 21,
/** @internal */ WriteComputedProps = 1 << 30, // { [E.A]: 1 }
/** @internal */ NoSyntacticPrinter = 1 << 31,
// Errors (cont.)
AllowNodeModulesRelativePaths : 1n << 26n,
/** @internal */ DoNotIncludeSymbolChain : 1n << 27n, // Skip looking up and printing an accessible symbol chain
/** @internal */ AllowUnresolvedNames : 1n << 32n,
AllowNodeModulesRelativePaths = 1 << 26,
/** @internal */ DoNotIncludeSymbolChain = 1 << 27, // Skip looking up and printing an accessible symbol chain
/** @internal */ AllowUnresolvedNames = 1 << 32,

IgnoreErrors = AllowThisInObjectLiteral | AllowQualifiedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple | AllowEmptyIndexInfoType | AllowNodeModulesRelativePaths,

// State
InObjectTypeLiteral : 1n << 22n,
InTypeAlias : 1n << 23n, // Writing type in type alias declaration
InInitialEntityName : 1n << 24n, // Set when writing the LHS of an entity name or entity name expression
}

export const NodeBuilderFlagsIgnoreErrors =
NodeBuilderFlags.AllowThisInObjectLiteral
| NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier
| NodeBuilderFlags.AllowAnonymousIdentifier
| NodeBuilderFlags.AllowEmptyUnionOrIntersection
| NodeBuilderFlags.AllowEmptyTuple
| NodeBuilderFlags.AllowEmptyIndexInfoType
| NodeBuilderFlags.AllowNodeModulesRelativePaths;
InObjectTypeLiteral = 1 << 22,
InTypeAlias = 1 << 23, // Writing type in type alias declaration
InInitialEntityName = 1 << 24, // Set when writing the LHS of an entity name or entity name expression
}

// Ensure the shared flags between this and `NodeBuilderFlags` stay in alignment
// dprint-ignore
Expand Down
4 changes: 2 additions & 2 deletions src/harness/typeWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ export class TypeWriterWalker {
}
else {
const typeFormatFlags = ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType | ts.TypeFormatFlags.GenerateNamesForShadowedTypeParams;
let typeNode = this.checker.typeToTypeNode(type, node.parent, BigInt((typeFormatFlags & ts.TypeFormatFlags.NodeBuilderFlagsMask)) | ts.NodeBuilderFlagsIgnoreErrors)!;
let typeNode = this.checker.typeToTypeNode(type, node.parent, (typeFormatFlags & ts.TypeFormatFlags.NodeBuilderFlagsMask) | ts.NodeBuilderFlags.IgnoreErrors)!;
if (ts.isIdentifier(node) && ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node && ts.isIdentifier(typeNode) && ts.idText(typeNode) === ts.idText(node)) {
// for a complex type alias `type T = ...`, showing "T : T" isn't very helpful for type tests. When the type produced is the same as
// the name of the type alias, recreate the type string without reusing the alias name
typeNode = this.checker.typeToTypeNode(type, node.parent, BigInt((typeFormatFlags | ts.TypeFormatFlags.InTypeAlias) & ts.TypeFormatFlags.NodeBuilderFlagsMask) | ts.NodeBuilderFlagsIgnoreErrors)!;
typeNode = this.checker.typeToTypeNode(type, node.parent, ((typeFormatFlags | ts.TypeFormatFlags.InTypeAlias) & ts.TypeFormatFlags.NodeBuilderFlagsMask) | ts.NodeBuilderFlags.IgnoreErrors)!;
}

const { printer, writer, underliner, reset } = createSyntheticNodeUnderliningPrinter();
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ export function addNewNodeForMemberSymbol(
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
let flags = NodeBuilderFlags.NoTruncation;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't need AllowUnresolvedNames like the code below?

Sort of wondering if all old users of NoTruncation need that flag, but maybe we shouldn't add ones where we don't think it should matter except those where we would have set it manually...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Currently is not needed to pass the test cases. Thought we might be missing some, because adding it doesn't change any of them.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Right, our test suite is just not always exhaustive, so I suspect that there are some lurking bugs without this flag for these auto-import / codefix cases, given those seem to in other cases depend on this flag

flags |= quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None;
flags |= quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : 0;
let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context));
if (importAdder) {
const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget);
Expand Down
5 changes: 2 additions & 3 deletions src/services/inlayHints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ import {
Node,
NodeArray,
NodeBuilderFlags,
NodeBuilderFlagsIgnoreErrors,
ParameterDeclaration,
PrefixUnaryExpression,
PropertyDeclaration,
Expand Down Expand Up @@ -465,7 +464,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
}

function printTypeInSingleLine(type: Type) {
const flags = NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const printer = createPrinterWithRemoveComments();

return usingSingleLineStringWriter(writer => {
Expand All @@ -480,7 +479,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
return printTypeInSingleLine(type);
}

const flags = NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags);
Debug.assertIsDefined(typeNode, "should always get typenode");

Expand Down
3 changes: 1 addition & 2 deletions src/services/signatureHelp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ import {
mapToDisplayParts,
Node,
NodeBuilderFlags,
NodeBuilderFlagsIgnoreErrors,
ParameterDeclaration,
ParenthesizedExpression,
Printer,
Expand Down Expand Up @@ -644,7 +643,7 @@ function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node {
return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
}

const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
function createSignatureHelpItems(
candidates: readonly Signature[],
resolvedSignature: Signature,
Expand Down
3 changes: 1 addition & 2 deletions src/services/symbolDisplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ import {
NewExpression,
Node,
NodeBuilderFlags,
NodeBuilderFlagsIgnoreErrors,
ObjectFlags,
operatorPart,
PropertyAccessExpression,
Expand Down Expand Up @@ -111,7 +110,7 @@ import {
VariableDeclaration,
} from "./_namespaces/ts.js";

const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlagsIgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;

// TODO(drosen): use contextual SemanticMeaning.
/** @internal */
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/ArrowFunction1.types
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
=== ArrowFunction1.ts ===
var v = (a: ) => {
>v : (a: any) => void
> : ^ ^^^^^^^^^^^^^^
> : ^ ^^ ^^^^^^^^^
>(a: ) => { } : (a: any) => void
> : ^ ^^^^^^^^^^^^^^
> : ^ ^^ ^^^^^^^^^
>a : any
> : ^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module clodule1 {

function f(x: T) { }
>f : (x: T) => void
> : ^ ^^^^^^^^^^^^
> : ^ ^^ ^^^^^^^^^
>x : T
> : ^
}
Expand Down
Loading