Skip to content
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
8 changes: 4 additions & 4 deletions packages/typescript/src/enums/typeFlags.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export enum TypeFlags {
Intersection = 1 << 28,
Reserved1 = 1 << 29,
Reserved2 = 1 << 30,
Reserved3 = 1 << 31,
RegisteredESSymbol = 1 << 31,
AnyOrUnknown = Any | Unknown,
Nullable = Undefined | Null,
Literal = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral,
Expand All @@ -49,7 +49,7 @@ export enum TypeFlags {
BigIntLike = BigInt | BigIntLiteral,
BooleanLike = Boolean | BooleanLiteral,
EnumLike = Enum | EnumLiteral,
ESSymbolLike = ESSymbol | UniqueESSymbol,
ESSymbolLike = ESSymbol | UniqueESSymbol | RegisteredESSymbol,
VoidLike = Void | Undefined,
Primitive = StringLike | NumberLike | BigIntLike | BooleanLike | EnumLike | ESSymbolLike | VoidLike | Null,
DefinitelyNonNullable = StringLike | NumberLike | BigIntLike | BooleanLike | EnumLike | ESSymbolLike | Object | NonPrimitive,
Expand All @@ -58,14 +58,14 @@ export enum TypeFlags {
StructuredType = Object | Union | Intersection,
TypeVariable = TypeParameter | IndexedAccess,
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping | RegisteredESSymbol,
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
StructuredOrInstantiable = StructuredType | Instantiable,
ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection,
Simplifiable = IndexedAccess | Conditional | Index,
Singleton = Any | Unknown | String | Number | Boolean | BigInt | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive | TemplateLiteral | StringMapping,
IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive | TemplateLiteral | StringMapping | RegisteredESSymbol,
IncludesMissingType = TypeParameter,
IncludesNonWideningType = Index,
IncludesWildcard = IndexedAccess,
Expand Down
20 changes: 10 additions & 10 deletions packages/typescript/src/enums/typeFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export var TypeFlags: any;
TypeFlags[TypeFlags["Intersection"] = 268435456] = "Intersection";
TypeFlags[TypeFlags["Reserved1"] = 536870912] = "Reserved1";
TypeFlags[TypeFlags["Reserved2"] = 1073741824] = "Reserved2";
TypeFlags[TypeFlags["Reserved3"] = -2147483648] = "Reserved3";
TypeFlags[TypeFlags["RegisteredESSymbol"] = -2147483648] = "RegisteredESSymbol";
TypeFlags[TypeFlags["AnyOrUnknown"] = 3] = "AnyOrUnknown";
TypeFlags[TypeFlags["Nullable"] = 12] = "Nullable";
TypeFlags[TypeFlags["Literal"] = 15360] = "Literal";
Expand All @@ -49,23 +49,23 @@ export var TypeFlags: any;
TypeFlags[TypeFlags["BigIntLike"] = 4224] = "BigIntLike";
TypeFlags[TypeFlags["BooleanLike"] = 8448] = "BooleanLike";
TypeFlags[TypeFlags["EnumLike"] = 98304] = "EnumLike";
TypeFlags[TypeFlags["ESSymbolLike"] = 16896] = "ESSymbolLike";
TypeFlags[TypeFlags["ESSymbolLike"] = -2147466752] = "ESSymbolLike";
TypeFlags[TypeFlags["VoidLike"] = 20] = "VoidLike";
TypeFlags[TypeFlags["Primitive"] = 12713980] = "Primitive";
TypeFlags[TypeFlags["DefinitelyNonNullable"] = 13893600] = "DefinitelyNonNullable";
TypeFlags[TypeFlags["DisjointDomains"] = 12812284] = "DisjointDomains";
TypeFlags[TypeFlags["Primitive"] = -2134769668] = "Primitive";
TypeFlags[TypeFlags["DefinitelyNonNullable"] = -2133590048] = "DefinitelyNonNullable";
TypeFlags[TypeFlags["DisjointDomains"] = -2134671364] = "DisjointDomains";
TypeFlags[TypeFlags["UnionOrIntersection"] = 402653184] = "UnionOrIntersection";
TypeFlags[TypeFlags["StructuredType"] = 403701760] = "StructuredType";
TypeFlags[TypeFlags["TypeVariable"] = 34078720] = "TypeVariable";
TypeFlags[TypeFlags["InstantiableNonPrimitive"] = 117964800] = "InstantiableNonPrimitive";
TypeFlags[TypeFlags["InstantiablePrimitive"] = 14680064] = "InstantiablePrimitive";
TypeFlags[TypeFlags["Instantiable"] = 132644864] = "Instantiable";
TypeFlags[TypeFlags["StructuredOrInstantiable"] = 536346624] = "StructuredOrInstantiable";
TypeFlags[TypeFlags["InstantiablePrimitive"] = -2132803584] = "InstantiablePrimitive";
TypeFlags[TypeFlags["Instantiable"] = -2014838784] = "Instantiable";
TypeFlags[TypeFlags["StructuredOrInstantiable"] = -1611137024] = "StructuredOrInstantiable";
TypeFlags[TypeFlags["ObjectFlagsType"] = 403963917] = "ObjectFlagsType";
TypeFlags[TypeFlags["Simplifiable"] = 102760448] = "Simplifiable";
TypeFlags[TypeFlags["Singleton"] = 394239] = "Singleton";
TypeFlags[TypeFlags["Narrowable"] = 536575971] = "Narrowable";
TypeFlags[TypeFlags["IncludesMask"] = 416808959] = "IncludesMask";
TypeFlags[TypeFlags["Narrowable"] = -1610907677] = "Narrowable";
TypeFlags[TypeFlags["IncludesMask"] = -1730674689] = "IncludesMask";
TypeFlags[TypeFlags["IncludesMissingType"] = 524288] = "IncludesMissingType";
TypeFlags[TypeFlags["IncludesNonWideningType"] = 2097152] = "IncludesNonWideningType";
TypeFlags[TypeFlags["IncludesWildcard"] = 33554432] = "IncludesWildcard";
Expand Down
2 changes: 1 addition & 1 deletion tsc/internal/api/enum_values_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion tsc/internal/bundled/libs/lib.es2015.symbol.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ interface SymbolConstructor {
* Otherwise, returns a new symbol with this key.
* @param key key to search for.
*/
for(key: string): symbol;
for<Key extends string>(key: Key): RegisteredSymbol<Key>;

/**
* Returns a key from the global symbol registry matching the given Symbol if found.
Expand All @@ -42,3 +42,5 @@ interface SymbolConstructor {
}

declare var Symbol: SymbolConstructor;

type RegisteredSymbol<Key extends string | number> = intrinsic;
114 changes: 99 additions & 15 deletions tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,14 +356,16 @@ const (
IntrinsicTypeKindCapitalize
IntrinsicTypeKindUncapitalize
IntrinsicTypeKindNoInfer
IntrinsicTypeKindRegisteredSymbol
)

var intrinsicTypeKinds = map[string]IntrinsicTypeKind{
"Uppercase": IntrinsicTypeKindUppercase,
"Lowercase": IntrinsicTypeKindLowercase,
"Capitalize": IntrinsicTypeKindCapitalize,
"Uncapitalize": IntrinsicTypeKindUncapitalize,
"NoInfer": IntrinsicTypeKindNoInfer,
"Uppercase": IntrinsicTypeKindUppercase,
"Lowercase": IntrinsicTypeKindLowercase,
"Capitalize": IntrinsicTypeKindCapitalize,
"Uncapitalize": IntrinsicTypeKindUncapitalize,
"NoInfer": IntrinsicTypeKindNoInfer,
"RegisteredSymbol": IntrinsicTypeKindRegisteredSymbol,
}

type MappedTypeModifiers uint32
Expand Down Expand Up @@ -631,6 +633,7 @@ type Checker struct {
indexedAccessTypes map[CacheHashKey]*Type
templateLiteralTypes map[CacheHashKey]*Type
stringMappingTypes map[StringMappingKey]*Type
registeredESSymbolTypes map[CacheHashKey]*Type
uniqueESSymbolTypes map[*ast.Symbol]*Type
thisExpandoKinds map[*ast.Symbol]thisAssignmentDeclarationKind
thisExpandoLocations map[*ast.Symbol]*ast.Node
Expand Down Expand Up @@ -947,6 +950,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) {
c.indexedAccessTypes = make(map[CacheHashKey]*Type)
c.templateLiteralTypes = make(map[CacheHashKey]*Type)
c.stringMappingTypes = make(map[StringMappingKey]*Type)
c.registeredESSymbolTypes = make(map[CacheHashKey]*Type)
c.uniqueESSymbolTypes = make(map[*ast.Symbol]*Type)
c.thisExpandoKinds = make(map[*ast.Symbol]thisAssignmentDeclarationKind)
c.thisExpandoLocations = make(map[*ast.Symbol]*ast.Node)
Expand Down Expand Up @@ -7539,7 +7543,7 @@ func (c *Checker) getQuickTypeOfExpression(node *ast.Node) *Type {
return nil
// Optimize for the common case of a call to a function with a single non-generic call
// signature where we can just fetch the return type without checking the arguments.
case ast.IsCallExpression(expr) && expr.Expression().Kind != ast.KindSuperKeyword && !ast.IsRequireCall(expr, true /*requireStringLiteralLikeArgument*/) && !c.isSymbolOrSymbolForCall(expr) && !ast.IsImportCall(expr):
case ast.IsCallExpression(expr) && expr.Expression().Kind != ast.KindSuperKeyword && !ast.IsRequireCall(expr, true /*requireStringLiteralLikeArgument*/) && !c.isSymbolCall(expr) && !ast.IsImportCall(expr):
if isCallChain(expr) {
return c.getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr)
}
Expand Down Expand Up @@ -8519,7 +8523,7 @@ func (c *Checker) checkCallExpression(node *ast.Node, checkMode CheckMode) *Type
returnType := c.getReturnTypeOfSignature(signature)
// Treat any call to the global 'Symbol' function that is part of a const variable or readonly property
// as a fresh unique symbol literal type.
if returnType.flags&TypeFlagsESSymbolLike != 0 && c.isSymbolOrSymbolForCall(node) {
if returnType.flags&TypeFlagsESSymbolLike != 0 && c.isSymbolCall(node) {
return c.getESSymbolLikeTypeForNode(ast.WalkUpParenthesizedExpressions(node.Parent))
}
if ast.IsCallExpression(node) && node.QuestionDotToken() == nil && ast.IsExpressionStatement(node.Parent) && returnType.flags&TypeFlagsVoid != 0 && c.getTypePredicateOfSignature(signature) != nil {
Expand Down Expand Up @@ -8550,14 +8554,11 @@ func (c *Checker) addDeprecatedSuggestionWithSignature(location *ast.Node, decla
return c.addDeprecatedSuggestionWorker([]*ast.Node{declaration}, diagnostic)
}

func (c *Checker) isSymbolOrSymbolForCall(node *ast.Node) bool {
func (c *Checker) isSymbolCall(node *ast.Node) bool {
if !ast.IsCallExpression(node) {
return false
}
left := node.Expression()
if ast.IsPropertyAccessExpression(left) && left.Name().Text() == "for" {
left = left.Expression()
}
if !ast.IsIdentifier(left) || left.Text() != "Symbol" {
return false
}
Expand Down Expand Up @@ -12501,7 +12502,7 @@ func (c *Checker) checkAssertion(node *ast.Node, checkMode CheckMode) *Type {
// safe even for `x as const` and keeps diagnostics stable regardless of traversal order.
c.checkSourceElement(typeNode)
if isConstTypeReference(typeNode) {
if !c.isValidConstAssertionArgument(node.Expression()) {
if !c.isValidConstAssertionArgument(node.Expression()) && exprType.flags&TypeFlagsUniqueESSymbol == 0 {
c.error(node.Expression(), diagnostics.A_const_assertion_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals)
}
return c.getRegularTypeOfLiteralType(exprType)
Expand Down Expand Up @@ -18584,8 +18585,9 @@ func (c *Checker) widenTypeForVariableLikeDeclaration(t *Type, declaration *ast.
c.reportErrorsFromWidening(declaration, t, WideningKindNormal)
}

// always widen a 'unique symbol' type if the type was created for a different declaration.
if t.flags&TypeFlagsUniqueESSymbol != 0 && (ast.IsBindingElement(declaration) || declaration.Type() == nil) && t.symbol != c.getSymbolOfDeclaration(declaration) {
// Widen a 'unique symbol' type if the type was created for a different declaration, unless the
// declaration or initializer is const-like.
if t.flags&TypeFlagsUniqueESSymbol != 0 && !c.isConstLikeUniqueSymbolDeclaration(declaration) && (ast.IsBindingElement(declaration) || declaration.Type() == nil) && t.symbol != c.getSymbolOfDeclaration(declaration) {
t = c.esSymbolType
}
return c.getWidenedType(t)
Expand All @@ -18605,6 +18607,12 @@ func (c *Checker) widenTypeForVariableLikeDeclaration(t *Type, declaration *ast.
return t
}

func (c *Checker) isConstLikeUniqueSymbolDeclaration(declaration *ast.Node) bool {
return c.getCombinedNodeFlagsCached(declaration)&ast.NodeFlagsConstant != 0 ||
isDeclarationReadonly(declaration) ||
declaration.Initializer() != nil && ast.IsConstAssertion(ast.SkipParentheses(declaration.Initializer()))
}

func (c *Checker) reportImplicitAny(declaration *ast.Node, t *Type, wideningKind WideningKind) {
if ast.IsInJSFile(declaration) && !ast.IsCheckJSEnabledForFile(ast.GetSourceFileOfNode(declaration), c.compilerOptions) {
// Only report implicit any errors/suggestions in TS and ts-check JS files
Expand Down Expand Up @@ -22629,6 +22637,9 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias
return c.getTemplateLiteralType(t.AsTemplateLiteralType().texts, c.instantiateTypes(t.AsTemplateLiteralType().types, m))
case flags&TypeFlagsStringMapping != 0:
return c.getStringMappingType(t.symbol, c.instantiateType(t.AsStringMappingType().target, m))
case flags&TypeFlagsRegisteredESSymbol != 0:
newAlias := c.instantiateTypeAlias(t.alias, m)
return c.getRegisteredESSymbolType(newAlias.typeArguments[0], newAlias)
case flags&TypeFlagsConditional != 0:
return c.getConditionalTypeInstantiation(t, c.combineTypeMappers(t.AsConditionalType().mapper, m), false /*forConstraint*/, alias)
case flags&TypeFlagsSubstitution != 0:
Expand All @@ -22654,6 +22665,10 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias
return t
}

func isRegisteredSymbolAlias(alias *TypeAlias) bool {
return alias != nil && alias.symbol != nil && alias.symbol.Name == "RegisteredSymbol" && len(alias.typeArguments) == 1
}

// Handles instantiation of the following object types:
// AnonymousType (ObjectFlagsAnonymous|ObjectFlagsSingleSignatureType)
// TypeReference with node != nil (ObjectFlagsReference)
Expand Down Expand Up @@ -23358,6 +23373,68 @@ func (c *Checker) getESSymbolLikeTypeForNode(node *ast.Node) *Type {
return c.esSymbolType
}

func (c *Checker) getRegisteredESSymbolType(keyType *Type, alias *TypeAlias) *Type {
if keyType.flags&TypeFlagsNever != 0 {
return c.neverType
}
if keyType.flags&TypeFlagsUnion != 0 {
members := make([]*Type, 0, len(keyType.Types()))
for _, member := range keyType.Types() {
if member.flags&TypeFlagsStringOrNumberLiteral == 0 {
return c.esSymbolType
}
memberAlias := &TypeAlias{symbol: alias.symbol, typeArguments: []*Type{member}}
members = append(members, c.getRegisteredESSymbolType(member, memberAlias))
}
return c.getUnionType(members)
}
if keyType.flags&(TypeFlagsStringOrNumberLiteral|TypeFlagsTypeParameter) == 0 {
return c.esSymbolType
}
key := c.getRegisteredESSymbolTypeKey(keyType)
t := c.registeredESSymbolTypes[key]
if t == nil {
if keyType.flags&TypeFlagsTypeParameter != 0 {
data := &RegisteredESSymbolType{target: keyType}
t = c.newType(TypeFlagsRegisteredESSymbol, ObjectFlagsNone, data)
} else {
name := ast.InternalSymbolNamePrefix + "@@" + c.getRegisteredESSymbolNameText(keyType)
symbol := c.newSymbol(ast.SymbolFlagsProperty, name)
t = c.newUniqueESSymbolType(symbol, name)
}
c.registeredESSymbolTypes[key] = t
}
t.alias = alias
return t
}

func (c *Checker) getRegisteredESSymbolTypeKey(keyType *Type) CacheHashKey {
var b keyBuilder
b.writeString("RegisteredSymbol")
if keyType.flags&TypeFlagsStringLiteral != 0 {
b.writeByte('s')
b.writeString(getStringLiteralValue(keyType))
} else if keyType.flags&TypeFlagsNumberLiteral != 0 {
b.writeByte('n')
b.writeString(getNumberLiteralValue(keyType).String())
} else {
b.writeByte('t')
b.writeType(keyType)
}
return b.hash()
}

func (c *Checker) getRegisteredESSymbolNameText(keyType *Type) string {
switch {
case keyType.flags&TypeFlagsStringLiteral != 0:
return getStringLiteralValue(keyType)
case keyType.flags&TypeFlagsNumberLiteral != 0:
return getNumberLiteralValue(keyType).String()
default:
return c.typeToStringEx(keyType, nil, TypeFormatFlagsNoTruncation|TypeFormatFlagsUseAliasDefinedOutsideCurrentScope, nil)
}
}

func (c *Checker) getTypeFromTypeReference(node *ast.Node) *Type {
links := c.typeNodeLinks.Get(node)
if links.resolvedType == nil {
Expand Down Expand Up @@ -24039,6 +24116,11 @@ func (c *Checker) getTypeAliasInstantiation(symbol *ast.Symbol, typeArguments []
switch typeKind {
case IntrinsicTypeKindNoInfer:
return c.getNoInferType(typeArguments[0])
case IntrinsicTypeKindRegisteredSymbol:
if alias == nil {
alias = &TypeAlias{symbol: symbol, typeArguments: typeArguments}
}
return c.getRegisteredESSymbolType(typeArguments[0], alias)
default:
return c.getStringMappingType(symbol, typeArguments[0])
}
Expand Down Expand Up @@ -27837,7 +27919,7 @@ func (c *Checker) getBaseConstraintOrType(t *Type) *Type {
}

func (c *Checker) getBaseConstraintOfType(t *Type) *Type {
if t.flags&(TypeFlagsInstantiableNonPrimitive|TypeFlagsUnionOrIntersection|TypeFlagsTemplateLiteral|TypeFlagsStringMapping|TypeFlagsIndex) != 0 || c.isGenericTupleType(t) {
if t.flags&(TypeFlagsInstantiableNonPrimitive|TypeFlagsUnionOrIntersection|TypeFlagsTemplateLiteral|TypeFlagsStringMapping|TypeFlagsRegisteredESSymbol|TypeFlagsIndex) != 0 || c.isGenericTupleType(t) {
constraint := c.getResolvedBaseConstraint(t, nil)
if constraint != c.noConstraintType && constraint != c.circularConstraintType {
return constraint
Expand Down Expand Up @@ -27950,6 +28032,8 @@ func (c *Checker) computeBaseConstraint(t *Type, stack []RecursionId) *Type {
return c.getStringMappingType(t.symbol, constraint)
}
return c.stringType
case t.flags&TypeFlagsRegisteredESSymbol != 0:
return c.esSymbolType
case t.flags&TypeFlagsIndexedAccess != 0:
if c.isMappedTypeGenericIndexedAccess(t) {
// For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic,
Expand Down
8 changes: 8 additions & 0 deletions tsc/internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,11 @@ func (b *NodeBuilderImpl) getPropertyNameNodeForSymbolFromNameType(symbol *ast.S
return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod, symbol)
}
if nameType.flags&TypeFlagsUniqueESSymbol != 0 {
if isRegisteredSymbolAlias(nameType.alias) && symbol.ValueDeclaration != nil {
if declName := symbol.ValueDeclaration.Name(); declName != nil && ast.IsComputedPropertyName(declName) {
return b.f.DeepCloneNode(declName)
}
}
// The reference was tracked in the destination scope by trackComputedName.
// Reconstructing its spelling in the source scope must not paint that scope's declarations visible.
return b.f.NewComputedPropertyName(b.symbolToExpressionWorker(nameType.AsUniqueESSymbolType().symbol, ast.SymbolFlagsValue))
Expand Down Expand Up @@ -3409,6 +3414,9 @@ func (b *NodeBuilderImpl) typeToTypeNode(t *Type) *ast.TypeNode {
}
}
if t.flags&TypeFlagsUniqueESSymbol != 0 {
if isRegisteredSymbolAlias(t.alias) {
return t.alias.ToTypeReferenceNode(b)
}
if b.ctx.flags&nodebuilder.FlagsAllowUniqueESSymbolType == 0 {
if b.ch.IsValueSymbolAccessible(t.symbol, b.ctx.enclosingDeclaration) {
b.ctx.approximateLength += 6
Expand Down
2 changes: 2 additions & 0 deletions tsc/internal/checker/relater.go
Original file line number Diff line number Diff line change
Expand Up @@ -3397,6 +3397,8 @@ func (r *Relater) structuredTypeRelatedToWorker(source *Type, target *Type, repo
if source.AsStringMappingType().Symbol() == target.AsStringMappingType().Symbol() {
return r.isRelatedTo(source.AsStringMappingType().target, target.AsStringMappingType().target, RecursionFlagsBoth, false /*reportErrors*/)
}
case source.flags&TypeFlagsRegisteredESSymbol != 0:
return r.isRelatedTo(source.AsRegisteredESSymbolType().target, target.AsRegisteredESSymbolType().target, RecursionFlagsBoth, false /*reportErrors*/)
}
if source.flags&TypeFlagsObject == 0 {
return TernaryFalse
Expand Down
Loading