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

Extract node type printer #59282

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1,194 changes: 384 additions & 810 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -6962,7 +6962,7 @@
"category": "Error",
"code": 9008
},
"At least one accessor must have an explicit return type annotation with --isolatedDeclarations.": {
"At least one accessor must have an explicit type annotation with --isolatedDeclarations.": {
"category": "Error",
"code": 9009
},
Expand Down
1,130 changes: 976 additions & 154 deletions src/compiler/expressionToTypeNode.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/factory/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1668,7 +1668,7 @@ export function createAccessorPropertySetRedirector(factory: NodeFactory, node:
}

/** @internal */
export function findComputedPropertyNameCacheAssignment(name: ComputedPropertyName) {
export function findComputedPropertyNameCacheAssignment(name: ComputedPropertyName): AssignmentExpression<EqualsToken> & { readonly left: GeneratedIdentifier; } | undefined {
let node = name.expression;
while (true) {
node = skipOuterExpressions(node);
Expand Down
126 changes: 43 additions & 83 deletions src/compiler/transformers/declarations.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/compiler/transformers/declarations/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,8 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver): (nod
[SyntaxKind.ArrowFunction]: Diagnostics.Function_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations,
[SyntaxKind.MethodDeclaration]: Diagnostics.Method_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations,
[SyntaxKind.ConstructSignature]: Diagnostics.Method_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations,
[SyntaxKind.GetAccessor]: Diagnostics.At_least_one_accessor_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations,
[SyntaxKind.SetAccessor]: Diagnostics.At_least_one_accessor_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations,
[SyntaxKind.GetAccessor]: Diagnostics.At_least_one_accessor_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.SetAccessor]: Diagnostics.At_least_one_accessor_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.Parameter]: Diagnostics.Parameter_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.VariableDeclaration]: Diagnostics.Variable_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.PropertyDeclaration]: Diagnostics.Property_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
Expand Down
56 changes: 42 additions & 14 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5845,7 +5845,7 @@ export interface EmitResolver {
requiresAddingImplicitUndefined(node: ParameterDeclaration, enclosingDeclaration: Node | undefined): boolean;
isExpandoFunctionDeclaration(node: FunctionDeclaration | VariableDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfDeclaration(declaration: HasInferredType, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression;
Expand Down Expand Up @@ -10491,37 +10491,65 @@ export interface EvaluationResolver {

/** @internal */
export type HasInferredType =
| PropertyAssignment
| Exclude<VariableLikeDeclaration, JsxAttribute | EnumMember>
| PropertyAccessExpression
| BinaryExpression
| ElementAccessExpression
| VariableDeclaration
| ParameterDeclaration
| BindingElement
| PropertyDeclaration
| PropertySignature
| BinaryExpression
| ExportAssignment;

/** @internal */
export interface SyntacticTypeNodeBuilderContext {
flags: NodeBuilderFlags;
tracker: Required<Pick<SymbolTracker, "reportInferenceFallback">>;
enclosingFile: SourceFile | undefined;
enclosingDeclaration: Node | undefined;
approximateLength: number;
noInferenceFallback?: boolean;
}

/** @internal */
export interface SyntacticTypeNodeBuilderResolver {
isOptionalParameter(p: ParameterDeclaration): boolean;
isUndefinedIdentifierExpression(name: Identifier): boolean;
isExpandoFunctionDeclaration(name: FunctionDeclaration | VariableDeclaration): boolean;
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined): boolean;
requiresAddingImplicitUndefined(declaration: ParameterDeclaration | PropertySignature | JSDocParameterTag | JSDocPropertyTag | PropertyDeclaration, symbol: Symbol | undefined, enclosingDeclaration: Node | undefined): boolean;
isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean;
isEntityNameVisible(context: SyntacticTypeNodeBuilderContext, entityName: EntityNameOrEntityNameExpression, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
serializeExistingTypeNode(context: SyntacticTypeNodeBuilderContext, node: TypeNode, addUndefined?: boolean): TypeNode | undefined;
serializeReturnTypeForSignature(context: SyntacticTypeNodeBuilderContext, signatureDeclaration: SignatureDeclaration | JSDocSignature): TypeNode | undefined;
serializeTypeOfExpression(context: SyntacticTypeNodeBuilderContext, expr: Expression): TypeNode;
serializeTypeOfDeclaration(context: SyntacticTypeNodeBuilderContext, node: HasInferredType | GetAccessorDeclaration | SetAccessorDeclaration, symbol: Symbol | undefined): TypeNode | undefined;
serializeNameOfParameter(context: SyntacticTypeNodeBuilderContext, parameter: ParameterDeclaration): BindingName | string;
serializeTypeName(context: SyntacticTypeNodeBuilderContext, node: EntityName, isTypeOf?: boolean, typeArguments?: readonly TypeNode[]): TypeNode | undefined;
serializeEntityName(context: SyntacticTypeNodeBuilderContext, node: EntityNameExpression): Expression | undefined;
getJsDocPropertyOverride(context: SyntacticTypeNodeBuilderContext, jsDocTypeLiteral: JSDocTypeLiteral, jsDocProperty: JSDocPropertyLikeTag): TypeNode | undefined;
enterNewScope(context: SyntacticTypeNodeBuilderContext, node: IntroducesNewScopeNode | ConditionalTypeNode): () => void;
markNodeReuse<T extends Node>(context: SyntacticTypeNodeBuilderContext, range: T, location: Node | undefined): T;
trackExistingEntityName<T extends EntityNameOrEntityNameExpression>(context: SyntacticTypeNodeBuilderContext, node: T): { introducesError: boolean; node: T; };
trackComputedName(context: SyntacticTypeNodeBuilderContext, accessExpression: EntityNameOrEntityNameExpression): void;
evaluateEntityNameExpression(expression: EntityNameExpression): EvaluatorResult;
getModuleSpecifierOverride(context: SyntacticTypeNodeBuilderContext, parent: ImportTypeNode, lit: StringLiteral): string | undefined;
canReuseTypeNode(context: SyntacticTypeNodeBuilderContext, existing: TypeNode): boolean;
canReuseTypeNodeAnnotation(context: SyntacticTypeNodeBuilderContext, node: Declaration, existing: TypeNode, symbol: Symbol | undefined, requiresAddingUndefined?: boolean): boolean;
shouldRemoveDeclaration(context: SyntacticTypeNodeBuilderContext, node: DynamicNamedDeclaration): boolean;
hasLateBindableName(node: Declaration): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration;
createRecoveryBoundary(context: SyntacticTypeNodeBuilderContext): {
startRecoveryScope(): () => void;
finalizeBoundary(): boolean;
markError(): void;
hadError(): boolean;
};
}

/** @internal */
export interface SyntacticNodeBuilder {
typeFromExpression: (node: Expression, context: SyntacticTypeNodeBuilderContext, isConstContext?: boolean, requiresAddingUndefined?: boolean, preserveLiterals?: boolean) => boolean | undefined;
serializeTypeOfDeclaration: (node: HasInferredType, context: SyntacticTypeNodeBuilderContext) => boolean | undefined;
serializeReturnTypeForSignature: (node: SignatureDeclaration | JSDocSignature, context: SyntacticTypeNodeBuilderContext) => boolean | undefined;
serializeTypeOfExpression: (expr: Expression, context: SyntacticTypeNodeBuilderContext, addUndefined?: boolean, preserveLiterals?: boolean) => boolean;
serializeTypeOfDeclaration: (node: HasInferredType, symbol: Symbol, context: SyntacticTypeNodeBuilderContext) => TypeNode | undefined;
serializeReturnTypeForSignature: (signature: SignatureDeclaration | JSDocSignature, symbol: Symbol, context: SyntacticTypeNodeBuilderContext) => TypeNode | undefined;
serializeTypeOfExpression: (expr: Expression | JsxAttributeValue, context: SyntacticTypeNodeBuilderContext, addUndefined?: boolean, preserveLiterals?: boolean) => TypeNode;
tryReuseExistingTypeNode: (context: SyntacticTypeNodeBuilderContext, existing: TypeNode) => TypeNode | undefined;
serializeTypeOfAccessor: (accessor: AccessorDeclaration, symbol: Symbol, context: SyntacticTypeNodeBuilderContext) => TypeNode | undefined;
}

/** @internal */
export type IntroducesNewScopeNode = SignatureDeclaration | JSDocSignature | MappedTypeNode;
16 changes: 11 additions & 5 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ import {
InterfaceDeclaration,
InternalEmitFlags,
InternalSymbolName,
IntroducesNewScopeNode,
isAccessor,
isAnyDirectorySeparator,
isArray,
Expand Down Expand Up @@ -321,6 +322,7 @@ import {
isLeftHandSideExpression,
isLineBreak,
isLiteralTypeNode,
isMappedTypeNode,
isMemberName,
isMetaProperty,
isMethodDeclaration,
Expand Down Expand Up @@ -2853,11 +2855,6 @@ export function isVariableLike(node: Node): node is VariableLikeDeclaration {
return false;
}

/** @internal */
export function isVariableLikeOrAccessor(node: Node): node is AccessorDeclaration | VariableLikeDeclaration {
return isVariableLike(node) || isAccessor(node);
}

/** @internal */
export function isVariableDeclarationInVariableStatement(node: VariableDeclaration): boolean {
return node.parent.kind === SyntaxKind.VariableDeclarationList
Expand Down Expand Up @@ -11844,6 +11841,9 @@ export function hasInferredType(node: Node): node is HasInferredType {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.ExportAssignment:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.JSDocParameterTag:
case SyntaxKind.JSDocPropertyTag:
return true;
default:
assertType<never>(node);
Expand Down Expand Up @@ -11936,3 +11936,9 @@ export const nodeCoreModules: Set<string> = new Set([
...unprefixedNodeCoreModulesList.map(name => `node:${name}`),
...exclusivelyPrefixedNodeCoreModules,
]);
/** @internal */
export function isNewScopeNode(node: Node): node is IntroducesNewScopeNode {
return isFunctionLike(node)
|| isJSDocSignature(node)
|| isMappedTypeNode(node);
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const extractExpression = "extract-expression";
const errorCodes = [
Diagnostics.Function_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations.code,
Diagnostics.Method_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations.code,
Diagnostics.At_least_one_accessor_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations.code,
Diagnostics.At_least_one_accessor_must_have_an_explicit_type_annotation_with_isolatedDeclarations.code,
Diagnostics.Variable_must_have_an_explicit_type_annotation_with_isolatedDeclarations.code,
Diagnostics.Parameter_must_have_an_explicit_type_annotation_with_isolatedDeclarations.code,
Diagnostics.Property_must_have_an_explicit_type_annotation_with_isolatedDeclarations.code,
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/ambientConstLiterals.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,5 @@ declare const c9: {
declare const c10: number[];
declare const c11: string;
declare const c12: number;
declare const c13: string;
declare const c14: number;
declare const c13: "abc" | "def";
declare const c14: 123 | 456;
Comment on lines +77 to +78
Copy link
Member

Choose a reason for hiding this comment

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

This seems to reintroduce the widening problem we've previously discussed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did notice this, but I think this is actually a bug. Hovering over those variables in the playground shows the union on hover while the declarations show string and number.

Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ var a = () => <Error>{ name: "foo", message: "bar" };

var b = () => (<Error>{ name: "foo", message: "bar" });
>b : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>() => (<Error>{ name: "foo", message: "bar" }) : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>(<Error>{ name: "foo", message: "bar" }) : Error
> : ^^^^^
><Error>{ name: "foo", message: "bar" } : Error
Expand Down Expand Up @@ -59,9 +59,9 @@ var c = () => ({ name: "foo", message: "bar" });

var d = () => ((<Error>({ name: "foo", message: "bar" })));
>d : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>() => ((<Error>({ name: "foo", message: "bar" }))) : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>((<Error>({ name: "foo", message: "bar" }))) : Error
> : ^^^^^
>(<Error>({ name: "foo", message: "bar" })) : Error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ var a = () => <Error>{ name: "foo", message: "bar" };

var b = () => (<Error>{ name: "foo", message: "bar" });
>b : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>() => (<Error>{ name: "foo", message: "bar" }) : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>(<Error>{ name: "foo", message: "bar" }) : Error
> : ^^^^^
><Error>{ name: "foo", message: "bar" } : Error
Expand Down Expand Up @@ -59,9 +59,9 @@ var c = () => ({ name: "foo", message: "bar" });

var d = () => ((<Error>({ name: "foo", message: "bar" })));
>d : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>() => ((<Error>({ name: "foo", message: "bar" }))) : () => Error
> : ^^^^^^^^^^^
> : ^^^^^^
>((<Error>({ name: "foo", message: "bar" }))) : Error
> : ^^^^^
>(<Error>({ name: "foo", message: "bar" })) : Error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ assignmentCompatWithCallSignatures3.ts(77,1): error TS2322: Type '(x: { foo: str
Types of parameters 'y' and 'y' are incompatible.
Type 'T' is not assignable to type '{ foo: string; bar: string; }'.
Property 'bar' is missing in type 'Base' but required in type '{ foo: string; bar: string; }'.
assignmentCompatWithCallSignatures3.ts(80,1): error TS2322: Type '(x: Base[], y: Derived2[]) => Derived[]' is not assignable to type '<T extends Array<Base>>(x: Base[], y: T) => Derived[]'.
assignmentCompatWithCallSignatures3.ts(80,1): error TS2322: Type '(x: Array<Base>, y: Array<Derived2>) => Array<Derived>' is not assignable to type '<T extends Array<Base>>(x: Array<Base>, y: T) => Array<Derived>'.
Types of parameters 'y' and 'y' are incompatible.
Type 'T' is not assignable to type 'Derived2[]'.
Type 'Base[]' is not assignable to type 'Derived2[]'.
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
assignmentCompatWithCallSignatures3.ts(83,1): error TS2322: Type '(x: Base[], y: Derived[]) => Derived[]' is not assignable to type '<T extends Array<Derived>>(x: Base[], y: T) => T'.
assignmentCompatWithCallSignatures3.ts(83,1): error TS2322: Type '(x: Array<Base>, y: Array<Derived>) => Array<Derived>' is not assignable to type '<T extends Array<Derived>>(x: Array<Base>, y: T) => T'.
Type 'Derived[]' is not assignable to type 'T'.
'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'.
assignmentCompatWithCallSignatures3.ts(85,1): error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => Object'.
Expand Down Expand Up @@ -204,7 +204,7 @@ assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: strin
a12 = b12; // ok
b12 = a12; // ok
~~~
!!! error TS2322: Type '(x: Base[], y: Derived2[]) => Derived[]' is not assignable to type '<T extends Array<Base>>(x: Base[], y: T) => Derived[]'.
!!! error TS2322: Type '(x: Array<Base>, y: Array<Derived2>) => Array<Derived>' is not assignable to type '<T extends Array<Base>>(x: Array<Base>, y: T) => Array<Derived>'.
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'Derived2[]'.
!!! error TS2322: Type 'Base[]' is not assignable to type 'Derived2[]'.
Expand All @@ -213,7 +213,7 @@ assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: strin
a13 = b13; // ok
b13 = a13; // ok
~~~
!!! error TS2322: Type '(x: Base[], y: Derived[]) => Derived[]' is not assignable to type '<T extends Array<Derived>>(x: Base[], y: T) => T'.
!!! error TS2322: Type '(x: Array<Base>, y: Array<Derived>) => Array<Derived>' is not assignable to type '<T extends Array<Derived>>(x: Array<Base>, y: T) => T'.
!!! error TS2322: Type 'Derived[]' is not assignable to type 'T'.
!!! error TS2322: 'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'.
var b14: <T>(x: { a: T; b: T }) => T;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ assignmentCompatWithCallSignatures4.ts(58,9): error TS2322: Type '(...x: Base[])
assignmentCompatWithCallSignatures4.ts(62,9): error TS2322: Type '(x: { foo: string; }, y: { foo: string; bar: string; }) => Base' is not assignable to type '<T extends Derived>(x: T, y: T) => T'.
Type 'Base' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'Base'.
assignmentCompatWithCallSignatures4.ts(66,9): error TS2322: Type '(x: Base[], y: Derived2[]) => Derived[]' is not assignable to type '<T extends Array<Derived2>>(x: Base[], y: Base[]) => T'.
assignmentCompatWithCallSignatures4.ts(66,9): error TS2322: Type '(x: Array<Base>, y: Array<Derived2>) => Array<Derived>' is not assignable to type '<T extends Array<Derived2>>(x: Array<Base>, y: Array<Base>) => T'.
Type 'Derived[]' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'Derived[]'.
assignmentCompatWithCallSignatures4.ts(69,9): error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => number'.
Expand Down Expand Up @@ -163,7 +163,7 @@ assignmentCompatWithCallSignatures4.ts(96,9): error TS2322: Type '<T>(x: T) => s
a12 = b12;
b12 = a12;
~~~
!!! error TS2322: Type '(x: Base[], y: Derived2[]) => Derived[]' is not assignable to type '<T extends Array<Derived2>>(x: Base[], y: Base[]) => T'.
!!! error TS2322: Type '(x: Array<Base>, y: Array<Derived2>) => Array<Derived>' is not assignable to type '<T extends Array<Derived2>>(x: Array<Base>, y: Array<Base>) => T'.
!!! error TS2322: Type 'Derived[]' is not assignable to type 'T'.
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Derived[]'.

Expand Down
Loading