Skip to content

Type to string via type node#15790

Merged
aozgaa merged 43 commits into
microsoft:masterfrom
aozgaa:typeToStringViaTypeNode
May 17, 2017
Merged

Type to string via type node#15790
aozgaa merged 43 commits into
microsoft:masterfrom
aozgaa:typeToStringViaTypeNode

Conversation

@aozgaa
Copy link
Copy Markdown
Contributor

@aozgaa aozgaa commented May 12, 2017

Fixes #14444, and a number of miscellaneous issues with TypeNode creation, including:

  • parentheses creation
  • emit default type parameters
  • Better qualified name handling
  • formatting fixes
    and moves us closer to consolidating printing infrastructure. Will still need to make an emitter building display parts to eliminate SymbolDisplayBuilder methods.

Comment thread src/compiler/types.ts Outdated
/*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier.
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: spacing for comments.

Comment thread src/compiler/types.ts Outdated
SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type.

// Error handling
allowThisInObjectLiteral = 1 << 10,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mixed case for first letter. Prefer one or the other.

Comment thread src/compiler/types.ts Outdated
export const enum NewLineKind {
CarriageReturnLineFeed = 0,
LineFeed = 1,
None = 2
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Prefer we use EmitFlags.SingleLine instead of adding this member.

Comment thread src/compiler/types.ts Outdated
}

export const enum EmitFlags {
None = 0,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need this?

Comment thread src/compiler/types.ts Outdated
* collisions.
*/
printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string;
printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Don't allow undefined for source file on public API.

Comment thread src/compiler/visitor.ts

case SyntaxKind.PropertySignature:
return updatePropertySignature((<PropertySignature>node),
nodesVisitor((<PropertySignature>node).modifiers, visitor, isToken),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add this to reduceEachChild as well.

Comment thread src/compiler/checker.ts Outdated
}

function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration {
function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext, addInElementTypeFlag: boolean, addInFirstTypeArgumentFlag: boolean): TypeNode[] {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider adding parenthesization logic to the factory methods for types, similar to what we do for expressions. This would ensure we always handle parentheses consistently and would simplify much of the logic here.

Comment thread src/services/services.ts Outdated
_incrementExpressionBrand: any;
_unaryExpressionBrand: any;
_expressionBrand: any;
typeArguments: any;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Give this the right type, but mark it /*@internal*/

var x = "\u{abcd}\u{ef12}\u{3456}\u{7890}";
>x : string
>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "ꯍ㑖碐"
>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should probably fix these cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider adding support for textSourceNode from StringLiteral to Identifier so that you can just pull the raw text from the original source file. You would have to modify both getTextOfNode and getLiteralTextOfNode in emitter.ts to make a best effort to find the source file of the node if currentSourceFile is undefined, and otherwise just use the node's text.

//// class C implements I {[| |]}

verify.rangeAfterCodeFix(`
test(a: [string, number]): void {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why can't we use the alias name?

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.

Sometimes we really ought to instantiate the type reference. Consider:

interface I<T> {
    foo(t: T): void;
}
class C implements I<number> {}

Then we clearly ought to use the instantiated type for a.

It looks like it will be tricky to distinguish the above case and other variants from the test case.

The behavior in the test doesn't represent a regression.

Because the fix is complicated, I'll leave it for a separate PR.

Comment thread src/compiler/emitter.ts
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
ObjectBindingPatternElements = SingleLine | CommaDelimited | SpaceBetweenSiblings,
ObjectBindingPatternElementsWithSpaceBetweenBraces = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider reverting this in a separate PR, and simplify the names (especially for the general emit case).

Copy link
Copy Markdown
Contributor

@rbuckton rbuckton left a comment

Choose a reason for hiding this comment

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

Approved with a few minor comments.

Comment thread src/compiler/factory.ts Outdated

export function parenthesizeElementTypeMembers(members: TypeNode[]) {
// TODO: does this lose `originalNode` ptr?
return createNodeArray(members.map(parenthesizeElementTypeMember));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider using sameMap. Also do you need to resolve the TODO here?

Comment thread src/compiler/factory.ts Outdated
}

export function parenthesizeTypeParameters(typeParameters: TypeNode[]) {
if (typeParameters && typeParameters.length > 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

some(typeParameters)

Comment thread src/compiler/factory.ts Outdated
export function parenthesizeTypeParameters(typeParameters: TypeNode[]) {
if (typeParameters && typeParameters.length > 0) {
const nodeArray = createNodeArray(typeParameters);
const firstEntry = nodeArray[0];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Create a fresh node array, createNodeArray actually just turns typeParameters into a node array, so you end up mutating an existing array.

Comment thread src/compiler/utilities.ts Outdated
return false;
}

export function isFunctionOrConstructor(node: Node): node is FunctionTypeNode | ConstructorTypeNode {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe isFunctionOrConstructorTypeNode?

Comment thread src/compiler/types.ts Outdated
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics.
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: spacing nodes.Though

Comment thread src/compiler/checker.ts Outdated
const inFirstTypeArgument = context.flags & NodeBuilderFlags.InFirstTypeArgument;
const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias;
context.flags &= ~(NodeBuilderFlags.StateClearingFlags);
context.flags &= ~(NodeBuilderFlags.InTypeAlias);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove parens

Comment thread src/compiler/checker.ts Outdated
isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
const name = symbolToTypeReferenceName(type.aliasSymbol);
const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context);
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

consider moving existential check into mapToTypeNodeArray

Comment thread src/compiler/checker.ts Outdated
else if (type.target.objectFlags & ObjectFlags.Tuple) {
if (typeArguments.length > 0) {
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ false);
const slice = typeArguments.slice(0, getTypeReferenceArity(type));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you add the check to mapToTypeNodeArray you don't need to break this up into two statements.

Comment thread src/compiler/checker.ts Outdated
// the default outer type arguments), we don't show the group.
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
const typeArgumentNodes = createNodeArray(toTypeArgumentNodes(typeArguments.slice(start, i), context));
const slice = typeArguments.slice(start, i);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See above

Comment thread src/compiler/checker.ts Outdated
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
const slice = typeArguments && typeArguments.slice(i, typeParameterCount);
typeArgumentNodes = toTypeArgumentNodes(slice, context);
typeArgumentNodes = slice && mapToTypeNodeArray(slice, context);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See above

@aozgaa aozgaa merged commit ebcbd8f into microsoft:master May 17, 2017
@aozgaa aozgaa mentioned this pull request Aug 11, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

QuickFix for implementing missing members should support mapped types

3 participants