mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Initial support for 'match' type
This commit is contained in:
@@ -3367,6 +3367,10 @@ namespace ts {
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
case SyntaxKind.MappedType:
|
||||
case SyntaxKind.MatchType:
|
||||
case SyntaxKind.MatchTypeBlock:
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
case SyntaxKind.LiteralType:
|
||||
case SyntaxKind.NamespaceExportDeclaration:
|
||||
// Types and signatures are TypeScript syntax, and exclude all other facts.
|
||||
|
||||
@@ -2534,6 +2534,17 @@ namespace ts {
|
||||
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
|
||||
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
|
||||
}
|
||||
if (type.flags & TypeFlags.Match) {
|
||||
const typeArgument = typeToTypeNodeHelper((<MatchType>type).typeArgument, context);
|
||||
const clauses: MatchTypeMatchOrElseClause[] = map((<MatchType>type).clauses, clause => {
|
||||
const matchType = typeToTypeNodeHelper(clause.matchType, context);
|
||||
const resultType = typeToTypeNodeHelper(clause.resultType, context);
|
||||
return createMatchTypeMatchClause(matchType, resultType);
|
||||
});
|
||||
const elseType = (<MatchType>type).elseType;
|
||||
if (elseType) clauses.push(createMatchTypeElseClause(typeToTypeNodeHelper(elseType, context)));
|
||||
return createMatchTypeNode(typeArgument, createMatchTypeBlock(clauses));
|
||||
}
|
||||
|
||||
Debug.fail("Should be unreachable.");
|
||||
|
||||
@@ -3303,6 +3314,9 @@ namespace ts {
|
||||
writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Match) {
|
||||
writeMatchType(<MatchType>type);
|
||||
}
|
||||
else {
|
||||
// Should never get here
|
||||
// { ... }
|
||||
@@ -3314,6 +3328,35 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function writeMatchType(type: MatchType) {
|
||||
writeType((<MatchType>type).typeArgument, TypeFormatFlags.None);
|
||||
writeSpace(writer);
|
||||
writer.writeKeyword("match");
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writer.writeLine();
|
||||
writer.increaseIndent();
|
||||
for (const clause of (<MatchType>type).clauses) {
|
||||
writeType(clause.matchType, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(clause.resultType, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
const elseType = (<MatchType>type).elseType;
|
||||
if (elseType) {
|
||||
writer.writeKeyword("else");
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(elseType, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
writer.decreaseIndent();
|
||||
writer.writeLine();
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
|
||||
function writeTypeList(types: Type[], delimiter: SyntaxKind) {
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
@@ -7730,6 +7773,65 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function isGenericMatchTypeClause(clause: MatchTypeClause): boolean {
|
||||
return isGenericObjectType(clause.matchType);
|
||||
}
|
||||
|
||||
function getMatchTypeConstituents(type: MatchType) {
|
||||
if (type.clauses.length === 0) return type.elseType || neverType;
|
||||
const constituents: Type[] = [];
|
||||
for (const clause of type.clauses) {
|
||||
constituents.push(clause.resultType);
|
||||
}
|
||||
if (type.elseType) {
|
||||
constituents.push(type.elseType);
|
||||
}
|
||||
return getUnionType(constituents);
|
||||
}
|
||||
|
||||
function getMatchType(typeArgument: Type, clauses: ReadonlyArray<MatchTypeClause>, elseType: Type | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]) {
|
||||
if (clauses.length > 0 && (isGenericObjectType(typeArgument) || forEach(clauses, isGenericMatchTypeClause))) {
|
||||
if (clauses.length > 0) {
|
||||
const type = <MatchType>createType(TypeFlags.Match);
|
||||
type.typeArgument = typeArgument;
|
||||
type.clauses = clauses;
|
||||
type.elseType = elseType;
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
type.aliasTypeArguments = aliasTypeArguments;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
for (const clause of clauses) {
|
||||
if (isTypeAssignableTo(typeArgument, clause.matchType)) {
|
||||
return clause.resultType;
|
||||
}
|
||||
}
|
||||
|
||||
return elseType || neverType;
|
||||
}
|
||||
|
||||
function getTypeFromMatchTypeNode(node: MatchTypeNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
const typeArgument = getTypeFromTypeNode(node.typeArgument);
|
||||
const clauses: MatchTypeClause[] = [];
|
||||
let elseType: Type | undefined;
|
||||
for (const clause of node.matchBlock.clauses) {
|
||||
if (clause.kind === SyntaxKind.MatchTypeElseClause) {
|
||||
if (!elseType) elseType = getTypeFromTypeNode(clause.resultType);
|
||||
}
|
||||
else {
|
||||
const matchType = getTypeFromTypeNode(clause.matchType);
|
||||
const resultType = getTypeFromTypeNode(clause.resultType);
|
||||
clauses.push({ matchType, resultType });
|
||||
}
|
||||
}
|
||||
links.resolvedType = getMatchType(typeArgument, clauses, elseType, getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
@@ -7992,6 +8094,8 @@ namespace ts {
|
||||
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.MappedType:
|
||||
return getTypeFromMappedTypeNode(<MappedTypeNode>node);
|
||||
case SyntaxKind.MatchType:
|
||||
return getTypeFromMatchTypeNode(<MatchTypeNode>node);
|
||||
// This function assumes that an identifier or qualified name is a type expression
|
||||
// Callers should first ensure this by calling isTypeNode
|
||||
case SyntaxKind.Identifier:
|
||||
@@ -8005,6 +8109,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function instantiateList<T>(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[];
|
||||
function instantiateList<T>(items: ReadonlyArray<T>, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): ReadonlyArray<T>;
|
||||
function instantiateList<T>(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] {
|
||||
if (items && items.length) {
|
||||
const result: T[] = [];
|
||||
@@ -8356,9 +8462,23 @@ namespace ts {
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Match) {
|
||||
return getMatchType(
|
||||
instantiateType((<MatchType>type).typeArgument, mapper),
|
||||
instantiateList((<MatchType>type).clauses, mapper, instantiateMatchTypeClause),
|
||||
instantiateType((<MatchType>type).elseType, mapper),
|
||||
type.aliasSymbol,
|
||||
instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function instantiateMatchTypeClause(clause: MatchTypeClause, mapper: TypeMapper) {
|
||||
const matchType = instantiateType(clause.matchType, mapper);
|
||||
const resultType = instantiateType(clause.resultType, mapper);
|
||||
return { matchType, resultType };
|
||||
}
|
||||
|
||||
function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper): IndexInfo {
|
||||
return info && createIndexInfo(instantiateType(info.type, mapper), info.isReadonly, info.declaration);
|
||||
}
|
||||
@@ -9362,6 +9482,14 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (source.flags & TypeFlags.Match) {
|
||||
if (target.flags & TypeFlags.Union) {
|
||||
if (result = isRelatedTo(getMatchTypeConstituents(<MatchType>source), target, reportErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
|
||||
// We have type references to same target type, see if relationship holds for all type arguments
|
||||
if (result = typeArgumentsRelatedTo(<TypeReference>source, <TypeReference>target, reportErrors)) {
|
||||
@@ -18879,6 +19007,34 @@ namespace ts {
|
||||
checkTypeAssignableTo(constraintType, stringType, node.typeParameter.constraint);
|
||||
}
|
||||
|
||||
function checkMatchType(node: MatchTypeNode) {
|
||||
checkSourceElement(node.typeArgument);
|
||||
|
||||
let firstElseClause: MatchTypeElseClause;
|
||||
let hasDuplicateElseClause = false;
|
||||
for (const clause of node.matchBlock.clauses) {
|
||||
if (clause.kind === SyntaxKind.MatchTypeElseClause) {
|
||||
if (hasDuplicateElseClause) continue;
|
||||
if (!firstElseClause) {
|
||||
firstElseClause = clause;
|
||||
}
|
||||
else {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
const start = skipTrivia(sourceFile.text, clause.pos);
|
||||
const end = clause.resultType ? clause.resultType.pos : clause.end;
|
||||
grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.An_else_clause_cannot_appear_more_than_once_in_a_match_type);
|
||||
hasDuplicateElseClause = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkSourceElement(clause.matchType);
|
||||
}
|
||||
|
||||
checkSourceElement(clause.resultType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isPrivateWithinAmbient(node: Node): boolean {
|
||||
return hasModifier(node, ModifierFlags.Private) && isInAmbientContext(node);
|
||||
}
|
||||
@@ -22412,6 +22568,8 @@ namespace ts {
|
||||
return checkIndexedAccessType(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.MappedType:
|
||||
return checkMappedType(<MappedTypeNode>node);
|
||||
case SyntaxKind.MatchType:
|
||||
return checkMatchType(<MatchTypeNode>node);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return checkFunctionDeclaration(<FunctionDeclaration>node);
|
||||
case SyntaxKind.Block:
|
||||
|
||||
@@ -447,6 +447,8 @@ namespace ts {
|
||||
return emitIndexedAccessType(<IndexedAccessTypeNode>type);
|
||||
case SyntaxKind.MappedType:
|
||||
return emitMappedType(<MappedTypeNode>type);
|
||||
case SyntaxKind.MatchType:
|
||||
return emitMatchType(<MatchTypeNode>type);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return emitSignatureDeclarationWithJsDocComments(<FunctionOrConstructorTypeNode>type);
|
||||
@@ -579,6 +581,18 @@ namespace ts {
|
||||
enclosingDeclaration = prevEnclosingDeclaration;
|
||||
}
|
||||
|
||||
function emitMatchType(node: MatchTypeNode) {
|
||||
emitType(node.typeArgument);
|
||||
write(" match {");
|
||||
if (node.matchBlock.clauses.length) {
|
||||
increaseIndent();
|
||||
emitCommaList(node.matchBlock.clauses, emitNode);
|
||||
writeLine();
|
||||
decreaseIndent();
|
||||
}
|
||||
write("}");
|
||||
}
|
||||
|
||||
function emitTypeLiteral(type: TypeLiteralNode) {
|
||||
write("{");
|
||||
if (type.members.length) {
|
||||
@@ -1808,6 +1822,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitMatchTypeMatchClause(node: MatchTypeMatchClause) {
|
||||
writeLine();
|
||||
emitType(node.matchType);
|
||||
write(": ");
|
||||
emitType(node.resultType);
|
||||
}
|
||||
|
||||
function emitMatchTypeElseClause(node: MatchTypeElseClause) {
|
||||
writeLine();
|
||||
write("else: ");
|
||||
emitType(node.resultType);
|
||||
}
|
||||
|
||||
function emitNode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
@@ -1841,6 +1868,10 @@ namespace ts {
|
||||
return emitPropertyDeclaration(<PropertyDeclaration>node);
|
||||
case SyntaxKind.EnumMember:
|
||||
return emitEnumMemberDeclaration(<EnumMember>node);
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
return emitMatchTypeMatchClause(<MatchTypeMatchClause>node);
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
return emitMatchTypeElseClause(<MatchTypeElseClause>node);
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return emitExportAssignment(<ExportAssignment>node);
|
||||
case SyntaxKind.SourceFile:
|
||||
|
||||
@@ -907,6 +907,14 @@
|
||||
"category": "Error",
|
||||
"code": 1328
|
||||
},
|
||||
"Type or 'else' expected.": {
|
||||
"category": "Error",
|
||||
"code": 1329
|
||||
},
|
||||
"An 'else' clause cannot appear more than once in a 'match' type.": {
|
||||
"category": "Error",
|
||||
"code": 1330
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -557,6 +557,15 @@ namespace ts {
|
||||
return emitIndexedAccessType(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.MappedType:
|
||||
return emitMappedType(<MappedTypeNode>node);
|
||||
case SyntaxKind.MatchType:
|
||||
return emitMatchType(<MatchTypeNode>node);
|
||||
case SyntaxKind.MatchTypeBlock:
|
||||
return emitMatchTypeBlock(<MatchTypeBlock>node);
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
return emitMatchTypeMatchClause(<MatchTypeMatchClause>node);
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
return emitMatchTypeElseClause(<MatchTypeElseClause>node);
|
||||
|
||||
case SyntaxKind.LiteralType:
|
||||
return emitLiteralType(<LiteralTypeNode>node);
|
||||
|
||||
@@ -1114,6 +1123,30 @@ namespace ts {
|
||||
write("}");
|
||||
}
|
||||
|
||||
function emitMatchType(node: MatchTypeNode) {
|
||||
emit(node.typeArgument);
|
||||
writeToken(SyntaxKind.MatchKeyword, node.typeArgument.end);
|
||||
write(" ");
|
||||
emit(node.matchBlock);
|
||||
}
|
||||
|
||||
function emitMatchTypeBlock(node: MatchTypeBlock) {
|
||||
writeToken(SyntaxKind.OpenBraceToken, node.pos);
|
||||
emitList(node, node.clauses, ListFormat.MatchTypeBlockClauses);
|
||||
writeToken(SyntaxKind.CloseBraceToken, node.clauses.end);
|
||||
}
|
||||
|
||||
function emitMatchTypeMatchClause(node: MatchTypeMatchClause) {
|
||||
emit(node.matchType);
|
||||
write(": ");
|
||||
emit(node.resultType);
|
||||
}
|
||||
|
||||
function emitMatchTypeElseClause(node: MatchTypeElseClause) {
|
||||
write("else: ");
|
||||
emit(node.resultType);
|
||||
}
|
||||
|
||||
function emitLiteralType(node: LiteralTypeNode) {
|
||||
emitExpression(node.literal);
|
||||
}
|
||||
@@ -3134,6 +3167,7 @@ namespace ts {
|
||||
InterfaceMembers = Indented | MultiLine,
|
||||
EnumMembers = CommaDelimited | Indented | MultiLine,
|
||||
CaseBlockClauses = Indented | MultiLine,
|
||||
MatchTypeBlockClauses = Indented | MultiLine | CommaDelimited | AllowTrailingComma,
|
||||
NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces,
|
||||
JsxElementChildren = SingleLine | NoInterveningComments,
|
||||
JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
|
||||
|
||||
@@ -773,6 +773,58 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMatchTypeNode(typeArgument: TypeNode, matchBlock: MatchTypeBlock) {
|
||||
const node = createSynthesizedNode(SyntaxKind.MatchType) as MatchTypeNode;
|
||||
node.typeArgument = typeArgument;
|
||||
node.matchBlock = matchBlock;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateMatchTypeNode(node: MatchTypeNode, typeArgument: TypeNode, matchBlock: MatchTypeBlock) {
|
||||
return node.typeArgument !== typeArgument
|
||||
|| node.matchBlock !== matchBlock
|
||||
? updateNode(createMatchTypeNode(typeArgument, matchBlock), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMatchTypeBlock(clauses: ReadonlyArray<MatchTypeMatchOrElseClause>) {
|
||||
const node = createSynthesizedNode(SyntaxKind.MatchTypeBlock) as MatchTypeBlock;
|
||||
node.clauses = createNodeArray(clauses);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateMatchTypeBlock(node: MatchTypeBlock, clauses: ReadonlyArray<MatchTypeMatchOrElseClause>) {
|
||||
return node.clauses !== clauses
|
||||
? updateNode(createMatchTypeBlock(clauses), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMatchTypeMatchClause(matchType: TypeNode, resultType: TypeNode) {
|
||||
const node = createSynthesizedNode(SyntaxKind.MatchTypeMatchClause) as MatchTypeMatchClause;
|
||||
node.matchType = matchType;
|
||||
node.resultType = resultType;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateMatchTypeMatchClause(node: MatchTypeMatchClause, matchType: TypeNode, resultType: TypeNode) {
|
||||
return node.matchType !== matchType
|
||||
|| node.resultType !== resultType
|
||||
? updateNode(createMatchTypeMatchClause(matchType, resultType), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMatchTypeElseClause(resultType: TypeNode) {
|
||||
const node = createSynthesizedNode(SyntaxKind.MatchTypeElseClause) as MatchTypeElseClause;
|
||||
node.resultType = resultType;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateMatchTypeElseClause(node: MatchTypeElseClause, resultType: TypeNode) {
|
||||
return node.resultType !== resultType
|
||||
? updateNode(createMatchTypeElseClause(resultType), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createLiteralTypeNode(literal: Expression) {
|
||||
const node = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
|
||||
node.literal = literal;
|
||||
|
||||
@@ -155,6 +155,16 @@ namespace ts {
|
||||
visitNode(cbNode, (<MappedTypeNode>node).typeParameter) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).questionToken) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).type);
|
||||
case SyntaxKind.MatchType:
|
||||
return visitNode(cbNode, (<MatchTypeNode>node).typeArgument) ||
|
||||
visitNode(cbNode, (<MatchTypeNode>node).matchBlock);
|
||||
case SyntaxKind.MatchTypeBlock:
|
||||
return visitNodes(cbNode, cbNodes, (<MatchTypeBlock>node).clauses);
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
return visitNode(cbNode, (<MatchTypeMatchClause>node).matchType) ||
|
||||
visitNode(cbNode, (<MatchTypeMatchClause>node).resultType);
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
return visitNode(cbNode, (<MatchTypeElseClause>node).resultType);
|
||||
case SyntaxKind.LiteralType:
|
||||
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
@@ -1332,6 +1342,8 @@ namespace ts {
|
||||
return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement();
|
||||
case ParsingContext.SwitchClauses:
|
||||
return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
|
||||
case ParsingContext.MatchTypeClauses:
|
||||
return token() === SyntaxKind.ElseKeyword || token() === SyntaxKind.CommaToken || isStartOfType();
|
||||
case ParsingContext.TypeMembers:
|
||||
return lookAhead(isTypeMemberStart);
|
||||
case ParsingContext.ClassMembers:
|
||||
@@ -1446,6 +1458,7 @@ namespace ts {
|
||||
switch (kind) {
|
||||
case ParsingContext.BlockStatements:
|
||||
case ParsingContext.SwitchClauses:
|
||||
case ParsingContext.MatchTypeClauses:
|
||||
case ParsingContext.TypeMembers:
|
||||
case ParsingContext.ClassMembers:
|
||||
case ParsingContext.EnumMembers:
|
||||
@@ -1631,6 +1644,9 @@ namespace ts {
|
||||
case ParsingContext.SwitchClauses:
|
||||
return isReusableSwitchClause(node);
|
||||
|
||||
case ParsingContext.MatchTypeClauses:
|
||||
return isReusableMatchTypeClause(node);
|
||||
|
||||
case ParsingContext.SourceElements:
|
||||
case ParsingContext.BlockStatements:
|
||||
case ParsingContext.SwitchClauseStatements:
|
||||
@@ -1740,6 +1756,17 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isReusableMatchTypeClause(node: Node) {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isReusableStatement(node: Node) {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
@@ -1848,6 +1875,7 @@ namespace ts {
|
||||
case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected;
|
||||
case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected;
|
||||
case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected;
|
||||
case ParsingContext.MatchTypeClauses: return Diagnostics.Type_or_else_expected;
|
||||
case ParsingContext.RestProperties: // fallthrough
|
||||
case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected;
|
||||
case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected;
|
||||
@@ -2585,6 +2613,45 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseMatchTypeMatchClause() {
|
||||
const node = <MatchTypeMatchClause>createNode(SyntaxKind.MatchTypeMatchClause);
|
||||
node.matchType = parseType();
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.resultType = parseType();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseMatchTypeElseClause() {
|
||||
const node = <MatchTypeElseClause>createNode(SyntaxKind.MatchTypeElseClause);
|
||||
parseExpected(SyntaxKind.ElseKeyword);
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.resultType = parseType();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseMatchTypeCaseOrElseClause(): MatchTypeMatchOrElseClause {
|
||||
return token() === SyntaxKind.ElseKeyword ? parseMatchTypeElseClause() : parseMatchTypeMatchClause();
|
||||
}
|
||||
|
||||
function parseMatchTypeRest(type: TypeNode) {
|
||||
while (true) {
|
||||
type = parseArrayTypeRest(type);
|
||||
if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.MatchKeyword) {
|
||||
const node = <MatchTypeNode>createNode(SyntaxKind.MatchType, type.pos);
|
||||
node.typeArgument = type;
|
||||
parseExpected(SyntaxKind.MatchKeyword);
|
||||
const matchBlock = <MatchTypeBlock>createNode(SyntaxKind.MatchTypeBlock);
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
matchBlock.clauses = parseDelimitedList(ParsingContext.MatchTypeClauses, parseMatchTypeCaseOrElseClause, /*considerSemicolonAsDelimiter*/ true);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
node.matchBlock = finishNode(matchBlock);
|
||||
type = finishNode(node);
|
||||
continue;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
function parseTupleType(): TupleTypeNode {
|
||||
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
|
||||
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
|
||||
@@ -2768,6 +2835,10 @@ namespace ts {
|
||||
|
||||
function parseArrayTypeOrHigher(): TypeNode {
|
||||
let type = parseJSDocPostfixTypeOrHigher();
|
||||
return parseMatchTypeRest(type);
|
||||
}
|
||||
|
||||
function parseArrayTypeRest(type: TypeNode): TypeNode {
|
||||
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
if (isStartOfType()) {
|
||||
const node = <IndexedAccessTypeNode>createNode(SyntaxKind.IndexedAccessType, type.pos);
|
||||
@@ -6118,6 +6189,7 @@ namespace ts {
|
||||
BlockStatements, // Statements in block
|
||||
SwitchClauses, // Clauses in switch statement
|
||||
SwitchClauseStatements, // Statements in switch clause
|
||||
MatchTypeClauses, // Clauses in a match type block
|
||||
TypeMembers, // Members in interface or type literal
|
||||
ClassMembers, // Members in class declaration
|
||||
EnumMembers, // Members in enum declaration
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace ts {
|
||||
"is": SyntaxKind.IsKeyword,
|
||||
"keyof": SyntaxKind.KeyOfKeyword,
|
||||
"let": SyntaxKind.LetKeyword,
|
||||
"match": SyntaxKind.MatchKeyword,
|
||||
"module": SyntaxKind.ModuleKeyword,
|
||||
"namespace": SyntaxKind.NamespaceKeyword,
|
||||
"never": SyntaxKind.NeverKeyword,
|
||||
|
||||
+53
-9
@@ -187,6 +187,7 @@ namespace ts {
|
||||
GetKeyword,
|
||||
IsKeyword,
|
||||
KeyOfKeyword,
|
||||
MatchKeyword,
|
||||
ModuleKeyword,
|
||||
NamespaceKeyword,
|
||||
NeverKeyword,
|
||||
@@ -239,6 +240,10 @@ namespace ts {
|
||||
TypeOperator,
|
||||
IndexedAccessType,
|
||||
MappedType,
|
||||
MatchType,
|
||||
MatchTypeBlock,
|
||||
MatchTypeMatchClause,
|
||||
MatchTypeElseClause,
|
||||
LiteralType,
|
||||
// Binding patterns
|
||||
ObjectBindingPattern,
|
||||
@@ -1005,6 +1010,32 @@ namespace ts {
|
||||
type?: TypeNode;
|
||||
}
|
||||
|
||||
export interface MatchTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.MatchType;
|
||||
typeArgument: TypeNode;
|
||||
matchBlock: MatchTypeBlock;
|
||||
}
|
||||
|
||||
export interface MatchTypeBlock extends Node {
|
||||
kind: SyntaxKind.MatchTypeBlock;
|
||||
clauses: NodeArray<MatchTypeMatchOrElseClause>;
|
||||
}
|
||||
|
||||
export type MatchTypeMatchOrElseClause =
|
||||
| MatchTypeMatchClause
|
||||
| MatchTypeElseClause;
|
||||
|
||||
export interface MatchTypeMatchClause extends Node {
|
||||
kind: SyntaxKind.MatchTypeMatchClause;
|
||||
matchType: TypeNode;
|
||||
resultType: TypeNode;
|
||||
}
|
||||
|
||||
export interface MatchTypeElseClause extends Node {
|
||||
kind: SyntaxKind.MatchTypeElseClause;
|
||||
resultType: TypeNode;
|
||||
}
|
||||
|
||||
export interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
@@ -3156,17 +3187,18 @@ namespace ts {
|
||||
Intersection = 1 << 17, // Intersection (T & U)
|
||||
Index = 1 << 18, // keyof T
|
||||
IndexedAccess = 1 << 19, // T[K]
|
||||
Match = 1 << 20, // T match { U: V }
|
||||
/* @internal */
|
||||
FreshLiteral = 1 << 20, // Fresh literal type
|
||||
FreshLiteral = 1 << 21, // Fresh literal type
|
||||
/* @internal */
|
||||
ContainsWideningType = 1 << 21, // Type is or contains undefined or null widening type
|
||||
ContainsWideningType = 1 << 22, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type
|
||||
ContainsObjectLiteral = 1 << 23, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains the anyFunctionType
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
ContainsAnyFunctionType = 1 << 24, // Type is or contains the anyFunctionType
|
||||
NonPrimitive = 1 << 25, // intrinsic object type
|
||||
/* @internal */
|
||||
JsxAttributes = 1 << 25, // Jsx attributes type
|
||||
JsxAttributes = 1 << 26, // Jsx attributes type
|
||||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
@@ -3185,12 +3217,12 @@ namespace ts {
|
||||
EnumLike = Enum | EnumLiteral,
|
||||
UnionOrIntersection = Union | Intersection,
|
||||
StructuredType = Object | Union | Intersection,
|
||||
StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess,
|
||||
TypeVariable = TypeParameter | IndexedAccess,
|
||||
StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess | Match,
|
||||
TypeVariable = TypeParameter | IndexedAccess | Match,
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive,
|
||||
Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | Match | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive,
|
||||
NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
@@ -3420,6 +3452,18 @@ namespace ts {
|
||||
type: TypeVariable | UnionOrIntersectionType;
|
||||
}
|
||||
|
||||
// T match {} types (TypeFlags.Match)
|
||||
export interface MatchType extends Type {
|
||||
typeArgument: Type;
|
||||
clauses: ReadonlyArray<MatchTypeClause>;
|
||||
elseType?: Type;
|
||||
}
|
||||
|
||||
export interface MatchTypeClause {
|
||||
matchType: Type;
|
||||
resultType: Type;
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
Call,
|
||||
Construct,
|
||||
|
||||
@@ -4844,7 +4844,6 @@ namespace ts {
|
||||
|| kind === SyntaxKind.BooleanKeyword
|
||||
|| kind === SyntaxKind.StringKeyword
|
||||
|| kind === SyntaxKind.SymbolKeyword
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.VoidKeyword
|
||||
|| kind === SyntaxKind.UndefinedKeyword
|
||||
|| kind === SyntaxKind.NullKeyword
|
||||
@@ -4871,6 +4870,16 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isMatchTypeBlock(node: Node): node is MatchTypeBlock {
|
||||
return node.kind === SyntaxKind.MatchTypeBlock;
|
||||
}
|
||||
|
||||
export function isMatchTypeMatchOrElseClause(node: Node): node is MatchTypeMatchOrElseClause {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.MatchTypeMatchClause
|
||||
|| kind === SyntaxKind.MatchTypeElseClause;
|
||||
}
|
||||
|
||||
// Binding patterns
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -405,6 +405,24 @@ namespace ts {
|
||||
visitNode((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.MatchType:
|
||||
return updateMatchTypeNode(<MatchTypeNode>node,
|
||||
visitNode((<MatchTypeNode>node).typeArgument, visitor, isTypeNode),
|
||||
visitNode((<MatchTypeNode>node).matchBlock, visitor, isMatchTypeBlock));
|
||||
|
||||
case SyntaxKind.MatchTypeBlock:
|
||||
return updateMatchTypeBlock(<MatchTypeBlock>node,
|
||||
nodesVisitor((<MatchTypeBlock>node).clauses, visitor, isMatchTypeMatchOrElseClause));
|
||||
|
||||
case SyntaxKind.MatchTypeMatchClause:
|
||||
return updateMatchTypeMatchClause(<MatchTypeMatchClause>node,
|
||||
visitNode((<MatchTypeMatchClause>node).matchType, visitor, isTypeNode),
|
||||
visitNode((<MatchTypeMatchClause>node).resultType, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.MatchTypeElseClause:
|
||||
return updateMatchTypeElseClause(<MatchTypeElseClause>node,
|
||||
visitNode((<MatchTypeElseClause>node).resultType, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.LiteralType:
|
||||
return updateLiteralTypeNode(<LiteralTypeNode>node,
|
||||
visitNode((<LiteralTypeNode>node).literal, visitor, isExpression));
|
||||
|
||||
Reference in New Issue
Block a user