From 13968b080a173650b8b7f2cc76ba0146365ff1c7 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 22 Aug 2019 16:48:39 -0700 Subject: [PATCH] Nominal type brands --- src/compiler/binder.ts | 9 + src/compiler/checker.ts | 136 ++++++--- src/compiler/types.ts | 40 ++- .../reference/api/tsserverlibrary.d.ts | 26 +- tests/baselines/reference/api/typescript.d.ts | 26 +- .../reference/uniqueNominalBrands1.js | 54 ++++ .../reference/uniqueNominalBrands1.symbols | 104 +++++++ .../reference/uniqueNominalBrands1.types | 119 ++++++++ .../reference/uniqueNominalBrands2.errors.txt | 58 ++++ .../reference/uniqueNominalBrands2.js | 46 +++ .../reference/uniqueNominalBrands2.symbols | 93 ++++++ .../reference/uniqueNominalBrands2.types | 104 +++++++ .../uniqueNominalBrandsControlFlow.errors.txt | 156 ++++++++++ .../uniqueNominalBrandsControlFlow.js | 144 +++++++++ .../uniqueNominalBrandsControlFlow.symbols | 256 ++++++++++++++++ .../uniqueNominalBrandsControlFlow.types | 276 ++++++++++++++++++ .../uniqueNominalBrandsDeclarations1.js | 131 +++++++++ .../uniqueNominalBrandsDeclarations1.symbols | 165 +++++++++++ .../uniqueNominalBrandsDeclarations1.types | 170 +++++++++++ ...niqueNominalBrandsDeclarations2.errors.txt | 14 + .../uniqueNominalBrandsDeclarations2.js | 19 ++ .../uniqueNominalBrandsDeclarations2.symbols | 27 ++ .../uniqueNominalBrandsDeclarations2.types | 25 ++ .../reference/uniqueSymbolsErrors.errors.txt | 5 +- .../reference/uniqueSymbolsErrors.types | 2 +- .../nominalBrands/uniqueNominalBrands1.ts | 28 ++ .../nominalBrands/uniqueNominalBrands2.ts | 25 ++ .../uniqueNominalBrandsControlFlow.ts | 82 ++++++ .../uniqueNominalBrandsDeclarations1.ts | 55 ++++ .../uniqueNominalBrandsDeclarations2.ts | 8 + tests/cases/user/prettier/prettier | 2 +- 31 files changed, 2343 insertions(+), 62 deletions(-) create mode 100644 tests/baselines/reference/uniqueNominalBrands1.js create mode 100644 tests/baselines/reference/uniqueNominalBrands1.symbols create mode 100644 tests/baselines/reference/uniqueNominalBrands1.types create mode 100644 tests/baselines/reference/uniqueNominalBrands2.errors.txt create mode 100644 tests/baselines/reference/uniqueNominalBrands2.js create mode 100644 tests/baselines/reference/uniqueNominalBrands2.symbols create mode 100644 tests/baselines/reference/uniqueNominalBrands2.types create mode 100644 tests/baselines/reference/uniqueNominalBrandsControlFlow.errors.txt create mode 100644 tests/baselines/reference/uniqueNominalBrandsControlFlow.js create mode 100644 tests/baselines/reference/uniqueNominalBrandsControlFlow.symbols create mode 100644 tests/baselines/reference/uniqueNominalBrandsControlFlow.types create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations1.js create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations1.symbols create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations1.types create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations2.errors.txt create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations2.js create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations2.symbols create mode 100644 tests/baselines/reference/uniqueNominalBrandsDeclarations2.types create mode 100644 tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts create mode 100644 tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts create mode 100644 tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts create mode 100644 tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts create mode 100644 tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2b032f456f34a..2a89979e9fc94 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2216,6 +2216,11 @@ namespace ts { break; // Binding the children will handle everything case SyntaxKind.TypeParameter: return bindTypeParameter(node as TypeParameterDeclaration); + case SyntaxKind.TypeOperator: + if ((node as TypeOperatorNode).operator === SyntaxKind.UniqueKeyword) { + return bindUniqueKeyword(node as TypeOperatorNode); + } + break; case SyntaxKind.Parameter: return bindParameter(node); case SyntaxKind.VariableDeclaration: @@ -2929,6 +2934,10 @@ namespace ts { } } + function bindUniqueKeyword(node: TypeOperatorNode) { + addDeclarationToSymbol(createSymbol(SymbolFlags.NominalBrand, InternalSymbolName.NominalBrand), node, SymbolFlags.NominalBrand); + } + // reachability checks function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cfd83efeb31aa..764f6eb1f814f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3752,7 +3752,28 @@ namespace ts { return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; + const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : filter((type).types, t => !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) || !(t.flags & TypeFlags.NominalBrand && !t.aliasSymbol)); + if (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope && type.flags & TypeFlags.Intersection && length(types) !== length((type).types)) { + // If an intersection had brands and no alias, add a `unique` to the front to indicate this + // the brands aren't _precisely_ recoverable by this printback, but it's a good indicator in the LS that there's an unutterable nominal tag on the type + // Ideally, we could hyperlink the `unique` we manufacture here to each of the brand locations it refers to + context.approximateLength += 7; + if (length(types) === 0) { + context.approximateLength += 7; + return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createKeywordTypeNode(SyntaxKind.UnknownKeyword)); + } + if (length(types) === 1) { + return createTypeOperatorNode(SyntaxKind.UniqueKeyword, typeToTypeNodeHelper(types[0], context)); + } + const nodes = mapToTypeNodes(types, context, /*isBareList*/ true); + if (!length(nodes)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + context.encounteredError = true; + } + return undefined!; // TODO: GH#18217 + } + return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, nodes!)); + } if (length(types) === 1) { return typeToTypeNodeHelper(types[0], context); } @@ -3799,6 +3820,17 @@ namespace ts { if (type.flags & TypeFlags.Substitution) { return typeToTypeNodeHelper((type).typeVariable, context); } + if (type.flags & TypeFlags.NominalBrand) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + context.encounteredError = true; + if (context.tracker && context.tracker.trackSymbol) { + // TODO: issue a custom error message about brand name not being directly accessible + context.tracker.trackSymbol(type.symbol, context.enclosingDeclaration, SymbolFlags.Type); + } + } + context.approximateLength += 14; + return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createKeywordTypeNode(SyntaxKind.UnknownKeyword)); + } return Debug.fail("Should be unreachable."); @@ -10206,7 +10238,7 @@ namespace ts { maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type, stringsOnly) : getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))) : type === wildcardType ? wildcardType : - type.flags & TypeFlags.Unknown ? neverType : + type.flags & (TypeFlags.Unknown | TypeFlags.NominalBrand) ? neverType : type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) : !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) : @@ -10235,9 +10267,12 @@ namespace ts { links.resolvedType = getIndexType(getTypeFromTypeNode(node.type)); break; case SyntaxKind.UniqueKeyword: + // Note, the first case does _not_ unwrap parenthesis - this is intentional + // This means if you _actually want_ a _class_ of nominally branded symbols, you can + // accomplish as much by writing `unique (symbol)` to avoid getting a symbol-tied-to-a-value links.resolvedType = node.type.kind === SyntaxKind.SymbolKeyword ? getESSymbolLikeTypeForNode(walkUpParenthesizedTypes(node.parent)) - : errorType; + : getUniqueBrandOfType(getTypeFromTypeNode(node.type), node.symbol, getAliasSymbolForTypeNode(node)); break; case SyntaxKind.ReadonlyKeyword: links.resolvedType = getTypeFromTypeNode(node.type); @@ -10249,6 +10284,37 @@ namespace ts { return links.resolvedType; } + /** + * Note that this construction of brands precludes the possibility of a branded `never` - a `unique never` will always just be `never` + * Meanwhile, a `unique unknown` will produce _just_ the brand. A brand is printed as it's alias, or may be hinted at by `unique ` + * (though that does not specify _which_ instance of `unique` is relevant, just that a brand has been applied!) + */ + function getUniqueBrandOfType(type: Type, brand: Symbol, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined = getTypeArgumentsForAliasSymbol(aliasSymbol)) { + const brandType = getOrCreateBrandFromSymbol(brand); + if (type.flags & TypeFlags.AnyOrUnknown) { + // A `unique any` or a `unique unknown` both become just the brand type, which needs an alias symbol to be printable + // If a type like `type MyObj = { x: unique unknown }` is made, the type of `x` is _just_ the brand from the object literal + // in such scenarios, all printback will simply be `unique unknown` and (if possible), a related span/link back to the `unique` keyword + // where the type originated + // Do note that this means `unique any` actually becomes a very restrictive type, because the `unique` brand removes the any-ness - this + // is intentional. If you're opting in to nominal types, you _probably_ didn't want an `any` flowing in to destroy your brands. + brandType.aliasSymbol = aliasSymbol; + brandType.aliasTypeArguments = aliasTypeArguments; + return brandType; + } + return getIntersectionType([type, brandType], aliasSymbol, aliasTypeArguments); + } + + function getOrCreateBrandFromSymbol(symbol: Symbol) { + const links = getSymbolLinks(symbol); + if (!links.brandType) { + const brandType = createType(TypeFlags.NominalBrand); + brandType.symbol = symbol; + links.brandType = brandType; + } + return links.brandType; + } + function createIndexedAccessType(objectType: Type, indexType: Type) { const type = createType(TypeFlags.IndexedAccess); type.objectType = objectType; @@ -10297,6 +10363,9 @@ namespace ts { } function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { + if (originalObjectType.flags & TypeFlags.NominalBrand) { + return accessFlags & AccessFlags.Writing ? unknownType : neverType; + } const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { @@ -33169,40 +33238,39 @@ namespace ts { function checkGrammarTypeOperatorNode(node: TypeOperatorNode) { if (node.operator === SyntaxKind.UniqueKeyword) { - if (node.type.kind !== SyntaxKind.SymbolKeyword) { - return grammarErrorOnNode(node.type, Diagnostics._0_expected, tokenToString(SyntaxKind.SymbolKeyword)); - } - - const parent = walkUpParenthesizedTypes(node.parent); - switch (parent.kind) { - case SyntaxKind.VariableDeclaration: - const decl = parent as VariableDeclaration; - if (decl.name.kind !== SyntaxKind.Identifier) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); - } - if (!isVariableDeclarationInVariableStatement(decl)) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); - } - if (!(decl.parent.flags & NodeFlags.Const)) { - return grammarErrorOnNode((parent).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); - } - break; + if (node.type.kind === SyntaxKind.SymbolKeyword) { + // Continue to recognize `unique symbol` as a special kind of type with certain restrictions to permit analysis + const parent = walkUpParenthesizedTypes(node.parent); + switch (parent.kind) { + case SyntaxKind.VariableDeclaration: + const decl = parent as VariableDeclaration; + if (decl.name.kind !== SyntaxKind.Identifier) { + return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); + } + if (!isVariableDeclarationInVariableStatement(decl)) { + return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); + } + if (!(decl.parent.flags & NodeFlags.Const)) { + return grammarErrorOnNode((parent).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); + } + break; - case SyntaxKind.PropertyDeclaration: - if (!hasModifier(parent, ModifierFlags.Static) || - !hasModifier(parent, ModifierFlags.Readonly)) { - return grammarErrorOnNode((parent).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly); - } - break; + case SyntaxKind.PropertyDeclaration: + if (!hasModifier(parent, ModifierFlags.Static) || + !hasModifier(parent, ModifierFlags.Readonly)) { + return grammarErrorOnNode((parent).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly); + } + break; - case SyntaxKind.PropertySignature: - if (!hasModifier(parent, ModifierFlags.Readonly)) { - return grammarErrorOnNode((parent).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly); - } - break; + case SyntaxKind.PropertySignature: + if (!hasModifier(parent, ModifierFlags.Readonly)) { + return grammarErrorOnNode((parent).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly); + } + break; - default: - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here); + default: + return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here); + } } } else if (node.operator === SyntaxKind.ReadonlyKeyword) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dbb2dec0c513a..c4fc695b9d86d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1244,7 +1244,7 @@ namespace ts { type: TypeNode; } - export interface TypeOperatorNode extends TypeNode { + export interface TypeOperatorNode extends TypeNode, Declaration { kind: SyntaxKind.TypeOperator; operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; type: TypeNode; @@ -3692,6 +3692,7 @@ namespace ts { Transient = 1 << 25, // Transient symbol (created during type check) Assignment = 1 << 26, // Assignment treated as declaration (eg `this.prop = 1`) ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports` + NominalBrand = 1 << 28, // Symbol associated with a nominal brand location, eg `unique string` /* @internal */ All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral @@ -3700,7 +3701,7 @@ namespace ts { Enum = RegularEnum | ConstEnum, Variable = FunctionScopedVariable | BlockScopedVariable, Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, - Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias, + Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | NominalBrand, Namespace = ValueModule | NamespaceModule | Enum, Module = ValueModule | NamespaceModule, Accessor = GetAccessor | SetAccessor, @@ -3803,6 +3804,7 @@ namespace ts { variances?: VarianceFlags[]; // Alias symbol type argument variance cache deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type deferralParent?: Type; // Source union/intersection of a deferred type + brandType?: NominalBrandType; // The nominal brand type associated with this symbol } /* @internal */ @@ -3865,6 +3867,7 @@ namespace ts { ExportEquals = "export=", // Export assignment symbol Default = "default", // Default export symbol (technically not wholly internal, but included here for usability) This = "this", + NominalBrand = "__brand", // non-brinting name of a nominal brand symbol } /** @@ -3984,6 +3987,7 @@ namespace ts { Conditional = 1 << 24, // T extends U ? X : Y Substitution = 1 << 25, // Type parameter substitution NonPrimitive = 1 << 26, // intrinsic object type + NominalBrand = 1 << 27, // unique === & NominalBrand[node] /* @internal */ AnyOrUnknown = Any | Unknown, @@ -4431,6 +4435,38 @@ namespace ts { substitute: Type; // Type to substitute for type parameter } + // Nominal brand types (TypeFlags.NominalBrand) + // Nominal brand types are structureless singleton types which have no assignability relationships other than + // to `unknown` and themselves, and from `never` - all other rules fall out from how they're used + // (which is to say, as an intersection member). This actually means that within `isRelatedTo`, there + // is _zero_ mention of the NominalBrandType. Pretty neat. + // keyof a brand is never - which is to say that if you say `keyof unique {x}`, you just get `"x"` out. + // The nominal branded-ness of a type tells you nothing about the branded-ness or anything else about its keys. + // This is potentially up for debate - it's entirely possible to produce a usecase for wanting a viable + // `extends keyof BrandedType` constraint that requires that they keys be intersected with a `keyof brand`. Given + // the impossibility of implementing such a type safely, combined with the fact that all keys are only strings + // at runtime, make the value of such a thing unclear. + // Indexing into a brand produces `unknown` when an intersection is made (ie, for writing), or + // `never` when a union is (ie, for reading), which is to say it functions as a kind of blank + // (a brand says nothing about the branded-ness of their members) + // Nominal brands do not reduce with one another in intersections or unions - this is so that a + // type NormalizedPath = unique string; + // and + // type AbsolutePath = unique string; + // can be naturally combined into + // type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; + // You might be wondering "why have a symbol, why not just patch on a declaration directly, it's not like the symbol + // is able to be named" - and you'd be reasonable in wondering as much. The reason we still work with + // a symbol is so that services knows how to look up the declaration of the type "for free" + // It is probably also worth noting at this point that theere is no _safe_ way to narrow to a nominal brand + // - a brand type must arise from a type system operation, which likely means from a declaration or cast + // at some origin point. This is because there is no way for the compiler to know what assumptions need to + // be upheld for your nominal brand ot be safely implemented, so the assumption is simply that it _cannot_ + // be safely implemented (and so must be cast to in some way). + export interface NominalBrandType extends Type { + symbol: Symbol; + } + /* @internal */ export const enum JsxReferenceKind { Component, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index bffe2114d19b5..451c61b069700 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -821,7 +821,7 @@ declare namespace ts { kind: SyntaxKind.ParenthesizedType; type: TypeNode; } - export interface TypeOperatorNode extends TypeNode { + export interface TypeOperatorNode extends TypeNode, Declaration { kind: SyntaxKind.TypeOperator; operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; type: TypeNode; @@ -2134,10 +2134,11 @@ declare namespace ts { Transient = 33554432, Assignment = 67108864, ModuleExports = 134217728, + NominalBrand = 268435456, Enum = 384, Variable = 3, Value = 111551, - Type = 788968, + Type = 269224424, Namespace = 1920, Module = 1536, Accessor = 98304, @@ -2145,19 +2146,19 @@ declare namespace ts { BlockScopedVariableExcludes = 111551, ParameterExcludes = 111551, PropertyExcludes = 0, - EnumMemberExcludes = 900095, + EnumMemberExcludes = 269335551, FunctionExcludes = 110991, - ClassExcludes = 899503, - InterfaceExcludes = 788872, - RegularEnumExcludes = 899327, - ConstEnumExcludes = 899967, + ClassExcludes = 269334959, + InterfaceExcludes = 269224328, + RegularEnumExcludes = 269334783, + ConstEnumExcludes = 269335423, ValueModuleExcludes = 110735, NamespaceModuleExcludes = 0, MethodExcludes = 103359, GetAccessorExcludes = 46015, SetAccessorExcludes = 78783, - TypeParameterExcludes = 526824, - TypeAliasExcludes = 788968, + TypeParameterExcludes = 268962280, + TypeAliasExcludes = 269224424, AliasExcludes = 2097152, ModuleMember = 2623475, ExportHasLocal = 944, @@ -2191,7 +2192,8 @@ declare namespace ts { Resolving = "__resolving__", ExportEquals = "export=", Default = "default", - This = "this" + This = "this", + NominalBrand = "__brand" } /** * This represents a string whose leading underscore have been escaped by adding extra leading underscores. @@ -2252,6 +2254,7 @@ declare namespace ts { Conditional = 16777216, Substitution = 33554432, NonPrimitive = 67108864, + NominalBrand = 134217728, Literal = 2944, Unit = 109440, StringOrNumberLiteral = 384, @@ -2415,6 +2418,9 @@ declare namespace ts { typeVariable: TypeVariable; substitute: Type; } + export interface NominalBrandType extends Type { + symbol: Symbol; + } export enum SignatureKind { Call = 0, Construct = 1 diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 457a1acb227aa..0ce2e11a00459 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -821,7 +821,7 @@ declare namespace ts { kind: SyntaxKind.ParenthesizedType; type: TypeNode; } - export interface TypeOperatorNode extends TypeNode { + export interface TypeOperatorNode extends TypeNode, Declaration { kind: SyntaxKind.TypeOperator; operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; type: TypeNode; @@ -2134,10 +2134,11 @@ declare namespace ts { Transient = 33554432, Assignment = 67108864, ModuleExports = 134217728, + NominalBrand = 268435456, Enum = 384, Variable = 3, Value = 111551, - Type = 788968, + Type = 269224424, Namespace = 1920, Module = 1536, Accessor = 98304, @@ -2145,19 +2146,19 @@ declare namespace ts { BlockScopedVariableExcludes = 111551, ParameterExcludes = 111551, PropertyExcludes = 0, - EnumMemberExcludes = 900095, + EnumMemberExcludes = 269335551, FunctionExcludes = 110991, - ClassExcludes = 899503, - InterfaceExcludes = 788872, - RegularEnumExcludes = 899327, - ConstEnumExcludes = 899967, + ClassExcludes = 269334959, + InterfaceExcludes = 269224328, + RegularEnumExcludes = 269334783, + ConstEnumExcludes = 269335423, ValueModuleExcludes = 110735, NamespaceModuleExcludes = 0, MethodExcludes = 103359, GetAccessorExcludes = 46015, SetAccessorExcludes = 78783, - TypeParameterExcludes = 526824, - TypeAliasExcludes = 788968, + TypeParameterExcludes = 268962280, + TypeAliasExcludes = 269224424, AliasExcludes = 2097152, ModuleMember = 2623475, ExportHasLocal = 944, @@ -2191,7 +2192,8 @@ declare namespace ts { Resolving = "__resolving__", ExportEquals = "export=", Default = "default", - This = "this" + This = "this", + NominalBrand = "__brand" } /** * This represents a string whose leading underscore have been escaped by adding extra leading underscores. @@ -2252,6 +2254,7 @@ declare namespace ts { Conditional = 16777216, Substitution = 33554432, NonPrimitive = 67108864, + NominalBrand = 134217728, Literal = 2944, Unit = 109440, StringOrNumberLiteral = 384, @@ -2415,6 +2418,9 @@ declare namespace ts { typeVariable: TypeVariable; substitute: Type; } + export interface NominalBrandType extends Type { + symbol: Symbol; + } export enum SignatureKind { Call = 0, Construct = 1 diff --git a/tests/baselines/reference/uniqueNominalBrands1.js b/tests/baselines/reference/uniqueNominalBrands1.js new file mode 100644 index 0000000000000..f72f0e6e3d753 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands1.js @@ -0,0 +1,54 @@ +//// [uniqueNominalBrands1.ts] +export type Paired = { + x: unique number; + y: unique number; +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = makePair(0, 0); +const b = {x: 0, y: 0}; + +if (Math.random() > 0.3) { + b.x = a.x; + b.y = a.y; +} + +if (isPaired(b)) { + b.x = a.x; + b.y = a.y; + a.x = b.x; + a.y = b.y; +} + + +//// [uniqueNominalBrands1.js] +"use strict"; +exports.__esModule = true; +function isPaired(x) { + return true; +} +exports.isPaired = isPaired; +function makePair(x, y) { + return { x: x, y: y }; +} +exports.makePair = makePair; +var a = makePair(0, 0); +var b = { x: 0, y: 0 }; +if (Math.random() > 0.3) { + b.x = a.x; + b.y = a.y; +} +if (isPaired(b)) { + b.x = a.x; + b.y = a.y; + a.x = b.x; + a.y = b.y; +} diff --git a/tests/baselines/reference/uniqueNominalBrands1.symbols b/tests/baselines/reference/uniqueNominalBrands1.symbols new file mode 100644 index 0000000000000..c399bc8413433 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands1.symbols @@ -0,0 +1,104 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts === +export type Paired = { +>Paired : Symbol(Paired, Decl(uniqueNominalBrands1.ts, 0, 0)) + + x: unique number; +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) + + y: unique number; +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) + +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : Symbol(isPaired, Decl(uniqueNominalBrands1.ts, 3, 2)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 6, 25)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 6, 29)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 6, 39)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 6, 25)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands1.ts, 0, 0)) + + return true; +} + +export function makePair(x: number, y: number): Paired { +>makePair : Symbol(makePair, Decl(uniqueNominalBrands1.ts, 8, 1)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 10, 25)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 10, 35)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands1.ts, 0, 0)) + + return {x, y} as Paired; +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 11, 12)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 11, 14)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands1.ts, 0, 0)) +} + +const a = makePair(0, 0); +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>makePair : Symbol(makePair, Decl(uniqueNominalBrands1.ts, 8, 1)) + +const b = {x: 0, y: 0}; +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 15, 11)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 15, 16)) + +if (Math.random() > 0.3) { +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + b.x = a.x; +>b.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 15, 11)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 15, 11)) +>a.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) + + b.y = a.y; +>b.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 15, 16)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 15, 16)) +>a.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +} + +if (isPaired(b)) { +>isPaired : Symbol(isPaired, Decl(uniqueNominalBrands1.ts, 3, 2)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) + + b.x = a.x; +>b.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>a.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) + + b.y = a.y; +>b.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>a.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) + + a.x = b.x; +>a.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>b.x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands1.ts, 0, 22)) + + a.y = b.y; +>a.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands1.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>b.y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +>b : Symbol(b, Decl(uniqueNominalBrands1.ts, 15, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands1.ts, 1, 21)) +} + diff --git a/tests/baselines/reference/uniqueNominalBrands1.types b/tests/baselines/reference/uniqueNominalBrands1.types new file mode 100644 index 0000000000000..e9e923c0b09a5 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands1.types @@ -0,0 +1,119 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts === +export type Paired = { +>Paired : Paired + + x: unique number; +>x : number & unique unknown + + y: unique number; +>y : number & unique unknown + +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : (x: { x: number; y: number; }) => x is Paired +>x : { x: number; y: number; } +>x : number +>y : number + + return true; +>true : true +} + +export function makePair(x: number, y: number): Paired { +>makePair : (x: number, y: number) => Paired +>x : number +>y : number + + return {x, y} as Paired; +>{x, y} as Paired : Paired +>{x, y} : { x: number; y: number; } +>x : number +>y : number +} + +const a = makePair(0, 0); +>a : Paired +>makePair(0, 0) : Paired +>makePair : (x: number, y: number) => Paired +>0 : 0 +>0 : 0 + +const b = {x: 0, y: 0}; +>b : { x: number; y: number; } +>{x: 0, y: 0} : { x: number; y: number; } +>x : number +>0 : 0 +>y : number +>0 : 0 + +if (Math.random() > 0.3) { +>Math.random() > 0.3 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.3 : 0.3 + + b.x = a.x; +>b.x = a.x : number & unique unknown +>b.x : number +>b : { x: number; y: number; } +>x : number +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown + + b.y = a.y; +>b.y = a.y : number & unique unknown +>b.y : number +>b : { x: number; y: number; } +>y : number +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown +} + +if (isPaired(b)) { +>isPaired(b) : boolean +>isPaired : (x: { x: number; y: number; }) => x is Paired +>b : { x: number; y: number; } + + b.x = a.x; +>b.x = a.x : number & unique unknown +>b.x : number & unique unknown +>b : Paired +>x : number & unique unknown +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown + + b.y = a.y; +>b.y = a.y : number & unique unknown +>b.y : number & unique unknown +>b : Paired +>y : number & unique unknown +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown + + a.x = b.x; +>a.x = b.x : number & unique unknown +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown +>b.x : number & unique unknown +>b : Paired +>x : number & unique unknown + + a.y = b.y; +>a.y = b.y : number & unique unknown +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown +>b.y : number & unique unknown +>b : Paired +>y : number & unique unknown +} + diff --git a/tests/baselines/reference/uniqueNominalBrands2.errors.txt b/tests/baselines/reference/uniqueNominalBrands2.errors.txt new file mode 100644 index 0000000000000..d757ca7a7ec15 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands2.errors.txt @@ -0,0 +1,58 @@ +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(18,1): error TS2719: Type 'number & unique unknown' is not assignable to type 'number & unique unknown'. Two different types with this name exist, but they are unrelated. + Type 'unique number' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(19,1): error TS2719: Type 'number & unique unknown' is not assignable to type 'number & unique unknown'. Two different types with this name exist, but they are unrelated. + Type 'unique number' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(21,1): error TS2322: Type 'number' is not assignable to type 'unique number'. + Type 'number' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(22,1): error TS2322: Type 'number' is not assignable to type 'unique number'. + Type 'number' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(24,1): error TS2322: Type 'number' is not assignable to type 'unique number'. + Type 'number' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts(25,1): error TS2322: Type 'number' is not assignable to type 'unique number'. + Type 'number' is not assignable to type 'unique unknown'. + + +==== tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts (6 errors) ==== + export type Paired = { + x: unique number; + y: unique number; + }; + + + export function isPaired(x: {x: number, y: number}): x is Paired { + return true; + } + + export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; + } + + const a = makePair(0, 0); + const b = {x: 0, y: 0}; + + a.x = a.y; // err + ~~~ +!!! error TS2719: Type 'number & unique unknown' is not assignable to type 'number & unique unknown'. Two different types with this name exist, but they are unrelated. +!!! error TS2719: Type 'unique number' is not assignable to type 'unique unknown'. + a.y = a.x; // err + ~~~ +!!! error TS2719: Type 'number & unique unknown' is not assignable to type 'number & unique unknown'. Two different types with this name exist, but they are unrelated. +!!! error TS2719: Type 'unique number' is not assignable to type 'unique unknown'. + + a.x = b.y; // err + ~~~ +!!! error TS2322: Type 'number' is not assignable to type 'unique number'. +!!! error TS2322: Type 'number' is not assignable to type 'unique unknown'. + a.y = b.y; // err + ~~~ +!!! error TS2322: Type 'number' is not assignable to type 'unique number'. +!!! error TS2322: Type 'number' is not assignable to type 'unique unknown'. + + a.x = b.x; // err + ~~~ +!!! error TS2322: Type 'number' is not assignable to type 'unique number'. +!!! error TS2322: Type 'number' is not assignable to type 'unique unknown'. + a.y = b.x; // err + ~~~ +!!! error TS2322: Type 'number' is not assignable to type 'unique number'. +!!! error TS2322: Type 'number' is not assignable to type 'unique unknown'. \ No newline at end of file diff --git a/tests/baselines/reference/uniqueNominalBrands2.js b/tests/baselines/reference/uniqueNominalBrands2.js new file mode 100644 index 0000000000000..43f850f7637e4 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands2.js @@ -0,0 +1,46 @@ +//// [uniqueNominalBrands2.ts] +export type Paired = { + x: unique number; + y: unique number; +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = makePair(0, 0); +const b = {x: 0, y: 0}; + +a.x = a.y; // err +a.y = a.x; // err + +a.x = b.y; // err +a.y = b.y; // err + +a.x = b.x; // err +a.y = b.x; // err + +//// [uniqueNominalBrands2.js] +"use strict"; +exports.__esModule = true; +function isPaired(x) { + return true; +} +exports.isPaired = isPaired; +function makePair(x, y) { + return { x: x, y: y }; +} +exports.makePair = makePair; +var a = makePair(0, 0); +var b = { x: 0, y: 0 }; +a.x = a.y; // err +a.y = a.x; // err +a.x = b.y; // err +a.y = b.y; // err +a.x = b.x; // err +a.y = b.x; // err diff --git a/tests/baselines/reference/uniqueNominalBrands2.symbols b/tests/baselines/reference/uniqueNominalBrands2.symbols new file mode 100644 index 0000000000000..74592cf2cb189 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands2.symbols @@ -0,0 +1,93 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts === +export type Paired = { +>Paired : Symbol(Paired, Decl(uniqueNominalBrands2.ts, 0, 0)) + + x: unique number; +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) + + y: unique number; +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) + +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : Symbol(isPaired, Decl(uniqueNominalBrands2.ts, 3, 2)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 6, 25)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 6, 29)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 6, 39)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 6, 25)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands2.ts, 0, 0)) + + return true; +} + +export function makePair(x: number, y: number): Paired { +>makePair : Symbol(makePair, Decl(uniqueNominalBrands2.ts, 8, 1)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 10, 25)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 10, 35)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands2.ts, 0, 0)) + + return {x, y} as Paired; +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 11, 12)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 11, 14)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrands2.ts, 0, 0)) +} + +const a = makePair(0, 0); +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>makePair : Symbol(makePair, Decl(uniqueNominalBrands2.ts, 8, 1)) + +const b = {x: 0, y: 0}; +>b : Symbol(b, Decl(uniqueNominalBrands2.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 15, 11)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 15, 16)) + +a.x = a.y; // err +>a.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>a.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) + +a.y = a.x; // err +>a.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>a.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) + +a.x = b.y; // err +>a.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>b.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 15, 16)) +>b : Symbol(b, Decl(uniqueNominalBrands2.ts, 15, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 15, 16)) + +a.y = b.y; // err +>a.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>b.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 15, 16)) +>b : Symbol(b, Decl(uniqueNominalBrands2.ts, 15, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 15, 16)) + +a.x = b.x; // err +>a.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 0, 22)) +>b.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 15, 11)) +>b : Symbol(b, Decl(uniqueNominalBrands2.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 15, 11)) + +a.y = b.x; // err +>a.y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>a : Symbol(a, Decl(uniqueNominalBrands2.ts, 14, 5)) +>y : Symbol(y, Decl(uniqueNominalBrands2.ts, 1, 21)) +>b.x : Symbol(x, Decl(uniqueNominalBrands2.ts, 15, 11)) +>b : Symbol(b, Decl(uniqueNominalBrands2.ts, 15, 5)) +>x : Symbol(x, Decl(uniqueNominalBrands2.ts, 15, 11)) + diff --git a/tests/baselines/reference/uniqueNominalBrands2.types b/tests/baselines/reference/uniqueNominalBrands2.types new file mode 100644 index 0000000000000..f1e640db92030 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrands2.types @@ -0,0 +1,104 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts === +export type Paired = { +>Paired : Paired + + x: unique number; +>x : number & unique unknown + + y: unique number; +>y : number & unique unknown + +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : (x: { x: number; y: number; }) => x is Paired +>x : { x: number; y: number; } +>x : number +>y : number + + return true; +>true : true +} + +export function makePair(x: number, y: number): Paired { +>makePair : (x: number, y: number) => Paired +>x : number +>y : number + + return {x, y} as Paired; +>{x, y} as Paired : Paired +>{x, y} : { x: number; y: number; } +>x : number +>y : number +} + +const a = makePair(0, 0); +>a : Paired +>makePair(0, 0) : Paired +>makePair : (x: number, y: number) => Paired +>0 : 0 +>0 : 0 + +const b = {x: 0, y: 0}; +>b : { x: number; y: number; } +>{x: 0, y: 0} : { x: number; y: number; } +>x : number +>0 : 0 +>y : number +>0 : 0 + +a.x = a.y; // err +>a.x = a.y : number & unique unknown +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown + +a.y = a.x; // err +>a.y = a.x : number & unique unknown +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown + +a.x = b.y; // err +>a.x = b.y : number +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown +>b.y : number +>b : { x: number; y: number; } +>y : number + +a.y = b.y; // err +>a.y = b.y : number +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown +>b.y : number +>b : { x: number; y: number; } +>y : number + +a.x = b.x; // err +>a.x = b.x : number +>a.x : number & unique unknown +>a : Paired +>x : number & unique unknown +>b.x : number +>b : { x: number; y: number; } +>x : number + +a.y = b.x; // err +>a.y = b.x : number +>a.y : number & unique unknown +>a : Paired +>y : number & unique unknown +>b.x : number +>b : { x: number; y: number; } +>x : number + diff --git a/tests/baselines/reference/uniqueNominalBrandsControlFlow.errors.txt b/tests/baselines/reference/uniqueNominalBrandsControlFlow.errors.txt new file mode 100644 index 0000000000000..d561f295daeca --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsControlFlow.errors.txt @@ -0,0 +1,156 @@ +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(22,23): error TS2345: Argument of type '{ x: number; } & BrandA' is not assignable to parameter of type 'BrandB'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(24,27): error TS2345: Argument of type '{ x: number; } & BrandA' is not assignable to parameter of type 'BrandA & BrandB'. + Type '{ x: number; } & BrandA' is not assignable to type 'BrandB'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(29,23): error TS2345: Argument of type '{ x: number; } & BrandB' is not assignable to parameter of type 'BrandA'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(32,27): error TS2345: Argument of type '{ x: number; } & BrandB' is not assignable to parameter of type 'BrandA & BrandB'. + Type '{ x: number; } & BrandB' is not assignable to type 'BrandA'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(35,23): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(36,23): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandB'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(37,26): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA | BrandB'. + Type '{ x: number; }' is not assignable to type 'BrandB'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(38,27): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA & BrandB'. + Type '{ x: number; }' is not assignable to type 'BrandA'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(64,29): error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'AbsolutePath'. + Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(66,39): error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. + Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(71,31): error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedPath'. + Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(74,39): error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. + Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(77,31): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedPath'. + Type '"/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(78,29): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'AbsolutePath'. + Type '"/a/b/c"' is not assignable to type 'unique unknown'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(79,41): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedPath | AbsolutePath'. +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts(80,39): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. + Type '"/a/b/c"' is not assignable to type 'unique unknown'. + + +==== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts (16 errors) ==== + type BrandA = unique unknown; + type BrandB = unique unknown; + + declare function isBrandA(x: any): x is BrandA; + declare function isBrandB(x: any): x is BrandB; + + declare function consumeBrandA(x: BrandA): void; + declare function consumeBrandB(x: BrandB): void; + declare function consumeBrandAOrB(x: BrandA | BrandB): void; + declare function consumeBrandAAndB(x: BrandA & BrandB): void; + + const x = {x: 12}; + if (isBrandA(x)) { + if (isBrandB(x)) { + consumeBrandA(x); + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); + } + else { + consumeBrandA(x); + consumeBrandB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; } & BrandA' is not assignable to parameter of type 'BrandB'. + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; } & BrandA' is not assignable to parameter of type 'BrandA & BrandB'. +!!! error TS2345: Type '{ x: number; } & BrandA' is not assignable to type 'BrandB'. + } + } + else { + if (isBrandB(x)) { + consumeBrandA(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; } & BrandB' is not assignable to parameter of type 'BrandA'. + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; } & BrandB' is not assignable to parameter of type 'BrandA & BrandB'. +!!! error TS2345: Type '{ x: number; } & BrandB' is not assignable to type 'BrandA'. + } + else { + consumeBrandA(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA'. + consumeBrandB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandB'. + consumeBrandAOrB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA | BrandB'. +!!! error TS2345: Type '{ x: number; }' is not assignable to type 'BrandB'. + consumeBrandAAndB(x); // err + ~ +!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'BrandA & BrandB'. +!!! error TS2345: Type '{ x: number; }' is not assignable to type 'BrandA'. + } + } + + type NormalizedPath = unique string; + type AbsolutePath = unique string; + type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; + + declare function isNormalizedPath(x: string): x is NormalizedPath; + declare function isAbsolutePath(x: string): x is AbsolutePath; + + declare function consumeNormalizedPath(x: NormalizedPath): void; + declare function consumeAbsolutePath(x: AbsolutePath): void; + declare function consumeNormalizedOrAbsolutePath(x: NormalizedPath | AbsolutePath): void; + declare function consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void; + + const p = "/a/b/c"; + if (isNormalizedPath(p)) { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); + } + else { + consumeNormalizedPath(p); + consumeAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'AbsolutePath'. +!!! error TS2345: Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. +!!! error TS2345: Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. + } + } + else { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); // err + ~ +!!! error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedPath'. +!!! error TS2345: Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type 'unique "/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. +!!! error TS2345: Type 'unique "/a/b/c"' is not assignable to type 'unique unknown'. + } + else { + consumeNormalizedPath(p); // err + ~ +!!! error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedPath'. +!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'unique unknown'. + consumeAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'AbsolutePath'. +!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'unique unknown'. + consumeNormalizedOrAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedPath | AbsolutePath'. + consumeNormalizedAbsolutePath(p); // err + ~ +!!! error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedAbsolutePath'. +!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'unique unknown'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/uniqueNominalBrandsControlFlow.js b/tests/baselines/reference/uniqueNominalBrandsControlFlow.js new file mode 100644 index 0000000000000..bf5d82afdf6d8 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsControlFlow.js @@ -0,0 +1,144 @@ +//// [uniqueNominalBrandsControlFlow.ts] +type BrandA = unique unknown; +type BrandB = unique unknown; + +declare function isBrandA(x: any): x is BrandA; +declare function isBrandB(x: any): x is BrandB; + +declare function consumeBrandA(x: BrandA): void; +declare function consumeBrandB(x: BrandB): void; +declare function consumeBrandAOrB(x: BrandA | BrandB): void; +declare function consumeBrandAAndB(x: BrandA & BrandB): void; + +const x = {x: 12}; +if (isBrandA(x)) { + if (isBrandB(x)) { + consumeBrandA(x); + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); + } + else { + consumeBrandA(x); + consumeBrandB(x); // err + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } +} +else { + if (isBrandB(x)) { + consumeBrandA(x); // err + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } + else { + consumeBrandA(x); // err + consumeBrandB(x); // err + consumeBrandAOrB(x); // err + consumeBrandAAndB(x); // err + } +} + +type NormalizedPath = unique string; +type AbsolutePath = unique string; +type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; + +declare function isNormalizedPath(x: string): x is NormalizedPath; +declare function isAbsolutePath(x: string): x is AbsolutePath; + +declare function consumeNormalizedPath(x: NormalizedPath): void; +declare function consumeAbsolutePath(x: AbsolutePath): void; +declare function consumeNormalizedOrAbsolutePath(x: NormalizedPath | AbsolutePath): void; +declare function consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void; + +const p = "/a/b/c"; +if (isNormalizedPath(p)) { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); + } + else { + consumeNormalizedPath(p); + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } +} +else { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } + else { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); // err + consumeNormalizedAbsolutePath(p); // err + } +} + + +//// [uniqueNominalBrandsControlFlow.js] +var x = { x: 12 }; +if (isBrandA(x)) { + if (isBrandB(x)) { + consumeBrandA(x); + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); + } + else { + consumeBrandA(x); + consumeBrandB(x); // err + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } +} +else { + if (isBrandB(x)) { + consumeBrandA(x); // err + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } + else { + consumeBrandA(x); // err + consumeBrandB(x); // err + consumeBrandAOrB(x); // err + consumeBrandAAndB(x); // err + } +} +var p = "/a/b/c"; +if (isNormalizedPath(p)) { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); + } + else { + consumeNormalizedPath(p); + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } +} +else { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } + else { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); // err + consumeNormalizedAbsolutePath(p); // err + } +} diff --git a/tests/baselines/reference/uniqueNominalBrandsControlFlow.symbols b/tests/baselines/reference/uniqueNominalBrandsControlFlow.symbols new file mode 100644 index 0000000000000..a5e3d0cb1358e --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsControlFlow.symbols @@ -0,0 +1,256 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts === +type BrandA = unique unknown; +>BrandA : Symbol(BrandA, Decl(uniqueNominalBrandsControlFlow.ts, 0, 0)) + +type BrandB = unique unknown; +>BrandB : Symbol(BrandB, Decl(uniqueNominalBrandsControlFlow.ts, 0, 29)) + +declare function isBrandA(x: any): x is BrandA; +>isBrandA : Symbol(isBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 1, 29)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 3, 26)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 3, 26)) +>BrandA : Symbol(BrandA, Decl(uniqueNominalBrandsControlFlow.ts, 0, 0)) + +declare function isBrandB(x: any): x is BrandB; +>isBrandB : Symbol(isBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 3, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 4, 26)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 4, 26)) +>BrandB : Symbol(BrandB, Decl(uniqueNominalBrandsControlFlow.ts, 0, 29)) + +declare function consumeBrandA(x: BrandA): void; +>consumeBrandA : Symbol(consumeBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 4, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 6, 31)) +>BrandA : Symbol(BrandA, Decl(uniqueNominalBrandsControlFlow.ts, 0, 0)) + +declare function consumeBrandB(x: BrandB): void; +>consumeBrandB : Symbol(consumeBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 6, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 7, 31)) +>BrandB : Symbol(BrandB, Decl(uniqueNominalBrandsControlFlow.ts, 0, 29)) + +declare function consumeBrandAOrB(x: BrandA | BrandB): void; +>consumeBrandAOrB : Symbol(consumeBrandAOrB, Decl(uniqueNominalBrandsControlFlow.ts, 7, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 8, 34)) +>BrandA : Symbol(BrandA, Decl(uniqueNominalBrandsControlFlow.ts, 0, 0)) +>BrandB : Symbol(BrandB, Decl(uniqueNominalBrandsControlFlow.ts, 0, 29)) + +declare function consumeBrandAAndB(x: BrandA & BrandB): void; +>consumeBrandAAndB : Symbol(consumeBrandAAndB, Decl(uniqueNominalBrandsControlFlow.ts, 8, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 9, 35)) +>BrandA : Symbol(BrandA, Decl(uniqueNominalBrandsControlFlow.ts, 0, 0)) +>BrandB : Symbol(BrandB, Decl(uniqueNominalBrandsControlFlow.ts, 0, 29)) + +const x = {x: 12}; +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 11)) + +if (isBrandA(x)) { +>isBrandA : Symbol(isBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 1, 29)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + if (isBrandB(x)) { +>isBrandB : Symbol(isBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 3, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandA(x); +>consumeBrandA : Symbol(consumeBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 4, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandB(x); +>consumeBrandB : Symbol(consumeBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 6, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAOrB(x); +>consumeBrandAOrB : Symbol(consumeBrandAOrB, Decl(uniqueNominalBrandsControlFlow.ts, 7, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAAndB(x); +>consumeBrandAAndB : Symbol(consumeBrandAAndB, Decl(uniqueNominalBrandsControlFlow.ts, 8, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + } + else { + consumeBrandA(x); +>consumeBrandA : Symbol(consumeBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 4, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandB(x); // err +>consumeBrandB : Symbol(consumeBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 6, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAOrB(x); +>consumeBrandAOrB : Symbol(consumeBrandAOrB, Decl(uniqueNominalBrandsControlFlow.ts, 7, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAAndB(x); // err +>consumeBrandAAndB : Symbol(consumeBrandAAndB, Decl(uniqueNominalBrandsControlFlow.ts, 8, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + } +} +else { + if (isBrandB(x)) { +>isBrandB : Symbol(isBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 3, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandA(x); // err +>consumeBrandA : Symbol(consumeBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 4, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandB(x); +>consumeBrandB : Symbol(consumeBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 6, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAOrB(x); +>consumeBrandAOrB : Symbol(consumeBrandAOrB, Decl(uniqueNominalBrandsControlFlow.ts, 7, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAAndB(x); // err +>consumeBrandAAndB : Symbol(consumeBrandAAndB, Decl(uniqueNominalBrandsControlFlow.ts, 8, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + } + else { + consumeBrandA(x); // err +>consumeBrandA : Symbol(consumeBrandA, Decl(uniqueNominalBrandsControlFlow.ts, 4, 47)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandB(x); // err +>consumeBrandB : Symbol(consumeBrandB, Decl(uniqueNominalBrandsControlFlow.ts, 6, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAOrB(x); // err +>consumeBrandAOrB : Symbol(consumeBrandAOrB, Decl(uniqueNominalBrandsControlFlow.ts, 7, 48)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + + consumeBrandAAndB(x); // err +>consumeBrandAAndB : Symbol(consumeBrandAAndB, Decl(uniqueNominalBrandsControlFlow.ts, 8, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 11, 5)) + } +} + +type NormalizedPath = unique string; +>NormalizedPath : Symbol(NormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 39, 1)) + +type AbsolutePath = unique string; +>AbsolutePath : Symbol(AbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 41, 36)) + +type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; +>NormalizedAbsolutePath : Symbol(NormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 42, 34)) +>NormalizedPath : Symbol(NormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 39, 1)) +>AbsolutePath : Symbol(AbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 41, 36)) + +declare function isNormalizedPath(x: string): x is NormalizedPath; +>isNormalizedPath : Symbol(isNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 43, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 45, 34)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 45, 34)) +>NormalizedPath : Symbol(NormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 39, 1)) + +declare function isAbsolutePath(x: string): x is AbsolutePath; +>isAbsolutePath : Symbol(isAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 45, 66)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 46, 32)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 46, 32)) +>AbsolutePath : Symbol(AbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 41, 36)) + +declare function consumeNormalizedPath(x: NormalizedPath): void; +>consumeNormalizedPath : Symbol(consumeNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 46, 62)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 48, 39)) +>NormalizedPath : Symbol(NormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 39, 1)) + +declare function consumeAbsolutePath(x: AbsolutePath): void; +>consumeAbsolutePath : Symbol(consumeAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 48, 64)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 49, 37)) +>AbsolutePath : Symbol(AbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 41, 36)) + +declare function consumeNormalizedOrAbsolutePath(x: NormalizedPath | AbsolutePath): void; +>consumeNormalizedOrAbsolutePath : Symbol(consumeNormalizedOrAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 49, 60)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 50, 49)) +>NormalizedPath : Symbol(NormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 39, 1)) +>AbsolutePath : Symbol(AbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 41, 36)) + +declare function consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void; +>consumeNormalizedAbsolutePath : Symbol(consumeNormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 50, 89)) +>x : Symbol(x, Decl(uniqueNominalBrandsControlFlow.ts, 51, 47)) +>NormalizedAbsolutePath : Symbol(NormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 42, 34)) + +const p = "/a/b/c"; +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + +if (isNormalizedPath(p)) { +>isNormalizedPath : Symbol(isNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 43, 60)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + if (isAbsolutePath(p)) { +>isAbsolutePath : Symbol(isAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 45, 66)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedPath(p); +>consumeNormalizedPath : Symbol(consumeNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 46, 62)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeAbsolutePath(p); +>consumeAbsolutePath : Symbol(consumeAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 48, 64)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath : Symbol(consumeNormalizedOrAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 49, 60)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedAbsolutePath(p); +>consumeNormalizedAbsolutePath : Symbol(consumeNormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 50, 89)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + } + else { + consumeNormalizedPath(p); +>consumeNormalizedPath : Symbol(consumeNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 46, 62)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeAbsolutePath(p); // err +>consumeAbsolutePath : Symbol(consumeAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 48, 64)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath : Symbol(consumeNormalizedOrAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 49, 60)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath : Symbol(consumeNormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 50, 89)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + } +} +else { + if (isAbsolutePath(p)) { +>isAbsolutePath : Symbol(isAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 45, 66)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedPath(p); // err +>consumeNormalizedPath : Symbol(consumeNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 46, 62)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeAbsolutePath(p); +>consumeAbsolutePath : Symbol(consumeAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 48, 64)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath : Symbol(consumeNormalizedOrAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 49, 60)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath : Symbol(consumeNormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 50, 89)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + } + else { + consumeNormalizedPath(p); // err +>consumeNormalizedPath : Symbol(consumeNormalizedPath, Decl(uniqueNominalBrandsControlFlow.ts, 46, 62)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeAbsolutePath(p); // err +>consumeAbsolutePath : Symbol(consumeAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 48, 64)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedOrAbsolutePath(p); // err +>consumeNormalizedOrAbsolutePath : Symbol(consumeNormalizedOrAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 49, 60)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath : Symbol(consumeNormalizedAbsolutePath, Decl(uniqueNominalBrandsControlFlow.ts, 50, 89)) +>p : Symbol(p, Decl(uniqueNominalBrandsControlFlow.ts, 53, 5)) + } +} + diff --git a/tests/baselines/reference/uniqueNominalBrandsControlFlow.types b/tests/baselines/reference/uniqueNominalBrandsControlFlow.types new file mode 100644 index 0000000000000..f567186a451d6 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsControlFlow.types @@ -0,0 +1,276 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts === +type BrandA = unique unknown; +>BrandA : BrandA + +type BrandB = unique unknown; +>BrandB : BrandB + +declare function isBrandA(x: any): x is BrandA; +>isBrandA : (x: any) => x is BrandA +>x : any + +declare function isBrandB(x: any): x is BrandB; +>isBrandB : (x: any) => x is BrandB +>x : any + +declare function consumeBrandA(x: BrandA): void; +>consumeBrandA : (x: BrandA) => void +>x : BrandA + +declare function consumeBrandB(x: BrandB): void; +>consumeBrandB : (x: BrandB) => void +>x : BrandB + +declare function consumeBrandAOrB(x: BrandA | BrandB): void; +>consumeBrandAOrB : (x: BrandA | BrandB) => void +>x : BrandA | BrandB + +declare function consumeBrandAAndB(x: BrandA & BrandB): void; +>consumeBrandAAndB : (x: BrandA & BrandB) => void +>x : BrandA & BrandB + +const x = {x: 12}; +>x : { x: number; } +>{x: 12} : { x: number; } +>x : number +>12 : 12 + +if (isBrandA(x)) { +>isBrandA(x) : boolean +>isBrandA : (x: any) => x is BrandA +>x : { x: number; } + + if (isBrandB(x)) { +>isBrandB(x) : boolean +>isBrandB : (x: any) => x is BrandB +>x : { x: number; } & BrandA + + consumeBrandA(x); +>consumeBrandA(x) : void +>consumeBrandA : (x: BrandA) => void +>x : { x: number; } & BrandA & BrandB + + consumeBrandB(x); +>consumeBrandB(x) : void +>consumeBrandB : (x: BrandB) => void +>x : { x: number; } & BrandA & BrandB + + consumeBrandAOrB(x); +>consumeBrandAOrB(x) : void +>consumeBrandAOrB : (x: BrandA | BrandB) => void +>x : { x: number; } & BrandA & BrandB + + consumeBrandAAndB(x); +>consumeBrandAAndB(x) : void +>consumeBrandAAndB : (x: BrandA & BrandB) => void +>x : { x: number; } & BrandA & BrandB + } + else { + consumeBrandA(x); +>consumeBrandA(x) : void +>consumeBrandA : (x: BrandA) => void +>x : { x: number; } & BrandA + + consumeBrandB(x); // err +>consumeBrandB(x) : void +>consumeBrandB : (x: BrandB) => void +>x : { x: number; } & BrandA + + consumeBrandAOrB(x); +>consumeBrandAOrB(x) : void +>consumeBrandAOrB : (x: BrandA | BrandB) => void +>x : { x: number; } & BrandA + + consumeBrandAAndB(x); // err +>consumeBrandAAndB(x) : void +>consumeBrandAAndB : (x: BrandA & BrandB) => void +>x : { x: number; } & BrandA + } +} +else { + if (isBrandB(x)) { +>isBrandB(x) : boolean +>isBrandB : (x: any) => x is BrandB +>x : { x: number; } + + consumeBrandA(x); // err +>consumeBrandA(x) : void +>consumeBrandA : (x: BrandA) => void +>x : { x: number; } & BrandB + + consumeBrandB(x); +>consumeBrandB(x) : void +>consumeBrandB : (x: BrandB) => void +>x : { x: number; } & BrandB + + consumeBrandAOrB(x); +>consumeBrandAOrB(x) : void +>consumeBrandAOrB : (x: BrandA | BrandB) => void +>x : { x: number; } & BrandB + + consumeBrandAAndB(x); // err +>consumeBrandAAndB(x) : void +>consumeBrandAAndB : (x: BrandA & BrandB) => void +>x : { x: number; } & BrandB + } + else { + consumeBrandA(x); // err +>consumeBrandA(x) : void +>consumeBrandA : (x: BrandA) => void +>x : { x: number; } + + consumeBrandB(x); // err +>consumeBrandB(x) : void +>consumeBrandB : (x: BrandB) => void +>x : { x: number; } + + consumeBrandAOrB(x); // err +>consumeBrandAOrB(x) : void +>consumeBrandAOrB : (x: BrandA | BrandB) => void +>x : { x: number; } + + consumeBrandAAndB(x); // err +>consumeBrandAAndB(x) : void +>consumeBrandAAndB : (x: BrandA & BrandB) => void +>x : { x: number; } + } +} + +type NormalizedPath = unique string; +>NormalizedPath : NormalizedPath + +type AbsolutePath = unique string; +>AbsolutePath : AbsolutePath + +type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; +>NormalizedAbsolutePath : NormalizedAbsolutePath + +declare function isNormalizedPath(x: string): x is NormalizedPath; +>isNormalizedPath : (x: string) => x is NormalizedPath +>x : string + +declare function isAbsolutePath(x: string): x is AbsolutePath; +>isAbsolutePath : (x: string) => x is AbsolutePath +>x : string + +declare function consumeNormalizedPath(x: NormalizedPath): void; +>consumeNormalizedPath : (x: NormalizedPath) => void +>x : NormalizedPath + +declare function consumeAbsolutePath(x: AbsolutePath): void; +>consumeAbsolutePath : (x: AbsolutePath) => void +>x : AbsolutePath + +declare function consumeNormalizedOrAbsolutePath(x: NormalizedPath | AbsolutePath): void; +>consumeNormalizedOrAbsolutePath : (x: NormalizedPath | AbsolutePath) => void +>x : NormalizedPath | AbsolutePath + +declare function consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void; +>consumeNormalizedAbsolutePath : (x: NormalizedAbsolutePath) => void +>x : NormalizedAbsolutePath + +const p = "/a/b/c"; +>p : "/a/b/c" +>"/a/b/c" : "/a/b/c" + +if (isNormalizedPath(p)) { +>isNormalizedPath(p) : boolean +>isNormalizedPath : (x: string) => x is NormalizedPath +>p : "/a/b/c" + + if (isAbsolutePath(p)) { +>isAbsolutePath(p) : boolean +>isAbsolutePath : (x: string) => x is AbsolutePath +>p : "/a/b/c" & unique unknown + + consumeNormalizedPath(p); +>consumeNormalizedPath(p) : void +>consumeNormalizedPath : (x: NormalizedPath) => void +>p : "/a/b/c" & unique unknown & unique unknown + + consumeAbsolutePath(p); +>consumeAbsolutePath(p) : void +>consumeAbsolutePath : (x: AbsolutePath) => void +>p : "/a/b/c" & unique unknown & unique unknown + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath(p) : void +>consumeNormalizedOrAbsolutePath : (x: NormalizedPath | AbsolutePath) => void +>p : "/a/b/c" & unique unknown & unique unknown + + consumeNormalizedAbsolutePath(p); +>consumeNormalizedAbsolutePath(p) : void +>consumeNormalizedAbsolutePath : (x: NormalizedAbsolutePath) => void +>p : "/a/b/c" & unique unknown & unique unknown + } + else { + consumeNormalizedPath(p); +>consumeNormalizedPath(p) : void +>consumeNormalizedPath : (x: NormalizedPath) => void +>p : "/a/b/c" & unique unknown + + consumeAbsolutePath(p); // err +>consumeAbsolutePath(p) : void +>consumeAbsolutePath : (x: AbsolutePath) => void +>p : "/a/b/c" & unique unknown + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath(p) : void +>consumeNormalizedOrAbsolutePath : (x: NormalizedPath | AbsolutePath) => void +>p : "/a/b/c" & unique unknown + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath(p) : void +>consumeNormalizedAbsolutePath : (x: NormalizedAbsolutePath) => void +>p : "/a/b/c" & unique unknown + } +} +else { + if (isAbsolutePath(p)) { +>isAbsolutePath(p) : boolean +>isAbsolutePath : (x: string) => x is AbsolutePath +>p : "/a/b/c" + + consumeNormalizedPath(p); // err +>consumeNormalizedPath(p) : void +>consumeNormalizedPath : (x: NormalizedPath) => void +>p : "/a/b/c" & unique unknown + + consumeAbsolutePath(p); +>consumeAbsolutePath(p) : void +>consumeAbsolutePath : (x: AbsolutePath) => void +>p : "/a/b/c" & unique unknown + + consumeNormalizedOrAbsolutePath(p); +>consumeNormalizedOrAbsolutePath(p) : void +>consumeNormalizedOrAbsolutePath : (x: NormalizedPath | AbsolutePath) => void +>p : "/a/b/c" & unique unknown + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath(p) : void +>consumeNormalizedAbsolutePath : (x: NormalizedAbsolutePath) => void +>p : "/a/b/c" & unique unknown + } + else { + consumeNormalizedPath(p); // err +>consumeNormalizedPath(p) : void +>consumeNormalizedPath : (x: NormalizedPath) => void +>p : "/a/b/c" + + consumeAbsolutePath(p); // err +>consumeAbsolutePath(p) : void +>consumeAbsolutePath : (x: AbsolutePath) => void +>p : "/a/b/c" + + consumeNormalizedOrAbsolutePath(p); // err +>consumeNormalizedOrAbsolutePath(p) : void +>consumeNormalizedOrAbsolutePath : (x: NormalizedPath | AbsolutePath) => void +>p : "/a/b/c" + + consumeNormalizedAbsolutePath(p); // err +>consumeNormalizedAbsolutePath(p) : void +>consumeNormalizedAbsolutePath : (x: NormalizedAbsolutePath) => void +>p : "/a/b/c" + } +} + diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations1.js b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.js new file mode 100644 index 0000000000000..21111b232483f --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.js @@ -0,0 +1,131 @@ +//// [uniqueNominalBrandsDeclarations1.ts] +export type Downcased = unique string; +export type Analyzed = unique T; +export type Paired = { + x: unique number; + y: unique number; +}; + +export function downcase(x: string): Downcased { + return x.toLocaleLowerCase() as Downcased; +} + +export function downcaseLit(x: T): T & Downcased { + return x.toLocaleLowerCase() as T & Downcased; +} + +export function isDowncase(x: string): x is Downcased { + return null as any; +} + +export function analyze(x: T): Analyzed { + return x as Analyzed; +} + +export function isAnalyzed(x: T): x is Analyzed { + return Math.random() > 0.33 ? false : true; +} + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = "ok"; +export const b = downcase(a); +export const d = downcaseLit(b); + +if (isDowncase(d)) { + d; +} + +const e = {data: { value: "str" }}; +export const f = analyze(e); +if (isAnalyzed(e)) { + e; +} + +export const g = makePair(0, 0); +const h = {x: 0, y: 0}; +if (isPaired(h)) { + h; +} + + +//// [uniqueNominalBrandsDeclarations1.js] +"use strict"; +exports.__esModule = true; +function downcase(x) { + return x.toLocaleLowerCase(); +} +exports.downcase = downcase; +function downcaseLit(x) { + return x.toLocaleLowerCase(); +} +exports.downcaseLit = downcaseLit; +function isDowncase(x) { + return null; +} +exports.isDowncase = isDowncase; +function analyze(x) { + return x; +} +exports.analyze = analyze; +function isAnalyzed(x) { + return Math.random() > 0.33 ? false : true; +} +exports.isAnalyzed = isAnalyzed; +function isPaired(x) { + return true; +} +exports.isPaired = isPaired; +function makePair(x, y) { + return { x: x, y: y }; +} +exports.makePair = makePair; +var a = "ok"; +exports.b = downcase(a); +exports.d = downcaseLit(exports.b); +if (isDowncase(exports.d)) { + exports.d; +} +var e = { data: { value: "str" } }; +exports.f = analyze(e); +if (isAnalyzed(e)) { + e; +} +exports.g = makePair(0, 0); +var h = { x: 0, y: 0 }; +if (isPaired(h)) { + h; +} + + +//// [uniqueNominalBrandsDeclarations1.d.ts] +export declare type Downcased = unique string; +export declare type Analyzed = unique T; +export declare type Paired = { + x: unique number; + y: unique number; +}; +export declare function downcase(x: string): Downcased; +export declare function downcaseLit(x: T): T & Downcased; +export declare function isDowncase(x: string): x is Downcased; +export declare function analyze(x: T): Analyzed; +export declare function isAnalyzed(x: T): x is Analyzed; +export declare function isPaired(x: { + x: number; + y: number; +}): x is Paired; +export declare function makePair(x: number, y: number): Paired; +export declare const b: Downcased; +export declare const d: Downcased; +export declare const f: Analyzed<{ + data: { + value: string; + }; +}>; +export declare const g: Paired; diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations1.symbols b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.symbols new file mode 100644 index 0000000000000..20b994ce939ab --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.symbols @@ -0,0 +1,165 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts === +export type Downcased = unique string; +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) + +export type Analyzed = unique T; +>Analyzed : Symbol(Analyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 38)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 21)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 21)) + +export type Paired = { +>Paired : Symbol(Paired, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 35)) + + x: unique number; +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 2, 22)) + + y: unique number; +>y : Symbol(y, Decl(uniqueNominalBrandsDeclarations1.ts, 3, 21)) + +}; + +export function downcase(x: string): Downcased { +>downcase : Symbol(downcase, Decl(uniqueNominalBrandsDeclarations1.ts, 5, 2)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 7, 25)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) + + return x.toLocaleLowerCase() as Downcased; +>x.toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 7, 25)) +>toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) +} + +export function downcaseLit(x: T): T & Downcased { +>downcaseLit : Symbol(downcaseLit, Decl(uniqueNominalBrandsDeclarations1.ts, 9, 1)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 28)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 46)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 28)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 28)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) + + return x.toLocaleLowerCase() as T & Downcased; +>x.toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 46)) +>toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 11, 28)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) +} + +export function isDowncase(x: string): x is Downcased { +>isDowncase : Symbol(isDowncase, Decl(uniqueNominalBrandsDeclarations1.ts, 13, 1)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 15, 27)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 15, 27)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 0)) + + return null as any; +} + +export function analyze(x: T): Analyzed { +>analyze : Symbol(analyze, Decl(uniqueNominalBrandsDeclarations1.ts, 17, 1)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 24)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 27)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 24)) +>Analyzed : Symbol(Analyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 38)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 24)) + + return x as Analyzed; +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 27)) +>Analyzed : Symbol(Analyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 38)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 19, 24)) +} + +export function isAnalyzed(x: T): x is Analyzed { +>isAnalyzed : Symbol(isAnalyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 21, 1)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 23, 27)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 23, 30)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 23, 27)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 23, 30)) +>Analyzed : Symbol(Analyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 0, 38)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations1.ts, 23, 27)) + + return Math.random() > 0.33 ? false : true; +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +} + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : Symbol(isPaired, Decl(uniqueNominalBrandsDeclarations1.ts, 25, 1)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 27, 25)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 27, 29)) +>y : Symbol(y, Decl(uniqueNominalBrandsDeclarations1.ts, 27, 39)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 27, 25)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 35)) + + return true; +} + +export function makePair(x: number, y: number): Paired { +>makePair : Symbol(makePair, Decl(uniqueNominalBrandsDeclarations1.ts, 29, 1)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 31, 25)) +>y : Symbol(y, Decl(uniqueNominalBrandsDeclarations1.ts, 31, 35)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 35)) + + return {x, y} as Paired; +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 32, 12)) +>y : Symbol(y, Decl(uniqueNominalBrandsDeclarations1.ts, 32, 14)) +>Paired : Symbol(Paired, Decl(uniqueNominalBrandsDeclarations1.ts, 1, 35)) +} + +const a = "ok"; +>a : Symbol(a, Decl(uniqueNominalBrandsDeclarations1.ts, 35, 5)) + +export const b = downcase(a); +>b : Symbol(b, Decl(uniqueNominalBrandsDeclarations1.ts, 36, 12)) +>downcase : Symbol(downcase, Decl(uniqueNominalBrandsDeclarations1.ts, 5, 2)) +>a : Symbol(a, Decl(uniqueNominalBrandsDeclarations1.ts, 35, 5)) + +export const d = downcaseLit(b); +>d : Symbol(d, Decl(uniqueNominalBrandsDeclarations1.ts, 37, 12)) +>downcaseLit : Symbol(downcaseLit, Decl(uniqueNominalBrandsDeclarations1.ts, 9, 1)) +>b : Symbol(b, Decl(uniqueNominalBrandsDeclarations1.ts, 36, 12)) + +if (isDowncase(d)) { +>isDowncase : Symbol(isDowncase, Decl(uniqueNominalBrandsDeclarations1.ts, 13, 1)) +>d : Symbol(d, Decl(uniqueNominalBrandsDeclarations1.ts, 37, 12)) + + d; +>d : Symbol(d, Decl(uniqueNominalBrandsDeclarations1.ts, 37, 12)) +} + +const e = {data: { value: "str" }}; +>e : Symbol(e, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 5)) +>data : Symbol(data, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 11)) +>value : Symbol(value, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 18)) + +export const f = analyze(e); +>f : Symbol(f, Decl(uniqueNominalBrandsDeclarations1.ts, 44, 12)) +>analyze : Symbol(analyze, Decl(uniqueNominalBrandsDeclarations1.ts, 17, 1)) +>e : Symbol(e, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 5)) + +if (isAnalyzed(e)) { +>isAnalyzed : Symbol(isAnalyzed, Decl(uniqueNominalBrandsDeclarations1.ts, 21, 1)) +>e : Symbol(e, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 5)) + + e; +>e : Symbol(e, Decl(uniqueNominalBrandsDeclarations1.ts, 43, 5)) +} + +export const g = makePair(0, 0); +>g : Symbol(g, Decl(uniqueNominalBrandsDeclarations1.ts, 49, 12)) +>makePair : Symbol(makePair, Decl(uniqueNominalBrandsDeclarations1.ts, 29, 1)) + +const h = {x: 0, y: 0}; +>h : Symbol(h, Decl(uniqueNominalBrandsDeclarations1.ts, 50, 5)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations1.ts, 50, 11)) +>y : Symbol(y, Decl(uniqueNominalBrandsDeclarations1.ts, 50, 16)) + +if (isPaired(h)) { +>isPaired : Symbol(isPaired, Decl(uniqueNominalBrandsDeclarations1.ts, 25, 1)) +>h : Symbol(h, Decl(uniqueNominalBrandsDeclarations1.ts, 50, 5)) + + h; +>h : Symbol(h, Decl(uniqueNominalBrandsDeclarations1.ts, 50, 5)) +} + diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations1.types b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.types new file mode 100644 index 0000000000000..5664b840cb27b --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations1.types @@ -0,0 +1,170 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts === +export type Downcased = unique string; +>Downcased : Downcased + +export type Analyzed = unique T; +>Analyzed : Analyzed + +export type Paired = { +>Paired : Paired + + x: unique number; +>x : number & unique unknown + + y: unique number; +>y : number & unique unknown + +}; + +export function downcase(x: string): Downcased { +>downcase : (x: string) => Downcased +>x : string + + return x.toLocaleLowerCase() as Downcased; +>x.toLocaleLowerCase() as Downcased : Downcased +>x.toLocaleLowerCase() : string +>x.toLocaleLowerCase : (locales?: string | string[]) => string +>x : string +>toLocaleLowerCase : (locales?: string | string[]) => string +} + +export function downcaseLit(x: T): T & Downcased { +>downcaseLit : (x: T) => T & string & unique unknown +>x : T + + return x.toLocaleLowerCase() as T & Downcased; +>x.toLocaleLowerCase() as T & Downcased : T & string & unique unknown +>x.toLocaleLowerCase() : string +>x.toLocaleLowerCase : (locales?: string | string[]) => string +>x : T +>toLocaleLowerCase : (locales?: string | string[]) => string +} + +export function isDowncase(x: string): x is Downcased { +>isDowncase : (x: string) => x is Downcased +>x : string + + return null as any; +>null as any : any +>null : null +} + +export function analyze(x: T): Analyzed { +>analyze : (x: T) => Analyzed +>x : T + + return x as Analyzed; +>x as Analyzed : Analyzed +>x : T +} + +export function isAnalyzed(x: T): x is Analyzed { +>isAnalyzed : (x: T) => x is Analyzed +>x : T + + return Math.random() > 0.33 ? false : true; +>Math.random() > 0.33 ? false : true : boolean +>Math.random() > 0.33 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.33 : 0.33 +>false : false +>true : true +} + +export function isPaired(x: {x: number, y: number}): x is Paired { +>isPaired : (x: { x: number; y: number; }) => x is Paired +>x : { x: number; y: number; } +>x : number +>y : number + + return true; +>true : true +} + +export function makePair(x: number, y: number): Paired { +>makePair : (x: number, y: number) => Paired +>x : number +>y : number + + return {x, y} as Paired; +>{x, y} as Paired : Paired +>{x, y} : { x: number; y: number; } +>x : number +>y : number +} + +const a = "ok"; +>a : "ok" +>"ok" : "ok" + +export const b = downcase(a); +>b : Downcased +>downcase(a) : Downcased +>downcase : (x: string) => Downcased +>a : "ok" + +export const d = downcaseLit(b); +>d : Downcased +>downcaseLit(b) : Downcased +>downcaseLit : (x: T) => T & string & unique unknown +>b : Downcased + +if (isDowncase(d)) { +>isDowncase(d) : boolean +>isDowncase : (x: string) => x is Downcased +>d : Downcased + + d; +>d : Downcased +} + +const e = {data: { value: "str" }}; +>e : { data: { value: string; }; } +>{data: { value: "str" }} : { data: { value: string; }; } +>data : { value: string; } +>{ value: "str" } : { value: string; } +>value : string +>"str" : "str" + +export const f = analyze(e); +>f : Analyzed<{ data: { value: string; }; }> +>analyze(e) : Analyzed<{ data: { value: string; }; }> +>analyze : (x: T) => Analyzed +>e : { data: { value: string; }; } + +if (isAnalyzed(e)) { +>isAnalyzed(e) : boolean +>isAnalyzed : (x: T) => x is Analyzed +>e : { data: { value: string; }; } + + e; +>e : Analyzed<{ data: { value: string; }; }> +} + +export const g = makePair(0, 0); +>g : Paired +>makePair(0, 0) : Paired +>makePair : (x: number, y: number) => Paired +>0 : 0 +>0 : 0 + +const h = {x: 0, y: 0}; +>h : { x: number; y: number; } +>{x: 0, y: 0} : { x: number; y: number; } +>x : number +>0 : 0 +>y : number +>0 : 0 + +if (isPaired(h)) { +>isPaired(h) : boolean +>isPaired : (x: { x: number; y: number; }) => x is Paired +>h : { x: number; y: number; } + + h; +>h : Paired +} + diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations2.errors.txt b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.errors.txt new file mode 100644 index 0000000000000..fc187d9f899c5 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.errors.txt @@ -0,0 +1,14 @@ +tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts(7,14): error TS4025: Exported variable 'c' has or is using private name '__brand'. + + +==== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts (1 errors) ==== + export type Downcased = unique string; + + export function downcaseLit(x: T): T & Downcased { + return x.toLocaleLowerCase() as T & Downcased; + } + const a = "ok"; + export const c = downcaseLit(a); // visibility error + ~ +!!! error TS4025: Exported variable 'c' has or is using private name '__brand'. + \ No newline at end of file diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations2.js b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.js new file mode 100644 index 0000000000000..4a4c6fd05abf7 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.js @@ -0,0 +1,19 @@ +//// [uniqueNominalBrandsDeclarations2.ts] +export type Downcased = unique string; + +export function downcaseLit(x: T): T & Downcased { + return x.toLocaleLowerCase() as T & Downcased; +} +const a = "ok"; +export const c = downcaseLit(a); // visibility error + + +//// [uniqueNominalBrandsDeclarations2.js] +"use strict"; +exports.__esModule = true; +function downcaseLit(x) { + return x.toLocaleLowerCase(); +} +exports.downcaseLit = downcaseLit; +var a = "ok"; +exports.c = downcaseLit(a); // visibility error diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations2.symbols b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.symbols new file mode 100644 index 0000000000000..bb841ed8dba73 --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts === +export type Downcased = unique string; +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations2.ts, 0, 0)) + +export function downcaseLit(x: T): T & Downcased { +>downcaseLit : Symbol(downcaseLit, Decl(uniqueNominalBrandsDeclarations2.ts, 0, 38)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 28)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 46)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 28)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 28)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations2.ts, 0, 0)) + + return x.toLocaleLowerCase() as T & Downcased; +>x.toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 46)) +>toLocaleLowerCase : Symbol(String.toLocaleLowerCase, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(uniqueNominalBrandsDeclarations2.ts, 2, 28)) +>Downcased : Symbol(Downcased, Decl(uniqueNominalBrandsDeclarations2.ts, 0, 0)) +} +const a = "ok"; +>a : Symbol(a, Decl(uniqueNominalBrandsDeclarations2.ts, 5, 5)) + +export const c = downcaseLit(a); // visibility error +>c : Symbol(c, Decl(uniqueNominalBrandsDeclarations2.ts, 6, 12)) +>downcaseLit : Symbol(downcaseLit, Decl(uniqueNominalBrandsDeclarations2.ts, 0, 38)) +>a : Symbol(a, Decl(uniqueNominalBrandsDeclarations2.ts, 5, 5)) + diff --git a/tests/baselines/reference/uniqueNominalBrandsDeclarations2.types b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.types new file mode 100644 index 0000000000000..1ce6afdfe93fc --- /dev/null +++ b/tests/baselines/reference/uniqueNominalBrandsDeclarations2.types @@ -0,0 +1,25 @@ +=== tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts === +export type Downcased = unique string; +>Downcased : Downcased + +export function downcaseLit(x: T): T & Downcased { +>downcaseLit : (x: T) => T & string & unique unknown +>x : T + + return x.toLocaleLowerCase() as T & Downcased; +>x.toLocaleLowerCase() as T & Downcased : T & string & unique unknown +>x.toLocaleLowerCase() : string +>x.toLocaleLowerCase : (locales?: string | string[]) => string +>x : T +>toLocaleLowerCase : (locales?: string | string[]) => string +} +const a = "ok"; +>a : "ok" +>"ok" : "ok" + +export const c = downcaseLit(a); // visibility error +>c : "ok" & unique unknown +>downcaseLit(a) : "ok" & unique unknown +>downcaseLit : (x: T) => T & string & unique unknown +>a : "ok" + diff --git a/tests/baselines/reference/uniqueSymbolsErrors.errors.txt b/tests/baselines/reference/uniqueSymbolsErrors.errors.txt index 3feba130bd60d..d6dfbbfbc290a 100644 --- a/tests/baselines/reference/uniqueSymbolsErrors.errors.txt +++ b/tests/baselines/reference/uniqueSymbolsErrors.errors.txt @@ -1,4 +1,3 @@ -tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(2,41): error TS1005: 'symbol' expected. tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(3,19): error TS1333: 'unique symbol' types may not be used on a variable declaration with a binding name. tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(4,13): error TS1332: A variable whose type is a 'unique symbol' type must be 'const'. tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(5,13): error TS1332: A variable whose type is a 'unique symbol' type must be 'const'. @@ -61,11 +60,9 @@ tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(83,52): error tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts(87,7): error TS2322: Type 'unique symbol' is not assignable to type 'string'. -==== tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts (61 errors) ==== +==== tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts (60 errors) ==== // declarations declare const invalidUniqueType: unique number; - ~~~~~~ -!!! error TS1005: 'symbol' expected. declare const {}: unique symbol; ~~~~~~~~~~~~~ !!! error TS1333: 'unique symbol' types may not be used on a variable declaration with a binding name. diff --git a/tests/baselines/reference/uniqueSymbolsErrors.types b/tests/baselines/reference/uniqueSymbolsErrors.types index 64a1f33743052..34e5fb4ce33d5 100644 --- a/tests/baselines/reference/uniqueSymbolsErrors.types +++ b/tests/baselines/reference/uniqueSymbolsErrors.types @@ -1,7 +1,7 @@ === tests/cases/conformance/types/uniqueSymbol/uniqueSymbolsErrors.ts === // declarations declare const invalidUniqueType: unique number; ->invalidUniqueType : any +>invalidUniqueType : number & unique unknown declare const {}: unique symbol; declare let invalidLetType: unique symbol; diff --git a/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts new file mode 100644 index 0000000000000..baa79919cd5ab --- /dev/null +++ b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands1.ts @@ -0,0 +1,28 @@ +export type Paired = { + x: unique number; + y: unique number; +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = makePair(0, 0); +const b = {x: 0, y: 0}; + +if (Math.random() > 0.3) { + b.x = a.x; + b.y = a.y; +} + +if (isPaired(b)) { + b.x = a.x; + b.y = a.y; + a.x = b.x; + a.y = b.y; +} diff --git a/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts new file mode 100644 index 0000000000000..b9f3ace8096dc --- /dev/null +++ b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrands2.ts @@ -0,0 +1,25 @@ +export type Paired = { + x: unique number; + y: unique number; +}; + + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = makePair(0, 0); +const b = {x: 0, y: 0}; + +a.x = a.y; // err +a.y = a.x; // err + +a.x = b.y; // err +a.y = b.y; // err + +a.x = b.x; // err +a.y = b.x; // err \ No newline at end of file diff --git a/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts new file mode 100644 index 0000000000000..21eecc53b52a2 --- /dev/null +++ b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsControlFlow.ts @@ -0,0 +1,82 @@ +type BrandA = unique unknown; +type BrandB = unique unknown; + +declare function isBrandA(x: any): x is BrandA; +declare function isBrandB(x: any): x is BrandB; + +declare function consumeBrandA(x: BrandA): void; +declare function consumeBrandB(x: BrandB): void; +declare function consumeBrandAOrB(x: BrandA | BrandB): void; +declare function consumeBrandAAndB(x: BrandA & BrandB): void; + +const x = {x: 12}; +if (isBrandA(x)) { + if (isBrandB(x)) { + consumeBrandA(x); + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); + } + else { + consumeBrandA(x); + consumeBrandB(x); // err + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } +} +else { + if (isBrandB(x)) { + consumeBrandA(x); // err + consumeBrandB(x); + consumeBrandAOrB(x); + consumeBrandAAndB(x); // err + } + else { + consumeBrandA(x); // err + consumeBrandB(x); // err + consumeBrandAOrB(x); // err + consumeBrandAAndB(x); // err + } +} + +type NormalizedPath = unique string; +type AbsolutePath = unique string; +type NormalizedAbsolutePath = NormalizedPath & AbsolutePath; + +declare function isNormalizedPath(x: string): x is NormalizedPath; +declare function isAbsolutePath(x: string): x is AbsolutePath; + +declare function consumeNormalizedPath(x: NormalizedPath): void; +declare function consumeAbsolutePath(x: AbsolutePath): void; +declare function consumeNormalizedOrAbsolutePath(x: NormalizedPath | AbsolutePath): void; +declare function consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void; + +const p = "/a/b/c"; +if (isNormalizedPath(p)) { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); + } + else { + consumeNormalizedPath(p); + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } +} +else { + if (isAbsolutePath(p)) { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); + consumeNormalizedOrAbsolutePath(p); + consumeNormalizedAbsolutePath(p); // err + } + else { + consumeNormalizedPath(p); // err + consumeAbsolutePath(p); // err + consumeNormalizedOrAbsolutePath(p); // err + consumeNormalizedAbsolutePath(p); // err + } +} diff --git a/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts new file mode 100644 index 0000000000000..56c73bea55462 --- /dev/null +++ b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations1.ts @@ -0,0 +1,55 @@ +// @declaration: true +export type Downcased = unique string; +export type Analyzed = unique T; +export type Paired = { + x: unique number; + y: unique number; +}; + +export function downcase(x: string): Downcased { + return x.toLocaleLowerCase() as Downcased; +} + +export function downcaseLit(x: T): T & Downcased { + return x.toLocaleLowerCase() as T & Downcased; +} + +export function isDowncase(x: string): x is Downcased { + return null as any; +} + +export function analyze(x: T): Analyzed { + return x as Analyzed; +} + +export function isAnalyzed(x: T): x is Analyzed { + return Math.random() > 0.33 ? false : true; +} + +export function isPaired(x: {x: number, y: number}): x is Paired { + return true; +} + +export function makePair(x: number, y: number): Paired { + return {x, y} as Paired; +} + +const a = "ok"; +export const b = downcase(a); +export const d = downcaseLit(b); + +if (isDowncase(d)) { + d; +} + +const e = {data: { value: "str" }}; +export const f = analyze(e); +if (isAnalyzed(e)) { + e; +} + +export const g = makePair(0, 0); +const h = {x: 0, y: 0}; +if (isPaired(h)) { + h; +} diff --git a/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts new file mode 100644 index 0000000000000..7f25c0837c2f4 --- /dev/null +++ b/tests/cases/conformance/types/nominalBrands/uniqueNominalBrandsDeclarations2.ts @@ -0,0 +1,8 @@ +// @declaration: true +export type Downcased = unique string; + +export function downcaseLit(x: T): T & Downcased { + return x.toLocaleLowerCase() as T & Downcased; +} +const a = "ok"; +export const c = downcaseLit(a); // visibility error diff --git a/tests/cases/user/prettier/prettier b/tests/cases/user/prettier/prettier index 1e471a007968b..2314640485001 160000 --- a/tests/cases/user/prettier/prettier +++ b/tests/cases/user/prettier/prettier @@ -1 +1 @@ -Subproject commit 1e471a007968b7490563b91ed6909ae6046f3fe8 +Subproject commit 23146404850011972f695fb6bc2b8113c3cffbfc