mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-25 04:31:43 +00:00
Implement non-null assertions (#443)
This commit is contained in:
14
src/ast.ts
14
src/ast.ts
@ -116,10 +116,11 @@ export function nodeIsConstantValue(kind: NodeKind): bool {
|
||||
export function nodeIsCallable(kind: NodeKind): bool {
|
||||
switch (kind) {
|
||||
case NodeKind.IDENTIFIER:
|
||||
case NodeKind.ASSERTION: // if kind=NONNULL
|
||||
case NodeKind.CALL:
|
||||
case NodeKind.ELEMENTACCESS:
|
||||
case NodeKind.PROPERTYACCESS:
|
||||
case NodeKind.PARENTHESIZED: return true;
|
||||
case NodeKind.PARENTHESIZED:
|
||||
case NodeKind.PROPERTYACCESS: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -286,14 +287,14 @@ export abstract class Node {
|
||||
static createAssertionExpression(
|
||||
assertionKind: AssertionKind,
|
||||
expression: Expression,
|
||||
toType: CommonTypeNode,
|
||||
toType: CommonTypeNode | null,
|
||||
range: Range
|
||||
): AssertionExpression {
|
||||
var expr = new AssertionExpression();
|
||||
expr.range = range;
|
||||
expr.assertionKind = assertionKind;
|
||||
expr.expression = expression; expression.parent = expr;
|
||||
expr.toType = toType; toType.parent = expr;
|
||||
expr.toType = toType; if (toType) toType.parent = expr;
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -1282,7 +1283,8 @@ export class ArrayLiteralExpression extends LiteralExpression {
|
||||
/** Indicates the kind of an assertion. */
|
||||
export enum AssertionKind {
|
||||
PREFIX,
|
||||
AS
|
||||
AS,
|
||||
NONNULL
|
||||
}
|
||||
|
||||
/** Represents an assertion expression. */
|
||||
@ -1294,7 +1296,7 @@ export class AssertionExpression extends Expression {
|
||||
/** Expression being asserted. */
|
||||
expression: Expression;
|
||||
/** Target type. */
|
||||
toType: CommonTypeNode;
|
||||
toType: CommonTypeNode | null;
|
||||
}
|
||||
|
||||
/** Represents a binary expression. */
|
||||
|
@ -91,6 +91,7 @@ import {
|
||||
Source,
|
||||
Range,
|
||||
DecoratorKind,
|
||||
AssertionKind,
|
||||
|
||||
Statement,
|
||||
BlockStatement,
|
||||
@ -2704,12 +2705,25 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
|
||||
var toType = this.resolver.resolveType( // reports
|
||||
expression.toType,
|
||||
this.currentFunction.flow.contextualTypeArguments
|
||||
);
|
||||
if (!toType) return this.module.createUnreachable();
|
||||
return this.compileExpression(expression.expression, toType, ConversionKind.EXPLICIT, WrapMode.NONE);
|
||||
switch (expression.assertionKind) {
|
||||
case AssertionKind.PREFIX:
|
||||
case AssertionKind.AS: {
|
||||
let toType = this.resolver.resolveType( // reports
|
||||
assert(expression.toType),
|
||||
this.currentFunction.flow.contextualTypeArguments
|
||||
);
|
||||
if (!toType) return this.module.createUnreachable();
|
||||
return this.compileExpression(expression.expression, toType, ConversionKind.EXPLICIT, WrapMode.NONE);
|
||||
}
|
||||
case AssertionKind.NONNULL: {
|
||||
assert(!expression.toType);
|
||||
let expr = this.compileExpressionRetainType(expression.expression, contextualType, WrapMode.NONE);
|
||||
this.currentType = this.currentType.nonNullableType;
|
||||
return expr;
|
||||
}
|
||||
default: assert(false);
|
||||
}
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
|
||||
private f32ModInstance: Function | null = null;
|
||||
|
@ -477,15 +477,26 @@ export class ASTBuilder {
|
||||
|
||||
visitAssertionExpression(node: AssertionExpression): void {
|
||||
var sb = this.sb;
|
||||
if (node.assertionKind == AssertionKind.PREFIX) {
|
||||
sb.push("<");
|
||||
this.visitTypeNode(node.toType);
|
||||
sb.push(">");
|
||||
this.visitNode(node.expression);
|
||||
} else {
|
||||
this.visitNode(node.expression);
|
||||
sb.push(" as ");
|
||||
this.visitTypeNode(node.toType);
|
||||
switch (node.assertionKind) {
|
||||
case AssertionKind.PREFIX: {
|
||||
sb.push("<");
|
||||
this.visitTypeNode(assert(node.toType));
|
||||
sb.push(">");
|
||||
this.visitNode(node.expression);
|
||||
break;
|
||||
}
|
||||
case AssertionKind.AS: {
|
||||
this.visitNode(node.expression);
|
||||
sb.push(" as ");
|
||||
this.visitTypeNode(assert(node.toType));
|
||||
break;
|
||||
}
|
||||
case AssertionKind.NONNULL: {
|
||||
this.visitNode(node.expression);
|
||||
sb.push("!");
|
||||
break;
|
||||
}
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3472,6 +3472,15 @@ export class Parser extends DiagnosticEmitter {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case Token.EXCLAMATION: {
|
||||
expr = Node.createAssertionExpression(
|
||||
AssertionKind.NONNULL,
|
||||
expr,
|
||||
null,
|
||||
tn.range(startPos, tn.pos)
|
||||
);
|
||||
break;
|
||||
}
|
||||
// InstanceOfExpression
|
||||
case Token.INSTANCEOF: {
|
||||
let isType = this.parseType(tn); // reports
|
||||
@ -3835,7 +3844,8 @@ function determinePrecedence(kind: Token): Precedence {
|
||||
case Token.MINUS_MINUS: return Precedence.UNARY_POSTFIX;
|
||||
case Token.DOT:
|
||||
case Token.NEW:
|
||||
case Token.OPENBRACKET: return Precedence.MEMBERACCESS;
|
||||
case Token.OPENBRACKET:
|
||||
case Token.EXCLAMATION: return Precedence.MEMBERACCESS;
|
||||
}
|
||||
return Precedence.NONE;
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ import {
|
||||
Expression,
|
||||
IntegerLiteralExpression,
|
||||
UnaryPrefixExpression,
|
||||
UnaryPostfixExpression
|
||||
UnaryPostfixExpression,
|
||||
AssertionKind
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -685,17 +686,29 @@ export class Resolver extends DiagnosticEmitter {
|
||||
}
|
||||
switch (expression.kind) {
|
||||
case NodeKind.ASSERTION: {
|
||||
if ((<AssertionExpression>expression).assertionKind == AssertionKind.NONNULL) {
|
||||
return this.resolveExpression(
|
||||
(<AssertionExpression>expression).expression,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
let type = this.resolveType(
|
||||
(<AssertionExpression>expression).toType,
|
||||
assert((<AssertionExpression>expression).toType),
|
||||
contextualFunction.flow.contextualTypeArguments,
|
||||
reportMode
|
||||
);
|
||||
if (!type) return null;
|
||||
let classType = type.classReference;
|
||||
if (!classType) return null;
|
||||
let element: Element | null = type.classReference;
|
||||
if (!element) {
|
||||
let signature = type.signatureReference;
|
||||
if (!signature) return null;
|
||||
element = signature.asFunctionTarget(this.program);
|
||||
}
|
||||
this.currentThisExpression = null;
|
||||
this.currentElementExpression = null;
|
||||
return classType;
|
||||
return element;
|
||||
}
|
||||
case NodeKind.UNARYPREFIX: {
|
||||
// TODO: overloads
|
||||
@ -885,11 +898,7 @@ export class Resolver extends DiagnosticEmitter {
|
||||
} else {
|
||||
let signature = returnType.signatureReference;
|
||||
if (signature) {
|
||||
let functionTarget = signature.cachedFunctionTarget;
|
||||
if (!functionTarget) {
|
||||
functionTarget = new FunctionTarget(this.program, signature);
|
||||
signature.cachedFunctionTarget = functionTarget;
|
||||
}
|
||||
let functionTarget = signature.asFunctionTarget(this.program);
|
||||
// reuse resolvedThisExpression (might be property access)
|
||||
// reuse resolvedElementExpression (might be element access)
|
||||
return functionTarget;
|
||||
|
@ -526,6 +526,13 @@ export class Signature {
|
||||
this.type = Type.u32.asFunction(this);
|
||||
}
|
||||
|
||||
asFunctionTarget(program: Program): FunctionTarget {
|
||||
var target = this.cachedFunctionTarget;
|
||||
if (!target) this.cachedFunctionTarget = target = new FunctionTarget(program, this);
|
||||
else assert(target.program == program);
|
||||
return target;
|
||||
}
|
||||
|
||||
/** Gets the known or, alternatively, generic parameter name at the specified index. */
|
||||
getParameterName(index: i32): string {
|
||||
var parameterNames = this.parameterNames;
|
||||
|
Reference in New Issue
Block a user