in Public/Src/FrontEnd/TypeScript.Net/TypeScript.Net/TypeChecking/SymbolDisplayBuilder.cs [191:600]
private void BuildTypeDisplay(IType inputType, ISymbolWriter writer, INode enclosingDeclaration, TypeFormatFlags globalFlags, Stack<ISymbol> symbolStack = null)
{
var globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike;
var inObjectTypeLiteral = false;
WriteType(inputType, globalFlags);
return;
void WriteType(IType type, TypeFormatFlags flags)
{
// Write null/null type as any
if ((type.Flags & TypeFlags.Intrinsic) != TypeFlags.None)
{
if ((type.Flags & TypeFlags.PredicateType) != TypeFlags.None)
{
BuildTypePredicateDisplay(writer, type.Cast<IPredicateType>().Predicate);
BuildTypeDisplay(type.Cast<IPredicateType>().Predicate.Type, writer, enclosingDeclaration, flags, symbolStack);
}
else
{
// Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving
writer.WriteKeyword((globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) == TypeFormatFlags.None && IsTypeAny(type)
? "any"
: type.Cast<IIntrinsicType>().IntrinsicName);
}
}
else if ((type.Flags & TypeFlags.ThisType) != TypeFlags.None)
{
if (inObjectTypeLiteral)
{
writer.ReportInaccessibleThisError();
}
writer.WriteKeyword("this");
}
else if ((type.Flags & TypeFlags.Reference) != TypeFlags.None)
{
WriteTypeReference((ITypeReference)type, flags);
}
else if ((type.Flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) != TypeFlags.None)
{
// The specified symbol flags need to be reinterpreted as type flags
BuildSymbolDisplay(type.Symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
}
else if ((type.Flags & TypeFlags.Tuple) != TypeFlags.None)
{
WriteTupleType((ITupleType)type);
}
else if ((type.Flags & TypeFlags.UnionOrIntersection) != TypeFlags.None)
{
WriteUnionOrIntersectionType(type.Cast<IUnionOrIntersectionType>(), flags);
}
else if ((type.Flags & TypeFlags.Anonymous) != TypeFlags.None)
{
WriteAnonymousType((IObjectType)type, flags);
}
else if ((type.Flags & TypeFlags.StringLiteral) != TypeFlags.None)
{
writer.WriteStringLiteral(I($"\"{TextUtilities.EscapeString(((IStringLiteralType)type).Text)}\""));
}
else
{
// Should never get here
// { ... }
WritePunctuation(writer, SyntaxKind.OpenBraceToken);
WriteSpace(writer);
WritePunctuation(writer, SyntaxKind.DotDotDotToken);
WriteSpace(writer);
WritePunctuation(writer, SyntaxKind.CloseBraceToken);
}
}
void WriteTypeList(IReadOnlyList<IType> types, SyntaxKind delimiter)
{
for (var i = 0; i < types.Count; i++)
{
if (i > 0)
{
if (delimiter != SyntaxKind.CommaToken)
{
WriteSpace(writer);
}
WritePunctuation(writer, delimiter);
WriteSpace(writer);
}
WriteType(types[i], delimiter == SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
}
}
void WriteSymbolTypeReference(ISymbol symbol, IReadOnlyList<IType> typeArguments, int pos, int end, TypeFormatFlags flags)
{
// Unnamed expressions and arrow functions have reserved names that we don't want to display
if ((symbol.Flags & SymbolFlags.Class) != SymbolFlags.None || !IsReservedMemberName(symbol.Name))
{
BuildSymbolDisplay(symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
}
if (pos < end)
{
WritePunctuation(writer, SyntaxKind.LessThanToken);
WriteType(typeArguments[pos++], TypeFormatFlags.None);
while (pos < end)
{
WritePunctuation(writer, SyntaxKind.CommaToken);
WriteSpace(writer);
WriteType(typeArguments[pos++], TypeFormatFlags.None);
}
WritePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
void WriteTypeReference(ITypeReference type, TypeFormatFlags flags)
{
var typeArguments = type.TypeArguments ?? new List<IType>();
if (type.Target == m_checker.m_globalArrayType && (flags & TypeFormatFlags.WriteArrayAsGenericType) == TypeFormatFlags.None)
{
WriteType(typeArguments[0], TypeFormatFlags.InElementType);
WritePunctuation(writer, SyntaxKind.OpenBracketToken);
WritePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else
{
// Write the type reference in the format f<A>.g<B>.C<X, Y> where A and B are type arguments
// for outer type parameters, and f and g are the respective declaring containers of those
// type parameters.
var outerTypeParameters = type.Target.OuterTypeParameters;
var i = 0;
if (outerTypeParameters != null)
{
var length = outerTypeParameters.Count;
while (i < length)
{
// Find group of type arguments for type parameters with the same declaring container.
var start = i;
var parent = m_checker.GetParentSymbolOfTypeParameter(outerTypeParameters[i]);
do
{
i++;
}
while (i < length && m_checker.GetParentSymbolOfTypeParameter(outerTypeParameters[i]) == parent);
// When type parameters are their own type arguments for the whole group (i.e., we have
// the default outer type arguments), we don't show the group.
if (!outerTypeParameters.RangeEquals(typeArguments, start, i, EqualityComparer<IType>.Default))
{
WriteSymbolTypeReference(parent, typeArguments, start, i, flags);
WritePunctuation(writer, SyntaxKind.DotToken);
}
}
}
var typeParameterCount = type.Target.TypeParameters?.Count ?? 0;
WriteSymbolTypeReference(type.Symbol, typeArguments, i, typeParameterCount, flags);
}
}
void WriteTupleType(ITupleType type)
{
WritePunctuation(writer, SyntaxKind.OpenBracketToken);
WriteTypeList(type.ElementTypes, SyntaxKind.CommaToken);
WritePunctuation(writer, SyntaxKind.CloseBracketToken);
}
void WriteUnionOrIntersectionType(IUnionOrIntersectionType type, TypeFormatFlags flags)
{
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.OpenParenToken);
}
WriteTypeList(type.Types, (type.Flags & TypeFlags.Union) != TypeFlags.None ? SyntaxKind.BarToken : SyntaxKind.AmpersandToken);
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.CloseParenToken);
}
}
void WriteAnonymousType(IObjectType type, TypeFormatFlags flags)
{
var symbol = type.Symbol;
if (symbol != null)
{
// Always use 'typeof T' for type of class, enum, and module objects
if ((symbol.Flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) != SymbolFlags.None)
{
WriteTypeofSymbol(type, flags);
}
else if (ShouldWriteTypeOfFunctionSymbol(symbol, flags))
{
WriteTypeofSymbol(type, flags);
}
else if (symbolStack?.Contains(symbol) == true)
{
// If type is an anonymous type literal in a type alias declaration, use type alias name
var typeAlias = m_checker.GetTypeAliasForTypeLiteral(type);
if (typeAlias != null)
{
// The specified symbol flags need to be reinterpreted as type flags
BuildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
}
else
{
// Recursive usage, use any
WriteKeyword(writer, SyntaxKind.AnyKeyword);
}
}
else
{
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type
if (symbolStack == null)
{
symbolStack = new Stack<ISymbol>();
}
symbolStack.Push(symbol);
WriteLiteralType(type, flags);
symbolStack.Pop();
}
}
else
{
// Anonymous types with no symbol are never circular
WriteLiteralType(type, flags);
}
}
void WriteTypeofSymbol(IObjectType type, TypeFormatFlags typeFormatFlags)
{
WriteKeyword(writer, SyntaxKind.TypeOfKeyword);
WriteSpace(writer);
BuildSymbolDisplay(type.Symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
}
string GetIndexerParameterName(IObjectType type, IndexKind indexKind, string fallbackName)
{
var declaration = GetIndexDeclarationOfSymbol(type.Symbol, indexKind);
if (declaration == null)
{
// declaration might not be found if indexer was added from the contextual type.
// in this case use fallback name
return fallbackName;
}
Contract.Assert(declaration.Parameters.Length != 0);
return DeclarationNameToString(declaration.Parameters[0].Name);
}
void WriteLiteralType(IObjectType type, TypeFormatFlags flags)
{
IResolvedType resolved = m_checker.ResolveStructuredTypeMembers(type);
if (resolved.Properties.Count == 0 && resolved.StringIndexType == null && resolved.NumberIndexType == null)
{
if (resolved.CallSignatures.Count == 0 && resolved.ConstructSignatures.Count == 0)
{
WritePunctuation(writer, SyntaxKind.OpenBraceToken);
WritePunctuation(writer, SyntaxKind.CloseBraceToken);
return;
}
if (resolved.CallSignatures.Count == 1 && resolved.ConstructSignatures.Count == 0)
{
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.OpenParenToken);
}
BuildSignatureDisplay(resolved.CallSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ null, symbolStack);
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
}
if (resolved.ConstructSignatures.Count == 1 && resolved.CallSignatures.Count == 0)
{
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.OpenParenToken);
}
WriteKeyword(writer, SyntaxKind.NewKeyword);
WriteSpace(writer);
BuildSignatureDisplay(resolved.ConstructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ null, symbolStack);
if ((flags & TypeFormatFlags.InElementType) != TypeFormatFlags.None)
{
WritePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
}
}
var saveInObjectTypeLiteral = inObjectTypeLiteral;
inObjectTypeLiteral = true;
WritePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.WriteLine();
writer.IncreaseIndent();
foreach (var signature in resolved.CallSignatures.AsStructEnumerable())
{
BuildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ null, symbolStack);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
foreach (var signature in resolved.ConstructSignatures.AsStructEnumerable())
{
BuildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, SignatureKind.Construct, symbolStack);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
if (resolved.StringIndexType != null)
{
// [string x]:
WritePunctuation(writer, SyntaxKind.OpenBracketToken);
writer.WriteParameter(GetIndexerParameterName(resolved, IndexKind.String, /*fallbackName*/"x"));
WritePunctuation(writer, SyntaxKind.ColonToken);
WriteSpace(writer);
WriteKeyword(writer, SyntaxKind.StringKeyword);
WritePunctuation(writer, SyntaxKind.CloseBracketToken);
WritePunctuation(writer, SyntaxKind.ColonToken);
WriteSpace(writer);
WriteType(resolved.StringIndexType, TypeFormatFlags.None);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
if (resolved.NumberIndexType != null)
{
// [int x]:
WritePunctuation(writer, SyntaxKind.OpenBracketToken);
writer.WriteParameter(GetIndexerParameterName(resolved, IndexKind.Number, /*fallbackName*/"x"));
WritePunctuation(writer, SyntaxKind.ColonToken);
WriteSpace(writer);
WriteKeyword(writer, SyntaxKind.NumberKeyword);
WritePunctuation(writer, SyntaxKind.CloseBracketToken);
WritePunctuation(writer, SyntaxKind.ColonToken);
WriteSpace(writer);
WriteType(resolved.NumberIndexType, TypeFormatFlags.None);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
foreach (var p in resolved.Properties.AsStructEnumerable())
{
var t = m_checker.GetTypeOfSymbol(p);
if ((p.Flags & (SymbolFlags.Function | SymbolFlags.Method)) != SymbolFlags.None && m_checker.GetPropertiesOfObjectType(t).Count == 0)
{
var signatures = m_checker.GetSignaturesOfType(t, SignatureKind.Call);
foreach (var signature in signatures.AsStructEnumerable())
{
BuildSymbolDisplay(p, writer);
if ((p.Flags & SymbolFlags.Optional) != SymbolFlags.None)
{
WritePunctuation(writer, SyntaxKind.QuestionToken);
}
BuildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ null, symbolStack);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
}
else
{
BuildSymbolDisplay(p, writer);
if ((p.Flags & SymbolFlags.Optional) != SymbolFlags.None)
{
WritePunctuation(writer, SyntaxKind.QuestionToken);
}
WritePunctuation(writer, SyntaxKind.ColonToken);
WriteSpace(writer);
WriteType(t, TypeFormatFlags.None);
WritePunctuation(writer, SyntaxKind.SemicolonToken);
writer.WriteLine();
}
}
writer.DecreaseIndent();
WritePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
bool ShouldWriteTypeOfFunctionSymbol(ISymbol symbol, TypeFormatFlags flags)
{
var isStaticMethodSymbol = ((symbol.Flags & SymbolFlags.Method) != SymbolFlags.None && // typeof static method
symbol.DeclarationList.Any(declaration => (declaration.Flags & NodeFlags.Static) != NodeFlags.None)) == true;
var isNonLocalFunctionSymbol = (symbol.Flags & SymbolFlags.Function) != SymbolFlags.None &&
(symbol.Parent != null || // is exported symbol
symbol.DeclarationList.Any(declaration =>
declaration.Parent.Kind == SyntaxKind.SourceFile || declaration.Parent.Kind == SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol)
{
// typeof is allowed only for static/non local functions
return (flags & TypeFormatFlags.UseTypeOfFunction) != TypeFormatFlags.None || // use typeof if format flags specify it
symbolStack?.Contains(symbol) == true; // it is type of the symbol uses itself recursively
}
return false;
}
}