Skip to content

Commit

Permalink
type-level assertion operator (!)... parsing still fails
Browse files Browse the repository at this point in the history
checker errors with JSDocUnknownType, but didn't parse that?
  • Loading branch information
KiaraGrouwstra committed Aug 21, 2017
1 parent 5e8e735 commit e7dff1b
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/// <reference path="moduleNameResolver.ts"/>
/// <reference path="binder.ts"/>
/// <reference types="node"/>
declare var console: Console;

/* @internal */
namespace ts {
Expand Down Expand Up @@ -7540,6 +7542,14 @@ namespace ts {
return links.resolvedType;
}

function getTypeFromPostfixedTypeOperatorNode(node: NonNullTypeNode) { // TypeOperatorNode
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getNonNullableType(getTypeFromTypeNode(node.type));
}
return links.resolvedType;
}

function createIndexedAccessType(objectType: Type, indexType: Type) {
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
type.objectType = objectType;
Expand Down Expand Up @@ -7997,6 +8007,8 @@ namespace ts {
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
case SyntaxKind.TypeOperator:
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
case SyntaxKind.NonNullTypeNode:
return getTypeFromPostfixedTypeOperatorNode(<NonNullTypeNode>node);
case SyntaxKind.IndexedAccessType:
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
case SyntaxKind.MappedType:
Expand Down Expand Up @@ -18701,6 +18713,7 @@ namespace ts {
}

function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
if (allowSyntheticDefaultImports) console.trace("checkTypeReferenceNode");
checkGrammarTypeArguments(node, node.typeArguments);
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
Expand Down Expand Up @@ -22315,6 +22328,7 @@ namespace ts {
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
if (!isInJavaScriptFile(node) && !isInJSDoc(node)) {
if (allowSyntheticDefaultImports) console.trace("JSDocUnknownType");
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
return;
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,8 @@ namespace ts {
return emitAsExpression(<AsExpression>node);
case SyntaxKind.NonNullExpression:
return emitNonNullExpression(<NonNullExpression>node);
case SyntaxKind.NonNullTypeNode:
return emitWithSuffix((<NonNullTypeNode>node).type, "!");
case SyntaxKind.MetaProperty:
return emitMetaProperty(<MetaProperty>node);

Expand Down
12 changes: 12 additions & 0 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,18 @@ namespace ts {
: node;
}

export function createNonNullTypeNode(type: TypeNode) {
const node = <NonNullTypeNode>createSynthesizedNode(SyntaxKind.NonNullTypeNode);
node.type = parenthesizeElementTypeMember(type);
return node;
}

export function updateNonNullTypeNode(node: NonNullTypeNode, type: TypeNode) {
return node.type !== type
? updateNode(createNonNullTypeNode(type), node)
: node;
}

export function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) {
const node = <MetaProperty>createSynthesizedNode(SyntaxKind.MetaProperty);
node.keywordToken = keywordToken;
Expand Down
31 changes: 30 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ namespace ts {
visitNode(cbNode, (<AsExpression>node).type);
case SyntaxKind.NonNullExpression:
return visitNode(cbNode, (<NonNullExpression>node).expression);
case SyntaxKind.NonNullTypeNode:
return visitNode(cbNode, (<NonNullTypeNode>node).type);
case SyntaxKind.MetaProperty:
return visitNode(cbNode, (<MetaProperty>node).name);
case SyntaxKind.ConditionalExpression:
Expand Down Expand Up @@ -1959,6 +1961,7 @@ namespace ts {
while (parseOptional(SyntaxKind.DotToken)) {
if (token() === SyntaxKind.LessThanToken) {
// the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
console.trace("parseEntityName:jsdocDotPos");
entity.jsdocDotPos = dotPos;
break;
}
Expand Down Expand Up @@ -2122,6 +2125,7 @@ namespace ts {
}

function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
console.trace("parseJSDocUnknownOrNullableType");
const pos = scanner.getStartPos();
// skip the ?
nextToken();
Expand Down Expand Up @@ -2657,6 +2661,7 @@ namespace ts {
case SyntaxKind.AsteriskToken:
return parseJSDocAllType();
case SyntaxKind.QuestionToken:
console.trace("parseNonArrayType:QuestionToken");
return parseJSDocUnknownOrNullableType();
case SyntaxKind.FunctionKeyword:
return parseJSDocFunctionType();
Expand Down Expand Up @@ -2794,7 +2799,31 @@ namespace ts {
case SyntaxKind.KeyOfKeyword:
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
}
return parseArrayTypeOrHigher();
const type = parseArrayTypeOrHigher();
return parsePostfixTypeOperatorOrHigher(type);
}

function parsePostfixTypeOperator(type: TypeNode) { // , operator: SyntaxKind.NonNullTypeNode
// const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
const node = <NonNullTypeNode>createNode(SyntaxKind.NonNullTypeNode);
// parseExpected(operator);
parseExpected(SyntaxKind.ExclamationToken);
// node.operator = operator;
node.type = type;
return finishNode(node);
}

function parsePostfixTypeOperatorOrHigher(type: TypeNode): TypeNode {
let postfixed: TypeNode;
switch (token()) {
case SyntaxKind.NonNullTypeNode:
return parsePostfixTypeOperator(type); // , SyntaxKind.NonNullTypeNode
}
if (postfixed) {
return parsePostfixTypeOperatorOrHigher(postfixed);
} else {
return type;
}
}

function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ namespace ts {
ExpressionWithTypeArguments,
AsExpression,
NonNullExpression,
NonNullTypeNode,
MetaProperty,

// Misc
Expand Down Expand Up @@ -1545,6 +1546,11 @@ namespace ts {
expression: Expression;
}

export interface NonNullTypeNode extends TypeNode {
kind: SyntaxKind.NonNullTypeNode;
type: TypeNode;
}

// NOTE: MetaProperty is really a MemberExpression, but we consider it a PrimaryExpression
// for the same reasons we treat NewExpression as a PrimaryExpression.
export interface MetaProperty extends PrimaryExpression {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ namespace ts {
return updateNonNullExpression(<NonNullExpression>node,
visitNode((<NonNullExpression>node).expression, visitor, isExpression));

case SyntaxKind.NonNullTypeNode:
return updateNonNullTypeNode(<NonNullTypeNode>node,
visitNode((<NonNullTypeNode>node).type, visitor, isTypeNode));

case SyntaxKind.MetaProperty:
return updateMetaProperty(<MetaProperty>node,
visitNode((<MetaProperty>node).name, visitor, isIdentifier));
Expand Down
11 changes: 11 additions & 0 deletions tests/baselines/reference/nonNullType.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
tests/cases/compiler/nonNullType.ts(2,10): error TS8020: JSDoc types can only be used inside documentation comments.


==== tests/cases/compiler/nonNullType.ts (1 errors) ====
type a = string | undefined | null | never;
type b = a!;
~~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
// type Assert<T> = T!;
// type c = Assert<a>;

10 changes: 10 additions & 0 deletions tests/baselines/reference/nonNullType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//// [nonNullType.ts]
type a = string | undefined | null | never;
type b = a!;
// type Assert<T> = T!;
// type c = Assert<a>;


//// [nonNullType.js]
// type Assert<T> = T!;
// type c = Assert<a>;
5 changes: 5 additions & 0 deletions tests/cases/compiler/nonNullType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @allowSyntheticDefaultImports: true
type a = string | undefined | null | never;
type b = a!;
// type Assert<T> = T!;
// type c = Assert<a>;

0 comments on commit e7dff1b

Please sign in to comment.