Skip to content

Eliminate redundant type assertions #1156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 63 additions & 48 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,6 @@ export enum NodeKind {
COMMENT
}

/** Checks if a node represents a constant value. */
export function nodeIsConstantValue(kind: NodeKind): bool {
switch (kind) {
case NodeKind.LITERAL:
case NodeKind.NULL:
case NodeKind.TRUE:
case NodeKind.FALSE: return true;
}
return false;
}

/** Base class of all nodes. */
export abstract class Node {
/** Node kind indicator. */
Expand Down Expand Up @@ -1141,6 +1130,41 @@ export abstract class Node {
node.statement = statement;
return node;
}

/** Tests if this node is a literal of the specified kind. */
isLiteralKind(literalKind: LiteralKind): bool {
return this.kind == NodeKind.LITERAL
&& (<LiteralExpression>changetype<Node>(this)).literalKind == literalKind; // TS
}

/** Tests if this node is a literal of a numeric kind (float or integer). */
get isNumericLiteral(): bool {
if (this.kind == NodeKind.LITERAL) {
switch ((<LiteralExpression>changetype<Node>(this)).literalKind) { // TS
case LiteralKind.FLOAT:
case LiteralKind.INTEGER: return true;
}
}
return false;
}

/** Tests whether this node is guaranteed to compile to a constant value. */
get compilesToConst(): bool {
switch (this.kind) {
case NodeKind.LITERAL: {
switch ((<LiteralExpression>changetype<Node>(this)).literalKind) { // TS
case LiteralKind.FLOAT:
case LiteralKind.INTEGER:
case LiteralKind.STRING: return true;
}
break;
}
case NodeKind.NULL:
case NodeKind.TRUE:
case NodeKind.FALSE: return true;
}
return false;
}
}

// types
Expand All @@ -1153,28 +1177,29 @@ export abstract class TypeNode extends Node {

/** Tests if this type has a generic component matching one of the given type parameters. */
hasGenericComponent(typeParameterNodes: TypeParameterNode[]): bool {
var self = <TypeNode>this; // TS otherwise complains
if (this.kind == NodeKind.NAMEDTYPE) {
if (!(<NamedTypeNode>self).name.next) {
let typeArgumentNodes = (<NamedTypeNode>self).typeArguments;
let namedTypeNode = <NamedTypeNode>changetype<TypeNode>(this); // TS
if (!namedTypeNode.name.next) {
let typeArgumentNodes = namedTypeNode.typeArguments;
if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) {
for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) {
if (typeArgumentNodes[i].hasGenericComponent(typeParameterNodes)) return true;
}
} else {
let name = (<NamedTypeNode>self).name.identifier.text;
let name = namedTypeNode.name.identifier.text;
for (let i = 0, k = typeParameterNodes.length; i < k; ++i) {
if (typeParameterNodes[i].name.text == name) return true;
}
}
}
} else if (this.kind == NodeKind.FUNCTIONTYPE) {
let parameterNodes = (<FunctionTypeNode>self).parameters;
let functionTypeNode = <FunctionTypeNode>changetype<TypeNode>(this); // TS
let parameterNodes = functionTypeNode.parameters;
for (let i = 0, k = parameterNodes.length; i < k; ++i) {
if (parameterNodes[i].type.hasGenericComponent(typeParameterNodes)) return true;
}
if ((<FunctionTypeNode>self).returnType.hasGenericComponent(typeParameterNodes)) return true;
let explicitThisType = (<FunctionTypeNode>self).explicitThisType;
if (functionTypeNode.returnType.hasGenericComponent(typeParameterNodes)) return true;
let explicitThisType = functionTypeNode.explicitThisType;
if (explicitThisType !== null && explicitThisType.hasGenericComponent(typeParameterNodes)) return true;
} else {
assert(false);
Expand Down Expand Up @@ -1319,25 +1344,26 @@ export namespace DecoratorKind {
break;
}
}
} else if (
nameNode.kind == NodeKind.PROPERTYACCESS &&
(<PropertyAccessExpression>nameNode).expression.kind == NodeKind.IDENTIFIER
) {
let nameStr = (<IdentifierExpression>(<PropertyAccessExpression>nameNode).expression).text;
assert(nameStr.length);
let propStr = (<PropertyAccessExpression>nameNode).property.text;
assert(propStr.length);
// @operator.binary, @operator.prefix, @operator.postfix
if (nameStr == "operator") {
switch (propStr.charCodeAt(0)) {
case CharCode.b: {
if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY;
break;
}
case CharCode.p: {
if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX;
if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX;
break;
} else if (nameNode.kind == NodeKind.PROPERTYACCESS) {
let propertyAccessNode = <PropertyAccessExpression>nameNode;
let expression = propertyAccessNode.expression;
if (expression.kind == NodeKind.IDENTIFIER) {
let nameStr = (<IdentifierExpression>expression).text;
assert(nameStr.length);
let propStr = propertyAccessNode.property.text;
assert(propStr.length);
// @operator.binary, @operator.prefix, @operator.postfix
if (nameStr == "operator") {
switch (propStr.charCodeAt(0)) {
case CharCode.b: {
if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY;
break;
}
case CharCode.p: {
if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX;
if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX;
break;
}
}
}
}
Expand Down Expand Up @@ -1397,17 +1423,6 @@ export enum LiteralKind {
OBJECT
}

/** Checks if the given node represents a numeric (float or integer) literal. */
export function isNumericLiteral(node: Expression): bool {
if (node.kind == NodeKind.LITERAL) {
switch ((<LiteralExpression>node).literalKind) {
case LiteralKind.FLOAT:
case LiteralKind.INTEGER: return true;
}
}
return false;
}

/** Base class of all literal expressions. */
export abstract class LiteralExpression extends Expression {
/** Specific literal kind. */
Expand Down
19 changes: 7 additions & 12 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@ import {
} from "./diagnostics";

import {
NodeKind,
Expression,
LiteralKind,
LiteralExpression,
StringLiteralExpression,
CallExpression,
isNumericLiteral
CallExpression
} from "./ast";

import {
Expand Down Expand Up @@ -889,17 +886,15 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef {
return module.unreachable();
}
if (operands.length) {
if (
operands[0].kind != NodeKind.LITERAL ||
(<LiteralExpression>operands[0]).literalKind != LiteralKind.STRING
) {
let firstOperand = operands[0];
if (!firstOperand.isLiteralKind(LiteralKind.STRING)) {
compiler.error(
DiagnosticCode.String_literal_expected,
operands[0].range
);
return module.unreachable();
}
let fieldName = (<StringLiteralExpression>operands[0]).value;
let fieldName = (<StringLiteralExpression>firstOperand).value;
let classMembers = classType.members;
if (classMembers !== null && classMembers.has(fieldName)) {
let member = assert(classMembers.get(fieldName));
Expand All @@ -909,7 +904,7 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef {
}
compiler.error(
DiagnosticCode.Type_0_has_no_property_1,
operands[0].range, classType.internalName, fieldName
firstOperand.range, classType.internalName, fieldName
);
return module.unreachable();
}
Expand Down Expand Up @@ -1346,7 +1341,7 @@ function builtin_max(ctx: BuiltinContext): ExpressionRef {
var type = compiler.currentType;
if (!type.is(TypeFlags.REFERENCE)) {
let arg1: ExpressionRef;
if (!typeArguments && isNumericLiteral(left)) { // prefer right type
if (!typeArguments && left.isNumericLiteral) { // prefer right type
arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP);
if (compiler.currentType != type) {
arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP);
Expand Down Expand Up @@ -1425,7 +1420,7 @@ function builtin_min(ctx: BuiltinContext): ExpressionRef {
var type = compiler.currentType;
if (!type.is(TypeFlags.REFERENCE)) {
let arg1: ExpressionRef;
if (!typeArguments && isNumericLiteral(left)) { // prefer right type
if (!typeArguments && left.isNumericLiteral) { // prefer right type
arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP);
if (compiler.currentType != type) {
arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP);
Expand Down
Loading