From 0f52bf5514477f7b98f3b75217af442ebfd5ffab Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 12 Sep 2019 19:21:23 +0200 Subject: [PATCH 1/9] Improve inferring generic parameters --- src/ast.ts | 31 +++++++ src/compiler.ts | 50 +++-------- src/resolver.ts | 97 ++++++++++++++++++++++ tests/compiler/infer-generic.json | 5 ++ tests/compiler/infer-generic.optimized.wat | 20 +++++ tests/compiler/infer-generic.ts | 39 +++++++++ tests/compiler/infer-generic.untouched.wat | 66 +++++++++++++++ 7 files changed, 270 insertions(+), 38 deletions(-) create mode 100644 tests/compiler/infer-generic.json create mode 100644 tests/compiler/infer-generic.optimized.wat create mode 100644 tests/compiler/infer-generic.ts create mode 100644 tests/compiler/infer-generic.untouched.wat diff --git a/src/ast.ts b/src/ast.ts index e4439e6b2a..fc672f3936 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1087,6 +1087,37 @@ export abstract class TypeNode extends Node { /** Whether nullable or not. */ isNullable: bool; + + /** Tests if this type has a generic component matching one of the given type parameters. */ + hasGeneric(typeParameterNodes: TypeParameterNode[]): bool { + var self = this; // TS otherwise complains + if (this.kind == NodeKind.NAMEDTYPE) { + if (!(self).name.next) { + let typeArgumentNodes = (self).typeArguments; + if (typeArgumentNodes !== null && typeArgumentNodes.length) { + for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) { + if (typeArgumentNodes[i].hasGeneric(typeParameterNodes)) return true; + } + } else { + let name = (self).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 = (self).parameters; + for (let i = 0, k = parameterNodes.length; i < k; ++i) { + if (parameterNodes[i].type.hasGeneric(typeParameterNodes)) return true; + } + if ((self).returnType.hasGeneric(typeParameterNodes)) return true; + let explicitThisType = (self).explicitThisType; + if (explicitThisType !== null && explicitThisType.hasGeneric(typeParameterNodes)) return true; + } else { + assert(false); + } + return false; + } } /** Represents a type name. */ diff --git a/src/compiler.ts b/src/compiler.ts index 99463ce5ce..4d6c2c5fa8 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5843,13 +5843,12 @@ export class Compiler extends DiagnosticEmitter { // infer generic call if type arguments have been omitted } else if (prototype.is(CommonFlags.GENERIC)) { - let inferredTypes = new Map(); + let contextualTypeArguments = makeMap(flow.contextualTypeArguments); let typeParameterNodes = assert(prototype.typeParameterNodes); let numTypeParameters = typeParameterNodes.length; for (let i = 0; i < numTypeParameters; ++i) { - inferredTypes.set(typeParameterNodes[i].name.text, null); + contextualTypeArguments.set(typeParameterNodes[i].name.text, Type.auto); // T = auto } - // let numInferred = 0; let parameterNodes = prototype.functionTypeNode.parameters; let numParameters = parameterNodes.length; let argumentNodes = expression.arguments; @@ -5857,9 +5856,6 @@ export class Compiler extends DiagnosticEmitter { let argumentExprs = new Array(numArguments); for (let i = 0; i < numParameters; ++i) { let typeNode = parameterNodes[i].type; - let templateName = typeNode.kind == NodeKind.NAMEDTYPE && !(typeNode).name.next - ? (typeNode).name.identifier.text - : null; let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer; @@ -5870,43 +5866,21 @@ export class Compiler extends DiagnosticEmitter { ); return module.unreachable(); } - if (templateName !== null && inferredTypes.has(templateName)) { - let inferredType = inferredTypes.get(templateName); - if (inferredType) { - argumentExprs[i] = this.compileExpression(argumentExpression, inferredType); - let commonType: Type | null; - if (!(commonType = Type.commonDenominator(inferredType, this.currentType, true))) { - if (!(commonType = Type.commonDenominator(inferredType, this.currentType, false))) { - this.error( - DiagnosticCode.Type_0_is_not_assignable_to_type_1, - parameterNodes[i].type.range, this.currentType.toString(), inferredType.toString() - ); - return module.unreachable(); - } - } - inferredType = commonType; - } else { - argumentExprs[i] = this.compileExpression(argumentExpression, Type.auto); - inferredType = this.currentType; - // ++numInferred; - } - inferredTypes.set(templateName, inferredType); + let type: Type | null; + if (typeNode.hasGeneric(typeParameterNodes)) { + type = this.resolver.inferGenericType(typeNode, argumentExpression, flow, contextualTypeArguments); } else { - let concreteType = this.resolver.resolveType( - parameterNodes[i].type, - flow.actualFunction, - flow.contextualTypeArguments - ); - if (!concreteType) return module.unreachable(); - argumentExprs[i] = this.compileExpression(argumentExpression, concreteType, Constraints.CONV_IMPLICIT); + type = this.resolver.resolveType(typeNode, flow.actualFunction, contextualTypeArguments); } + if (!type) return module.unreachable(); + argumentExprs[i] = this.compileExpression(argumentExpression, type, Constraints.CONV_IMPLICIT); } - let resolvedTypeArguments = new Array(numTypeParameters); + let resolvedTypeArguments = Array.create(numTypeParameters); for (let i = 0; i < numTypeParameters; ++i) { let name = typeParameterNodes[i].name.text; - if (inferredTypes.has(name)) { - let inferredType = inferredTypes.get(name); - if (inferredType) { + if (contextualTypeArguments.has(name)) { + let inferredType = contextualTypeArguments.get(name)!; + if (inferredType != Type.auto) { resolvedTypeArguments[i] = inferredType; continue; } diff --git a/src/resolver.ts b/src/resolver.ts index 5b741f8269..29679a3c71 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -691,6 +691,103 @@ export class Resolver extends DiagnosticEmitter { return typeArguments; } + /** Infers the generic type(s) of an argument expression. */ + inferGenericType( + /** The generic type being inferred. */ + typeNode: TypeNode, + /** The respective argument expression. */ + exprNode: Expression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual types, i.e. `T` with generic parameters initialized to `auto`. */ + ctxTypes: Map, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var type = this.resolveExpression(exprNode, ctxFlow, Type.auto, reportMode); + if (!type) return null; + this.updateInferredGenericTypes(typeNode, type, ctxFlow, ctxTypes, reportMode); + return type; + } + + /** Updates contextual types with a possibly encapsulated inferred type. */ + private updateInferredGenericTypes( + /** The inferred type node. */ + node: TypeNode, + /** The inferred type. */ + type: Type, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual types, i.e. `T` with generic parameters initialized to `auto`. */ + ctxTypes: Map, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode + ): void { + if (node.kind == NodeKind.NAMEDTYPE) { + let typeArgumentNodes = (node).typeArguments; + if (typeArgumentNodes !== null && typeArgumentNodes.length) { // foo(bar: Array) + let classReference = type.classReference; + if (classReference) { + let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction, reportMode); + if (!classPrototype || classPrototype.kind != ElementKind.CLASS_PROTOTYPE) return; + if (classReference.prototype == classPrototype) { + let typeArguments = classReference.typeArguments; + if (typeArguments !== null && typeArguments.length == typeArgumentNodes.length) { + for (let i = 0, k = typeArguments.length; i < k; ++i) { + this.updateInferredGenericTypes(typeArgumentNodes[i], typeArguments[i], ctxFlow, ctxTypes, reportMode); + } + return; + } + } + } + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Type_0_is_not_assignable_to_type_1, + node.range, type.toString(), node.range.toString() + ); + } + } else { // foo(bar: T) + let name = (node).name.identifier.text; + if (ctxTypes.has(name)) { + let currentType = ctxTypes.get(name)!; + if (currentType == Type.auto) { + ctxTypes.set(name, type); + } else if (!type.isAssignableTo(currentType)) { // can this happen? + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Type_0_is_not_assignable_to_type_1, + node.range, type.toString(), currentType.toString() + ); + } + } + } // otherwise non-inferred bar: i32 + } + } else if (node.kind == NodeKind.FUNCTIONTYPE) { // foo(bar: (baz: T) => i32)) + let parameterNodes = (node).parameters; + if (parameterNodes !== null && parameterNodes.length) { + let signatureReference = type.signatureReference; + if (signatureReference) { + let parameterTypes = signatureReference.parameterTypes; + let thisType = signatureReference.thisType; + if (parameterTypes.length == parameterNodes.length && !thisType == !(node).explicitThisType) { + for (let i = 0, k = parameterTypes.length; i < k; ++i) { + this.updateInferredGenericTypes(parameterNodes[i].type, parameterTypes[i], ctxFlow, ctxTypes, reportMode); + } + this.updateInferredGenericTypes((node).returnType, signatureReference.returnType, ctxFlow, ctxTypes, reportMode); + if (thisType) this.updateInferredGenericTypes((node).explicitThisType!, thisType, ctxFlow, ctxTypes, reportMode); + return; + } + } + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Type_0_is_not_assignable_to_type_1, + node.range, type.toString(), node.range.toString() + ); + } + } + } + } + /** Gets the concrete type of an element. */ getTypeOfElement(element: Element): Type | null { var kind = element.kind; diff --git a/tests/compiler/infer-generic.json b/tests/compiler/infer-generic.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/infer-generic.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/infer-generic.optimized.wat b/tests/compiler/infer-generic.optimized.wat new file mode 100644 index 0000000000..5239167a0d --- /dev/null +++ b/tests/compiler/infer-generic.optimized.wat @@ -0,0 +1,20 @@ +(module + (type $FUNCSIG$ff (func (param f32) (result f32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$v (func)) + (memory $0 0) + (export "memory" (memory $0)) + (export "test1" (func $infer-generic/test1)) + (export "test2" (func $infer-generic/test2)) + (export "test3" (func $infer-generic/test2)) + (export "test4" (func $infer-generic/test2)) + (func $infer-generic/test1 (; 0 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + local.get $0 + ) + (func $infer-generic/test2 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $null (; 2 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/infer-generic.ts b/tests/compiler/infer-generic.ts new file mode 100644 index 0000000000..a736193d78 --- /dev/null +++ b/tests/compiler/infer-generic.ts @@ -0,0 +1,39 @@ +// T should infer T + +function inferPlain(arr: T): T { + return arr; +} + +export function test1(arr: f32): f32 { + return inferPlain(arr); +} + +// Array should infer T + +function inferEncapsulatedClass(arr: T[]): T[] { + return arr; +} + +export function test2(arr: f32[]): f32[] { + return inferEncapsulatedClass(arr); +} + +// (a: T) => R should infer T,R + +function inferEncapsulatedFunction(fn: (a: T) => R): (a: T) => R { + return fn; +} + +export function test3(fn: (a: f32) => f64): (a: f32) => f64 { + return inferEncapsulatedFunction(fn); +} + +// (a: T, b: i32) => R should not bail out on non-inferred i32 + +function inferEncapsulatedFunctionMixed(fn: (a: T, b: i32) => R): (a: T, b: i32) => R { + return fn; +} + +export function test4(fn: (a: f32, b: i32) => f64): (a: f32, b: i32) => f64 { + return inferEncapsulatedFunctionMixed(fn); +} diff --git a/tests/compiler/infer-generic.untouched.wat b/tests/compiler/infer-generic.untouched.wat new file mode 100644 index 0000000000..75c17b4d0d --- /dev/null +++ b/tests/compiler/infer-generic.untouched.wat @@ -0,0 +1,66 @@ +(module + (type $FUNCSIG$ff (func (param f32) (result f32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$v (func)) + (memory $0 0) + (table $0 1 funcref) + (elem (i32.const 0) $null) + (export "memory" (memory $0)) + (export "test1" (func $infer-generic/test1)) + (export "test2" (func $infer-generic/test2)) + (export "test3" (func $infer-generic/test3)) + (export "test4" (func $infer-generic/test4)) + (func $infer-generic/inferPlain (; 0 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + local.get $0 + ) + (func $infer-generic/test1 (; 1 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + local.get $0 + call $infer-generic/inferPlain + ) + (func $~lib/rt/stub/__retain (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $infer-generic/inferEncapsulatedClass (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $0 + ) + (func $~lib/rt/stub/__release (; 4 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $infer-generic/test2 (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $0 + call $infer-generic/inferEncapsulatedClass + local.tee $1 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $0 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $infer-generic/inferEncapsulatedFunction (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $infer-generic/test3 (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $infer-generic/inferEncapsulatedFunction + ) + (func $infer-generic/inferEncapsulatedFunctionMixed (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $infer-generic/test4 (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $infer-generic/inferEncapsulatedFunctionMixed + ) + (func $null (; 10 ;) (type $FUNCSIG$v) + ) +) From cdb1817b744be72a393a09e5489badd82b4b81ad Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 11:12:34 +0200 Subject: [PATCH 2/9] infer common compatible types --- src/compiler.ts | 42 +++++++++------ src/resolver.ts | 60 ++++++++-------------- tests/compiler/infer-generic.optimized.wat | 7 +-- tests/compiler/infer-generic.ts | 7 +++ tests/compiler/infer-generic.untouched.wat | 53 ++++++++++++++----- 5 files changed, 98 insertions(+), 71 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 4d6c2c5fa8..91b0c2c306 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5843,38 +5843,50 @@ export class Compiler extends DiagnosticEmitter { // infer generic call if type arguments have been omitted } else if (prototype.is(CommonFlags.GENERIC)) { + + // initialize contextual types with auto for each generic component let contextualTypeArguments = makeMap(flow.contextualTypeArguments); let typeParameterNodes = assert(prototype.typeParameterNodes); let numTypeParameters = typeParameterNodes.length; + let typeParameterNames = new Set(); for (let i = 0; i < numTypeParameters; ++i) { - contextualTypeArguments.set(typeParameterNodes[i].name.text, Type.auto); // T = auto + let name = typeParameterNodes[i].name.text; + contextualTypeArguments.set(name, Type.auto); // T = auto + typeParameterNames.add(name); } + let parameterNodes = prototype.functionTypeNode.parameters; let numParameters = parameterNodes.length; let argumentNodes = expression.arguments; let numArguments = argumentNodes.length; let argumentExprs = new Array(numArguments); + + // infer types with generic components while updating contextual types for (let i = 0; i < numParameters; ++i) { let typeNode = parameterNodes[i].type; - let argumentExpression = i < numArguments - ? argumentNodes[i] - : parameterNodes[i].initializer; - if (!argumentExpression) { // missing initializer -> too few arguments - this.error( - DiagnosticCode.Expected_0_arguments_but_got_1, - expression.range, numParameters.toString(10), numArguments.toString(10) - ); - return module.unreachable(); - } - let type: Type | null; if (typeNode.hasGeneric(typeParameterNodes)) { - type = this.resolver.inferGenericType(typeNode, argumentExpression, flow, contextualTypeArguments); - } else { - type = this.resolver.resolveType(typeNode, flow.actualFunction, contextualTypeArguments); + let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer; + if (!argumentExpression) { // missing initializer -> too few arguments + this.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + expression.range, numParameters.toString(10), numArguments.toString(10) + ); + return module.unreachable(); + } + this.resolver.inferGenericType(typeNode, argumentExpression, flow, contextualTypeArguments, typeParameterNames); } + } + + // use updated contextual types to resolve to concrete types and compile + for (let i = 0; i < numParameters; ++i) { + let typeNode = parameterNodes[i].type; + let type = this.resolver.resolveType(typeNode, flow.actualFunction, contextualTypeArguments); if (!type) return module.unreachable(); + let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer!; argumentExprs[i] = this.compileExpression(argumentExpression, type, Constraints.CONV_IMPLICIT); } + + // apply concrete types to the generic function signature let resolvedTypeArguments = Array.create(numTypeParameters); for (let i = 0; i < numTypeParameters; ++i) { let name = typeParameterNodes[i].name.text; diff --git a/src/resolver.ts b/src/resolver.ts index 29679a3c71..c4669ccd42 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -65,7 +65,8 @@ import { TernaryExpression, isTypeOmitted, FunctionExpression, - NewExpression + NewExpression, + ParameterNode } from "./ast"; import { @@ -691,7 +692,7 @@ export class Resolver extends DiagnosticEmitter { return typeArguments; } - /** Infers the generic type(s) of an argument expression. */ + /** Infers the generic type(s) of an argument expression and updates `ctxTypes`. */ inferGenericType( /** The generic type being inferred. */ typeNode: TypeNode, @@ -699,68 +700,53 @@ export class Resolver extends DiagnosticEmitter { exprNode: Expression, /** Contextual flow. */ ctxFlow: Flow, - /** Contextual types, i.e. `T` with generic parameters initialized to `auto`. */ + /** Contextual types, i.e. `T`, with unknown types initialized to `auto`. */ ctxTypes: Map, - /** How to proceed with eventual diagnostics. */ - reportMode: ReportMode = ReportMode.REPORT - ): Type | null { - var type = this.resolveExpression(exprNode, ctxFlow, Type.auto, reportMode); - if (!type) return null; - this.updateInferredGenericTypes(typeNode, type, ctxFlow, ctxTypes, reportMode); - return type; + /** The names of the type parameters being inferred. */ + typeParameterNames: Set + ): void { + var type = this.resolveExpression(exprNode, ctxFlow, Type.auto, ReportMode.SWALLOW); + if (type) this.propagateInferredGenericTypes(typeNode, type, ctxFlow, ctxTypes, typeParameterNames); } /** Updates contextual types with a possibly encapsulated inferred type. */ - private updateInferredGenericTypes( + private propagateInferredGenericTypes( /** The inferred type node. */ node: TypeNode, /** The inferred type. */ type: Type, /** Contextual flow. */ ctxFlow: Flow, - /** Contextual types, i.e. `T` with generic parameters initialized to `auto`. */ + /** Contextual types, i.e. `T`, with unknown types initialized to `auto`. */ ctxTypes: Map, - /** How to proceed with eventual diagnostics. */ - reportMode: ReportMode + /** The names of the type parameters being inferred. */ + typeParameterNames: Set ): void { if (node.kind == NodeKind.NAMEDTYPE) { let typeArgumentNodes = (node).typeArguments; if (typeArgumentNodes !== null && typeArgumentNodes.length) { // foo(bar: Array) let classReference = type.classReference; if (classReference) { - let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction, reportMode); + let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction); if (!classPrototype || classPrototype.kind != ElementKind.CLASS_PROTOTYPE) return; if (classReference.prototype == classPrototype) { let typeArguments = classReference.typeArguments; if (typeArguments !== null && typeArguments.length == typeArgumentNodes.length) { for (let i = 0, k = typeArguments.length; i < k; ++i) { - this.updateInferredGenericTypes(typeArgumentNodes[i], typeArguments[i], ctxFlow, ctxTypes, reportMode); + this.propagateInferredGenericTypes(typeArgumentNodes[i], typeArguments[i], ctxFlow, ctxTypes, typeParameterNames); } return; } } } - if (reportMode == ReportMode.REPORT) { - this.error( - DiagnosticCode.Type_0_is_not_assignable_to_type_1, - node.range, type.toString(), node.range.toString() - ); - } } else { // foo(bar: T) let name = (node).name.identifier.text; if (ctxTypes.has(name)) { let currentType = ctxTypes.get(name)!; - if (currentType == Type.auto) { + if (currentType == Type.auto || (typeParameterNames.has(name) && currentType.isAssignableTo(type))) { ctxTypes.set(name, type); - } else if (!type.isAssignableTo(currentType)) { // can this happen? - if (reportMode == ReportMode.REPORT) { - this.error( - DiagnosticCode.Type_0_is_not_assignable_to_type_1, - node.range, type.toString(), currentType.toString() - ); - } } - } // otherwise non-inferred bar: i32 + } } } else if (node.kind == NodeKind.FUNCTIONTYPE) { // foo(bar: (baz: T) => i32)) let parameterNodes = (node).parameters; @@ -771,19 +757,13 @@ export class Resolver extends DiagnosticEmitter { let thisType = signatureReference.thisType; if (parameterTypes.length == parameterNodes.length && !thisType == !(node).explicitThisType) { for (let i = 0, k = parameterTypes.length; i < k; ++i) { - this.updateInferredGenericTypes(parameterNodes[i].type, parameterTypes[i], ctxFlow, ctxTypes, reportMode); + this.propagateInferredGenericTypes(parameterNodes[i].type, parameterTypes[i], ctxFlow, ctxTypes, typeParameterNames); } - this.updateInferredGenericTypes((node).returnType, signatureReference.returnType, ctxFlow, ctxTypes, reportMode); - if (thisType) this.updateInferredGenericTypes((node).explicitThisType!, thisType, ctxFlow, ctxTypes, reportMode); + this.propagateInferredGenericTypes((node).returnType, signatureReference.returnType, ctxFlow, ctxTypes, typeParameterNames); + if (thisType) this.propagateInferredGenericTypes((node).explicitThisType!, thisType, ctxFlow, ctxTypes, typeParameterNames); return; } } - if (reportMode == ReportMode.REPORT) { - this.error( - DiagnosticCode.Type_0_is_not_assignable_to_type_1, - node.range, type.toString(), node.range.toString() - ); - } } } } diff --git a/tests/compiler/infer-generic.optimized.wat b/tests/compiler/infer-generic.optimized.wat index 5239167a0d..483f6416cb 100644 --- a/tests/compiler/infer-generic.optimized.wat +++ b/tests/compiler/infer-generic.optimized.wat @@ -1,8 +1,9 @@ (module + (type $FUNCSIG$v (func)) (type $FUNCSIG$ff (func (param f32) (result f32))) (type $FUNCSIG$ii (func (param i32) (result i32))) - (type $FUNCSIG$v (func)) - (memory $0 0) + (memory $0 1) + (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00i\00n\00f\00e\00r\00-\00g\00e\00n\00e\00r\00i\00c\00.\00t\00s") (export "memory" (memory $0)) (export "test1" (func $infer-generic/test1)) (export "test2" (func $infer-generic/test2)) @@ -14,7 +15,7 @@ (func $infer-generic/test2 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $null (; 2 ;) (type $FUNCSIG$v) + (func $start (; 2 ;) (type $FUNCSIG$v) nop ) ) diff --git a/tests/compiler/infer-generic.ts b/tests/compiler/infer-generic.ts index a736193d78..ece3a9147a 100644 --- a/tests/compiler/infer-generic.ts +++ b/tests/compiler/infer-generic.ts @@ -37,3 +37,10 @@ function inferEncapsulatedFunctionMixed(fn: (a: T, b: i32) => R): (a: T, b: export function test4(fn: (a: f32, b: i32) => f64): (a: f32, b: i32) => f64 { return inferEncapsulatedFunctionMixed(fn); } + +// should pick common compatible type f64 + +function inferCompatible(a: T, b: T): bool { + return a == b; +} +assert(inferCompatible(1, 1.0)); diff --git a/tests/compiler/infer-generic.untouched.wat b/tests/compiler/infer-generic.untouched.wat index 75c17b4d0d..1fa2fb41f7 100644 --- a/tests/compiler/infer-generic.untouched.wat +++ b/tests/compiler/infer-generic.untouched.wat @@ -1,9 +1,13 @@ (module + (type $FUNCSIG$idd (func (param f64 f64) (result i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$v (func)) (type $FUNCSIG$ff (func (param f32) (result f32))) (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$vi (func (param i32))) - (type $FUNCSIG$v (func)) - (memory $0 0) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00i\00n\00f\00e\00r\00-\00g\00e\00n\00e\00r\00i\00c\00.\00t\00s\00") (table $0 1 funcref) (elem (i32.const 0) $null) (export "memory" (memory $0)) @@ -11,26 +15,46 @@ (export "test2" (func $infer-generic/test2)) (export "test3" (func $infer-generic/test3)) (export "test4" (func $infer-generic/test4)) - (func $infer-generic/inferPlain (; 0 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + (start $start) + (func $infer-generic/inferCompatible (; 1 ;) (type $FUNCSIG$idd) (param $0 f64) (param $1 f64) (result i32) local.get $0 + local.get $1 + f64.eq + ) + (func $start:infer-generic (; 2 ;) (type $FUNCSIG$v) + f64.const 1 + f64.const 1 + call $infer-generic/inferCompatible + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 46 + i32.const 0 + call $~lib/builtins/abort + unreachable + end ) - (func $infer-generic/test1 (; 1 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + (func $infer-generic/inferPlain (; 3 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + local.get $0 + ) + (func $infer-generic/test1 (; 4 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) local.get $0 call $infer-generic/inferPlain ) - (func $~lib/rt/stub/__retain (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $~lib/rt/stub/__retain (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $infer-generic/inferEncapsulatedClass (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedClass (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/rt/stub/__retain drop local.get $0 ) - (func $~lib/rt/stub/__release (; 4 ;) (type $FUNCSIG$vi) (param $0 i32) + (func $~lib/rt/stub/__release (; 7 ;) (type $FUNCSIG$vi) (param $0 i32) nop ) - (func $infer-generic/test2 (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test2 (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) local.get $0 @@ -47,20 +71,23 @@ call $~lib/rt/stub/__release local.get $2 ) - (func $infer-generic/inferEncapsulatedFunction (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedFunction (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $infer-generic/test3 (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test3 (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $infer-generic/inferEncapsulatedFunction ) - (func $infer-generic/inferEncapsulatedFunctionMixed (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedFunctionMixed (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $infer-generic/test4 (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test4 (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $infer-generic/inferEncapsulatedFunctionMixed ) - (func $null (; 10 ;) (type $FUNCSIG$v) + (func $start (; 13 ;) (type $FUNCSIG$v) + call $start:infer-generic + ) + (func $null (; 14 ;) (type $FUNCSIG$v) ) ) From 61e1bd51a97271d672fbbe369558a46cd20ec3d7 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 11:18:19 +0200 Subject: [PATCH 3/9] always check min args --- src/compiler.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 91b0c2c306..7215b41248 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5863,16 +5863,16 @@ export class Compiler extends DiagnosticEmitter { // infer types with generic components while updating contextual types for (let i = 0; i < numParameters; ++i) { + let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer; + if (!argumentExpression) { // missing initializer -> too few arguments + this.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + expression.range, numParameters.toString(10), numArguments.toString(10) + ); + return module.unreachable(); + } let typeNode = parameterNodes[i].type; if (typeNode.hasGeneric(typeParameterNodes)) { - let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer; - if (!argumentExpression) { // missing initializer -> too few arguments - this.error( - DiagnosticCode.Expected_0_arguments_but_got_1, - expression.range, numParameters.toString(10), numArguments.toString(10) - ); - return module.unreachable(); - } this.resolver.inferGenericType(typeNode, argumentExpression, flow, contextualTypeArguments, typeParameterNames); } } From 789e097bdf514881cc9427bc00a645235c6e20dd Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 11:19:31 +0200 Subject: [PATCH 4/9] better name --- src/ast.ts | 10 +++++----- src/compiler.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index fc672f3936..57ded93d56 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1089,14 +1089,14 @@ export abstract class TypeNode extends Node { isNullable: bool; /** Tests if this type has a generic component matching one of the given type parameters. */ - hasGeneric(typeParameterNodes: TypeParameterNode[]): bool { + hasGenericComponent(typeParameterNodes: TypeParameterNode[]): bool { var self = this; // TS otherwise complains if (this.kind == NodeKind.NAMEDTYPE) { if (!(self).name.next) { let typeArgumentNodes = (self).typeArguments; if (typeArgumentNodes !== null && typeArgumentNodes.length) { for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) { - if (typeArgumentNodes[i].hasGeneric(typeParameterNodes)) return true; + if (typeArgumentNodes[i].hasGenericComponent(typeParameterNodes)) return true; } } else { let name = (self).name.identifier.text; @@ -1108,11 +1108,11 @@ export abstract class TypeNode extends Node { } else if (this.kind == NodeKind.FUNCTIONTYPE) { let parameterNodes = (self).parameters; for (let i = 0, k = parameterNodes.length; i < k; ++i) { - if (parameterNodes[i].type.hasGeneric(typeParameterNodes)) return true; + if (parameterNodes[i].type.hasGenericComponent(typeParameterNodes)) return true; } - if ((self).returnType.hasGeneric(typeParameterNodes)) return true; + if ((self).returnType.hasGenericComponent(typeParameterNodes)) return true; let explicitThisType = (self).explicitThisType; - if (explicitThisType !== null && explicitThisType.hasGeneric(typeParameterNodes)) return true; + if (explicitThisType !== null && explicitThisType.hasGenericComponent(typeParameterNodes)) return true; } else { assert(false); } diff --git a/src/compiler.ts b/src/compiler.ts index 7215b41248..fca928f76b 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5872,7 +5872,7 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } let typeNode = parameterNodes[i].type; - if (typeNode.hasGeneric(typeParameterNodes)) { + if (typeNode.hasGenericComponent(typeParameterNodes)) { this.resolver.inferGenericType(typeNode, argumentExpression, flow, contextualTypeArguments, typeParameterNames); } } From 709299dc9ee5984650143dbaa2fd4366beb6e289 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 22:47:27 +0200 Subject: [PATCH 5/9] can compile normally now --- src/compiler.ts | 22 ++---------- src/resolver.ts | 14 +++++++- tests/compiler/call-inferred.optimized.wat | 36 ++++++++++++++++++- tests/compiler/call-inferred.untouched.wat | 28 ++++++++++++--- tests/compiler/infer-generic.untouched.wat | 9 ++--- tests/compiler/number.untouched.wat | 16 +++------ tests/compiler/resolve-access.untouched.wat | 24 +++---------- tests/compiler/resolve-binary.untouched.wat | 8 ----- .../resolve-function-expression.untouched.wat | 16 +++------ tests/compiler/resolve-unary.untouched.wat | 16 +++------ 10 files changed, 92 insertions(+), 97 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index fca928f76b..86280d647f 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5843,15 +5843,15 @@ export class Compiler extends DiagnosticEmitter { // infer generic call if type arguments have been omitted } else if (prototype.is(CommonFlags.GENERIC)) { - - // initialize contextual types with auto for each generic component let contextualTypeArguments = makeMap(flow.contextualTypeArguments); + + // fill up contextual types with auto for each generic component let typeParameterNodes = assert(prototype.typeParameterNodes); let numTypeParameters = typeParameterNodes.length; let typeParameterNames = new Set(); for (let i = 0; i < numTypeParameters; ++i) { let name = typeParameterNodes[i].name.text; - contextualTypeArguments.set(name, Type.auto); // T = auto + contextualTypeArguments.set(name, Type.auto); typeParameterNames.add(name); } @@ -5859,7 +5859,6 @@ export class Compiler extends DiagnosticEmitter { let numParameters = parameterNodes.length; let argumentNodes = expression.arguments; let numArguments = argumentNodes.length; - let argumentExprs = new Array(numArguments); // infer types with generic components while updating contextual types for (let i = 0; i < numParameters; ++i) { @@ -5877,15 +5876,6 @@ export class Compiler extends DiagnosticEmitter { } } - // use updated contextual types to resolve to concrete types and compile - for (let i = 0; i < numParameters; ++i) { - let typeNode = parameterNodes[i].type; - let type = this.resolver.resolveType(typeNode, flow.actualFunction, contextualTypeArguments); - if (!type) return module.unreachable(); - let argumentExpression = i < numArguments ? argumentNodes[i] : parameterNodes[i].initializer!; - argumentExprs[i] = this.compileExpression(argumentExpression, type, Constraints.CONV_IMPLICIT); - } - // apply concrete types to the generic function signature let resolvedTypeArguments = Array.create(numTypeParameters); for (let i = 0; i < numTypeParameters; ++i) { @@ -5910,12 +5900,6 @@ export class Compiler extends DiagnosticEmitter { resolvedTypeArguments, makeMap(flow.contextualTypeArguments) ); - if (!instance) return this.module.unreachable(); - if (prototype.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression); - return this.makeCallDirect(instance, argumentExprs, expression, contextualType == Type.void); - // TODO: this skips inlining because inlining requires compiling its temporary locals in - // the scope of the inlined flow. might need another mechanism to lock temp. locals early, - // so inlining can be performed in `makeCallDirect` instead? // otherwise resolve the non-generic call as usual } else { diff --git a/src/resolver.ts b/src/resolver.ts index c4669ccd42..76fa590fd5 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -985,7 +985,7 @@ export class Resolver extends DiagnosticEmitter { case NodeKind.TRUE: { return this.resolveIdentifierExpression( node, - ctxFlow, ctxFlow.actualFunction, reportMode + ctxFlow, ctxType, ctxFlow.actualFunction, reportMode ); } case NodeKind.THIS: { @@ -1095,11 +1095,23 @@ export class Resolver extends DiagnosticEmitter { node: IdentifierExpression, /** Flow to search for scoped locals. */ ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, /** Element to search. */ ctxElement: Element = ctxFlow.actualFunction, // differs for enums and namespaces /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { + switch (node.kind) { + case NodeKind.TRUE: + case NodeKind.FALSE: return Type.bool; + case NodeKind.NULL: { + let classReference = ctxType.classReference; + return ctxType.is(TypeFlags.REFERENCE) && classReference !== null + ? classReference.type.asNullable() + : this.program.options.usizeType; // TODO: anyref context? + } + } var element = this.lookupIdentifierExpression(node, ctxFlow, ctxElement, reportMode); if (!element) return null; var type = this.getTypeOfElement(element); diff --git a/tests/compiler/call-inferred.optimized.wat b/tests/compiler/call-inferred.optimized.wat index a9c60e8c7f..15efb2b570 100644 --- a/tests/compiler/call-inferred.optimized.wat +++ b/tests/compiler/call-inferred.optimized.wat @@ -1,9 +1,43 @@ (module + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) (type $FUNCSIG$v (func)) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (memory $0 1) (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00c\00a\00l\00l\00-\00i\00n\00f\00e\00r\00r\00e\00d\00.\00t\00s") + (global $~lib/argc (mut i32) (i32.const 0)) (export "memory" (memory $0)) - (func $start (; 0 ;) (type $FUNCSIG$v) + (start $start) + (func $start:call-inferred (; 1 ;) (type $FUNCSIG$v) + (local $0 f32) + i32.const 0 + global.set $~lib/argc + block $1of1 + block $0of1 + block $outOfRange + global.get $~lib/argc + br_table $0of1 $1of1 $outOfRange + end + unreachable + end + f32.const 42 + local.set $0 + end + local.get $0 + f32.const 42 + f32.ne + if + i32.const 0 + i32.const 24 + i32.const 13 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + ) + (func $start (; 2 ;) (type $FUNCSIG$v) + call $start:call-inferred + ) + (func $null (; 3 ;) (type $FUNCSIG$v) nop ) ) diff --git a/tests/compiler/call-inferred.untouched.wat b/tests/compiler/call-inferred.untouched.wat index 4d8f89f101..97e21b27ca 100644 --- a/tests/compiler/call-inferred.untouched.wat +++ b/tests/compiler/call-inferred.untouched.wat @@ -9,6 +9,7 @@ (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00c\00a\00l\00l\00-\00i\00n\00f\00e\00r\00r\00e\00d\00.\00t\00s\00") (table $0 1 funcref) (elem (i32.const 0) $null) + (global $~lib/argc (mut i32) (i32.const 0)) (export "memory" (memory $0)) (start $start) (func $call-inferred/foo (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) @@ -23,7 +24,22 @@ (func $call-inferred/bar (; 4 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) local.get $0 ) - (func $start:call-inferred (; 5 ;) (type $FUNCSIG$v) + (func $call-inferred/bar|trampoline (; 5 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + block $1of1 + block $0of1 + block $outOfRange + global.get $~lib/argc + br_table $0of1 $1of1 $outOfRange + end + unreachable + end + f32.const 42 + local.set $0 + end + local.get $0 + call $call-inferred/bar + ) + (func $start:call-inferred (; 6 ;) (type $FUNCSIG$v) i32.const 42 call $call-inferred/foo i32.const 42 @@ -63,8 +79,10 @@ call $~lib/builtins/abort unreachable end - f32.const 42 - call $call-inferred/bar + i32.const 0 + global.set $~lib/argc + f32.const 0 + call $call-inferred/bar|trampoline f32.const 42 f32.eq i32.eqz @@ -77,9 +95,9 @@ unreachable end ) - (func $start (; 6 ;) (type $FUNCSIG$v) + (func $start (; 7 ;) (type $FUNCSIG$v) call $start:call-inferred ) - (func $null (; 7 ;) (type $FUNCSIG$v) + (func $null (; 8 ;) (type $FUNCSIG$v) ) ) diff --git a/tests/compiler/infer-generic.untouched.wat b/tests/compiler/infer-generic.untouched.wat index 1fa2fb41f7..1221131126 100644 --- a/tests/compiler/infer-generic.untouched.wat +++ b/tests/compiler/infer-generic.untouched.wat @@ -56,20 +56,15 @@ ) (func $infer-generic/test2 (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) (local $1 i32) - (local $2 i32) local.get $0 call $~lib/rt/stub/__retain drop local.get $0 call $infer-generic/inferEncapsulatedClass - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release + local.set $1 local.get $0 call $~lib/rt/stub/__release - local.get $2 + local.get $1 ) (func $infer-generic/inferEncapsulatedFunction (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 diff --git a/tests/compiler/number.untouched.wat b/tests/compiler/number.untouched.wat index 123054e703..826eba3516 100644 --- a/tests/compiler/number.untouched.wat +++ b/tests/compiler/number.untouched.wat @@ -440,20 +440,12 @@ call $~lib/util/number/itoa32 return ) - (func $~lib/rt/stub/__release (; 8 ;) (type $FUNCSIG$vi) (param $0 i32) - nop - ) - (func $~lib/number/I32#toString (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) + (func $~lib/number/I32#toString (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 + ) + (func $~lib/rt/stub/__release (; 9 ;) (type $FUNCSIG$vi) (param $0 i32) + nop ) (func $~lib/string/String#get:length (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 diff --git a/tests/compiler/resolve-access.untouched.wat b/tests/compiler/resolve-access.untouched.wat index 9b5ee73455..bb0f2a3084 100644 --- a/tests/compiler/resolve-access.untouched.wat +++ b/tests/compiler/resolve-access.untouched.wat @@ -1937,20 +1937,12 @@ call $~lib/util/number/utoa64 return ) - (func $~lib/rt/stub/__release (; 15 ;) (type $FUNCSIG$vi) (param $0 i32) - nop - ) - (func $~lib/number/U64#toString (; 16 ;) (type $FUNCSIG$ij) (param $0 i64) (result i32) - (local $1 i32) - (local $2 i32) + (func $~lib/number/U64#toString (; 15 ;) (type $FUNCSIG$ij) (param $0 i64) (result i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 + ) + (func $~lib/rt/stub/__release (; 16 ;) (type $FUNCSIG$vi) (param $0 i32) + nop ) (func $resolve-access/arrayAccess (; 17 ;) (type $FUNCSIG$i) (result i32) (local $0 i32) @@ -2054,16 +2046,8 @@ return ) (func $~lib/number/U32#toString (; 23 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 ) (func $resolve-access/propertyAccess (; 24 ;) (type $FUNCSIG$i) (result i32) (local $0 i32) diff --git a/tests/compiler/resolve-binary.untouched.wat b/tests/compiler/resolve-binary.untouched.wat index b758892828..b3292d57da 100644 --- a/tests/compiler/resolve-binary.untouched.wat +++ b/tests/compiler/resolve-binary.untouched.wat @@ -615,16 +615,8 @@ return ) (func $~lib/number/I32#toString (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 ) (func $~lib/math/NativeMath.scalbn (; 14 ;) (type $FUNCSIG$ddi) (param $0 f64) (param $1 i32) (result f64) (local $2 f64) diff --git a/tests/compiler/resolve-function-expression.untouched.wat b/tests/compiler/resolve-function-expression.untouched.wat index 4b897ebc8a..975bb7a130 100644 --- a/tests/compiler/resolve-function-expression.untouched.wat +++ b/tests/compiler/resolve-function-expression.untouched.wat @@ -415,20 +415,12 @@ call $~lib/util/number/itoa32 return ) - (func $~lib/rt/stub/__release (; 11 ;) (type $FUNCSIG$vi) (param $0 i32) - nop - ) - (func $~lib/number/I32#toString (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) + (func $~lib/number/I32#toString (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 + ) + (func $~lib/rt/stub/__release (; 12 ;) (type $FUNCSIG$vi) (param $0 i32) + nop ) (func $~lib/string/String#get:length (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 diff --git a/tests/compiler/resolve-unary.untouched.wat b/tests/compiler/resolve-unary.untouched.wat index d50da7ed2b..189238ada3 100644 --- a/tests/compiler/resolve-unary.untouched.wat +++ b/tests/compiler/resolve-unary.untouched.wat @@ -416,20 +416,12 @@ call $~lib/util/number/itoa32 return ) - (func $~lib/rt/stub/__release (; 8 ;) (type $FUNCSIG$vi) (param $0 i32) - nop - ) - (func $~lib/number/I32#toString (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) + (func $~lib/number/I32#toString (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release - local.get $2 + ) + (func $~lib/rt/stub/__release (; 9 ;) (type $FUNCSIG$vi) (param $0 i32) + nop ) (func $~lib/string/String#get:length (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 From ce496ca682bbea1d7c0268f35c4a5b3bb5f444ba Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 23:04:41 +0200 Subject: [PATCH 6/9] add test --- tests/compiler/infer-generic.optimized.wat | 68 ++++++++++- tests/compiler/infer-generic.ts | 6 + tests/compiler/infer-generic.untouched.wat | 126 +++++++++++++++++---- 3 files changed, 175 insertions(+), 25 deletions(-) diff --git a/tests/compiler/infer-generic.optimized.wat b/tests/compiler/infer-generic.optimized.wat index 483f6416cb..8da77f7349 100644 --- a/tests/compiler/infer-generic.optimized.wat +++ b/tests/compiler/infer-generic.optimized.wat @@ -1,21 +1,81 @@ (module + (type $FUNCSIG$iifii (func (param i32 f32 i32 i32) (result i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$v (func)) (type $FUNCSIG$ff (func (param f32) (result f32))) - (type $FUNCSIG$ii (func (param i32) (result i32))) (memory $0 1) (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00i\00n\00f\00e\00r\00-\00g\00e\00n\00e\00r\00i\00c\00.\00t\00s") + (data (i32.const 56) "\0c\00\00\00\01\00\00\00\00\00\00\00\0c\00\00\00\00\00\80?\00\00\00@\00\00@@") + (data (i32.const 88) "\10\00\00\00\01\00\00\00\03\00\00\00\10\00\00\00H\00\00\00H\00\00\00\0c\00\00\00\03") + (table $0 2 funcref) + (elem (i32.const 0) $null $start:infer-generic~anonymous|0) + (global $~lib/argc (mut i32) (i32.const 0)) (export "memory" (memory $0)) (export "test1" (func $infer-generic/test1)) (export "test2" (func $infer-generic/test2)) (export "test3" (func $infer-generic/test2)) (export "test4" (func $infer-generic/test2)) - (func $infer-generic/test1 (; 0 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + (start $start) + (func $start:infer-generic~anonymous|0 (; 0 ;) (type $FUNCSIG$iifii) (param $0 i32) (param $1 f32) (param $2 i32) (param $3 i32) (result i32) + local.get $1 + f32.const 0 + f32.ne + i32.const 0 + local.get $0 + select + ) + (func $~lib/array/Array#reduce (; 1 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + i32.const 116 + i32.load + local.set $1 + loop $loop|0 + local.get $0 + local.get $1 + i32.const 116 + i32.load + local.tee $2 + local.get $1 + local.get $2 + i32.lt_s + select + i32.lt_s + if + i32.const 4 + global.set $~lib/argc + local.get $3 + i32.const 108 + i32.load + local.get $0 + i32.const 2 + i32.shl + i32.add + f32.load + local.get $0 + i32.const 104 + call $start:infer-generic~anonymous|0 + local.set $3 + local.get $0 + i32.const 1 + i32.add + local.set $0 + br $loop|0 + end + end + ) + (func $infer-generic/test1 (; 2 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) local.get $0 ) - (func $infer-generic/test2 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test2 (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $start (; 2 ;) (type $FUNCSIG$v) + (func $start (; 4 ;) (type $FUNCSIG$v) + call $~lib/array/Array#reduce + ) + (func $null (; 5 ;) (type $FUNCSIG$v) nop ) ) diff --git a/tests/compiler/infer-generic.ts b/tests/compiler/infer-generic.ts index ece3a9147a..53b54dcde5 100644 --- a/tests/compiler/infer-generic.ts +++ b/tests/compiler/infer-generic.ts @@ -44,3 +44,9 @@ function inferCompatible(a: T, b: T): bool { return a == b; } assert(inferCompatible(1, 1.0)); + +// should work with function expressions with omitted types +// if all types can be inferred from other arguments + +const arr: f32[] = [1.0, 2.0, 3.0]; +arr.reduce(((arr, cur) => arr && cur != 0), false); diff --git a/tests/compiler/infer-generic.untouched.wat b/tests/compiler/infer-generic.untouched.wat index 1221131126..296df99d33 100644 --- a/tests/compiler/infer-generic.untouched.wat +++ b/tests/compiler/infer-generic.untouched.wat @@ -1,15 +1,21 @@ (module (type $FUNCSIG$idd (func (param f64 f64) (result i32))) (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) - (type $FUNCSIG$v (func)) - (type $FUNCSIG$ff (func (param f32) (result f32))) + (type $FUNCSIG$iifii (func (param i32 f32 i32 i32) (result i32))) (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$ff (func (param f32) (result f32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (memory $0 1) (data (i32.const 8) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00i\00n\00f\00e\00r\00-\00g\00e\00n\00e\00r\00i\00c\00.\00t\00s\00") - (table $0 1 funcref) - (elem (i32.const 0) $null) + (data (i32.const 56) "\0c\00\00\00\01\00\00\00\00\00\00\00\0c\00\00\00\00\00\80?\00\00\00@\00\00@@") + (data (i32.const 88) "\10\00\00\00\01\00\00\00\03\00\00\00\10\00\00\00H\00\00\00H\00\00\00\0c\00\00\00\03\00\00\00") + (table $0 2 funcref) + (elem (i32.const 0) $null $start:infer-generic~anonymous|0) + (global $infer-generic/arr i32 (i32.const 104)) + (global $~lib/argc (mut i32) (i32.const 0)) (export "memory" (memory $0)) (export "test1" (func $infer-generic/test1)) (export "test2" (func $infer-generic/test2)) @@ -21,7 +27,86 @@ local.get $1 f64.eq ) - (func $start:infer-generic (; 2 ;) (type $FUNCSIG$v) + (func $~lib/rt/stub/__retain (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $~lib/rt/stub/__release (; 3 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $start:infer-generic~anonymous|0 (; 4 ;) (type $FUNCSIG$iifii) (param $0 i32) (param $1 f32) (param $2 i32) (param $3 i32) (result i32) + (local $4 i32) + local.get $3 + call $~lib/rt/stub/__retain + drop + local.get $0 + if (result i32) + local.get $1 + f32.const 0 + f32.ne + else + i32.const 0 + end + local.set $4 + local.get $3 + call $~lib/rt/stub/__release + local.get $4 + ) + (func $~lib/array/Array#reduce (; 5 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + local.get $2 + local.set $3 + block $break|0 + i32.const 0 + local.set $4 + local.get $0 + i32.load offset=12 + local.set $5 + loop $loop|0 + local.get $4 + local.get $5 + local.tee $6 + local.get $0 + i32.load offset=12 + local.tee $7 + local.get $6 + local.get $7 + i32.lt_s + select + i32.lt_s + i32.eqz + br_if $break|0 + i32.const 4 + global.set $~lib/argc + local.get $3 + local.get $0 + i32.load offset=4 + local.get $4 + i32.const 2 + i32.shl + i32.add + f32.load + local.get $4 + local.get $0 + local.get $1 + call_indirect (type $FUNCSIG$iifii) + local.set $3 + local.get $4 + i32.const 1 + i32.add + local.set $4 + br $loop|0 + end + unreachable + end + local.get $3 + ) + (func $start:infer-generic (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) f64.const 1 f64.const 1 call $infer-generic/inferCompatible @@ -34,27 +119,26 @@ call $~lib/builtins/abort unreachable end + global.get $infer-generic/arr + i32.const 1 + i32.const 0 + call $~lib/array/Array#reduce + drop ) - (func $infer-generic/inferPlain (; 3 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + (func $infer-generic/inferPlain (; 7 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) local.get $0 ) - (func $infer-generic/test1 (; 4 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) + (func $infer-generic/test1 (; 8 ;) (type $FUNCSIG$ff) (param $0 f32) (result f32) local.get $0 call $infer-generic/inferPlain ) - (func $~lib/rt/stub/__retain (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - local.get $0 - ) - (func $infer-generic/inferEncapsulatedClass (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedClass (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/rt/stub/__retain drop local.get $0 ) - (func $~lib/rt/stub/__release (; 7 ;) (type $FUNCSIG$vi) (param $0 i32) - nop - ) - (func $infer-generic/test2 (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test2 (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) (local $1 i32) local.get $0 call $~lib/rt/stub/__retain @@ -66,23 +150,23 @@ call $~lib/rt/stub/__release local.get $1 ) - (func $infer-generic/inferEncapsulatedFunction (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedFunction (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $infer-generic/test3 (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test3 (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $infer-generic/inferEncapsulatedFunction ) - (func $infer-generic/inferEncapsulatedFunctionMixed (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/inferEncapsulatedFunctionMixed (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 ) - (func $infer-generic/test4 (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (func $infer-generic/test4 (; 14 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $infer-generic/inferEncapsulatedFunctionMixed ) - (func $start (; 13 ;) (type $FUNCSIG$v) + (func $start (; 15 ;) (type $FUNCSIG$v) call $start:infer-generic ) - (func $null (; 14 ;) (type $FUNCSIG$v) + (func $null (; 16 ;) (type $FUNCSIG$v) ) ) From 33df490b07f2a1529345e1349a068e37afbe4601 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 23:05:15 +0200 Subject: [PATCH 7/9] typo --- tests/compiler/infer-generic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiler/infer-generic.ts b/tests/compiler/infer-generic.ts index 53b54dcde5..fc8e5aedc7 100644 --- a/tests/compiler/infer-generic.ts +++ b/tests/compiler/infer-generic.ts @@ -49,4 +49,4 @@ assert(inferCompatible(1, 1.0)); // if all types can be inferred from other arguments const arr: f32[] = [1.0, 2.0, 3.0]; -arr.reduce(((arr, cur) => arr && cur != 0), false); +arr.reduce(((acc, cur) => acc && cur != 0), false); From 94186c7168473af1b3a957914c25e09444c74156 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 13 Sep 2019 23:26:49 +0200 Subject: [PATCH 8/9] merge --- tests/compiler/resolve-ternary.optimized.wat | 84 +++++++------ tests/compiler/resolve-ternary.untouched.wat | 118 +++++++++---------- 2 files changed, 95 insertions(+), 107 deletions(-) diff --git a/tests/compiler/resolve-ternary.optimized.wat b/tests/compiler/resolve-ternary.optimized.wat index 0672841651..52400e9277 100644 --- a/tests/compiler/resolve-ternary.optimized.wat +++ b/tests/compiler/resolve-ternary.optimized.wat @@ -39,7 +39,6 @@ (global $~lib/rt/pure/CUR (mut i32) (i32.const 0)) (global $~lib/rt/pure/END (mut i32) (i32.const 0)) (global $~lib/rt/pure/ROOTS (mut i32) (i32.const 0)) - (global $resolve-ternary/b i32 (i32.const 1)) (global $~lib/util/number/_frc_plus (mut i64) (i64.const 0)) (global $~lib/util/number/_frc_minus (mut i64) (i64.const 0)) (global $~lib/util/number/_exp (mut i32) (i32.const 0)) @@ -84,7 +83,7 @@ local.get $2 i32.const 1073741808 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -105,7 +104,7 @@ i32.shr_u local.set $2 i32.const 0 - else + else local.get $2 i32.const 31 local.get $2 @@ -129,7 +128,7 @@ local.get $2 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -350,7 +349,7 @@ local.tee $3 i32.store local.get $2 - else + else local.get $1 end local.set $1 @@ -370,7 +369,7 @@ local.get $2 i32.const 1073741808 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -411,7 +410,7 @@ i32.shr_u local.set $4 i32.const 0 - else + else local.get $2 i32.const 31 local.get $2 @@ -435,7 +434,7 @@ local.get $4 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -564,7 +563,7 @@ i32.sub local.set $1 end - else + else local.get $1 local.get $0 i32.const 1572 @@ -634,7 +633,7 @@ memory.grow i32.const 0 i32.lt_s - else + else i32.const 0 end if @@ -738,7 +737,7 @@ i32.shr_u local.set $1 i32.const 0 - else + else local.get $1 i32.const 536870904 i32.lt_u @@ -778,7 +777,7 @@ local.get $1 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -813,7 +812,7 @@ local.get $0 i32.add i32.load offset=96 - else + else local.get $0 i32.load i32.const -1 @@ -853,7 +852,7 @@ local.get $0 i32.add i32.load offset=96 - else + else i32.const 0 end end @@ -968,7 +967,7 @@ local.get $0 local.get $1 call $~lib/rt/tlsf/insertBlock - else + else local.get $1 local.get $3 i32.const -2 @@ -1059,7 +1058,7 @@ local.tee $2 if (result i32) local.get $2 - else + else call $~lib/rt/tlsf/initializeRoot global.get $~lib/rt/tlsf/ROOT end @@ -1268,7 +1267,7 @@ br $continue|2 end end - else + else local.get $1 i32.const 7 i32.and @@ -1472,12 +1471,12 @@ local.get $0 i32.const -2147483648 i32.store offset=4 - else + else global.get $~lib/rt/tlsf/ROOT local.get $0 call $~lib/rt/tlsf/freeBlock end - else + else local.get $1 i32.const 0 i32.le_u @@ -1504,7 +1503,7 @@ i32.and i32.or i32.store offset=4 - else + else local.get $0 local.get $1 i32.const 1 @@ -1589,7 +1588,7 @@ if local.get $0 call $~lib/rt/pure/scanBlack - else + else local.get $0 local.get $1 i32.const -1879048193 @@ -1619,7 +1618,7 @@ i32.const -2147483648 i32.and i32.eqz - else + else i32.const 0 end if @@ -1672,7 +1671,7 @@ i32.and i32.const 0 i32.gt_u - else + else i32.const 0 end if @@ -1685,7 +1684,7 @@ i32.const 4 i32.add local.set $2 - else + else i32.const 0 local.get $1 i32.const 268435455 @@ -1699,7 +1698,7 @@ global.get $~lib/rt/tlsf/ROOT local.get $4 call $~lib/rt/tlsf/freeBlock - else + else local.get $4 local.get $1 i32.const 2147483647 @@ -1912,7 +1911,7 @@ i32.sub local.tee $5 i32.eqz - else + else i32.const 0 end if @@ -2417,7 +2416,7 @@ local.get $3 i32.const 21 i32.le_s - else + else i32.const 0 end if (result i32) @@ -2451,7 +2450,7 @@ local.get $3 i32.const 2 i32.add - else + else local.get $3 i32.const 21 i32.le_s @@ -2482,7 +2481,7 @@ local.get $1 i32.const 1 i32.add - else + else local.get $3 i32.const 0 i32.le_s @@ -2533,7 +2532,7 @@ local.get $1 local.get $3 i32.add - else + else local.get $1 i32.const 1 i32.eq @@ -2574,7 +2573,7 @@ local.get $2 i32.const 2 i32.add - else + else local.get $0 i32.const 4 i32.add @@ -2977,7 +2976,7 @@ local.get $3 if (result i32) i32.const 0 - else + else local.get $0 call $~lib/string/String#get:length i32.const 1 @@ -3082,15 +3081,11 @@ (local $2 i32) i32.const 1 i32.const 2 - global.get $resolve-ternary/b + i32.const 1 select call $~lib/util/number/itoa32 local.tee $0 - call $~lib/rt/pure/__retain - local.set $1 local.get $0 - call $~lib/rt/pure/__release - local.get $1 i32.const 296 call $~lib/string/String.__eq i32.eqz @@ -3104,11 +3099,12 @@ end f64.const 1 f64.const 2 - global.get $resolve-ternary/b + i32.const 1 select call $~lib/util/number/dtoa - local.tee $2 - local.get $2 + local.tee $0 + local.set $2 + local.get $0 i32.const 1568 call $~lib/string/String.__eq i32.eqz @@ -3125,7 +3121,7 @@ i32.const 1 i32.const 1 i32.const 2 - global.get $resolve-ternary/b + i32.const 1 select call_indirect (type $FUNCSIG$ii) i32.const 2 @@ -3143,7 +3139,7 @@ i32.const 1 i32.const 3 i32.const 4 - global.get $resolve-ternary/b + i32.const 1 select call_indirect (type $FUNCSIG$ii) i32.const 4 @@ -3161,7 +3157,7 @@ i32.const 1 i32.const 2 i32.const 4 - global.get $resolve-ternary/b + i32.const 1 select call_indirect (type $FUNCSIG$ii) i32.const 3 @@ -3174,8 +3170,8 @@ call $~lib/builtins/abort unreachable end - local.get $1 call $~lib/rt/pure/__release + local.get $2 call $~lib/rt/pure/__release ) (func $start (; 42 ;) (type $FUNCSIG$v) diff --git a/tests/compiler/resolve-ternary.untouched.wat b/tests/compiler/resolve-ternary.untouched.wat index fe0e360e3a..ceb48b8707 100644 --- a/tests/compiler/resolve-ternary.untouched.wat +++ b/tests/compiler/resolve-ternary.untouched.wat @@ -103,7 +103,7 @@ local.get $3 i32.const 1073741808 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -125,7 +125,7 @@ i32.const 4 i32.shr_u local.set $5 - else + else i32.const 31 local.get $3 i32.clz @@ -155,7 +155,7 @@ local.get $5 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -456,7 +456,7 @@ local.get $8 i32.const 1073741808 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -499,7 +499,7 @@ i32.const 4 i32.shr_u local.set $10 - else + else i32.const 31 local.get $8 i32.clz @@ -529,7 +529,7 @@ local.get $10 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -640,7 +640,7 @@ i32.const 15 i32.and i32.eqz - else + else i32.const 0 end if (result i32) @@ -648,7 +648,7 @@ i32.const 15 i32.and i32.eqz - else + else i32.const 0 end i32.eqz @@ -696,10 +696,10 @@ local.get $4 i32.load local.set $5 - else + else nop end - else + else local.get $1 local.get $0 i32.const 1572 @@ -815,7 +815,7 @@ memory.grow i32.const 0 i32.lt_s - else + else i32.const 0 end if @@ -965,7 +965,7 @@ i32.const 4 i32.shr_u local.set $3 - else + else local.get $1 i32.const 536870904 i32.lt_u @@ -980,7 +980,7 @@ i32.add i32.const 1 i32.sub - else + else local.get $1 end local.set $4 @@ -1013,7 +1013,7 @@ local.get $3 i32.const 16 i32.lt_u - else + else i32.const 0 end i32.eqz @@ -1063,7 +1063,7 @@ if i32.const 0 local.set $7 - else + else local.get $5 i32.ctz local.set $2 @@ -1107,7 +1107,7 @@ i32.load offset=96 local.set $7 end - else + else local.get $0 local.set $9 local.get $2 @@ -1268,7 +1268,7 @@ local.get $0 local.get $5 call $~lib/rt/tlsf/insertBlock - else + else local.get $1 local.get $3 i32.const 1 @@ -1510,7 +1510,7 @@ local.get $1 i32.const 3 i32.and - else + else i32.const 0 end i32.eqz @@ -2552,7 +2552,7 @@ i32.le_u if (result i32) i32.const 1 - else + else local.get $5 local.get $3 i32.add @@ -2667,7 +2667,7 @@ end unreachable end - else + else local.get $4 i32.const 7 i32.and @@ -2771,7 +2771,7 @@ i32.const 15 i32.and i32.eqz - else + else i32.const 0 end i32.eqz @@ -2900,7 +2900,7 @@ global.get $~lib/rt/tlsf/ROOT local.get $0 call $~lib/rt/tlsf/freeBlock - else + else local.get $0 i32.const -2147483648 i32.const 0 @@ -2909,7 +2909,7 @@ i32.or i32.store offset=4 end - else + else local.get $2 i32.const 0 i32.gt_u @@ -2946,7 +2946,7 @@ local.get $0 call $~lib/rt/pure/appendRoot end - else + else local.get $0 local.get $1 i32.const 268435455 @@ -3035,7 +3035,7 @@ if local.get $0 call $~lib/rt/pure/scanBlack - else + else local.get $0 local.get $1 i32.const 1879048192 @@ -3068,7 +3068,7 @@ i32.const -2147483648 i32.and i32.eqz - else + else i32.const 0 end if @@ -3130,7 +3130,7 @@ i32.and i32.const 0 i32.gt_u - else + else i32.const 0 end if @@ -3143,7 +3143,7 @@ i32.const 4 i32.add local.set $1 - else + else local.get $5 i32.const 1879048192 i32.and @@ -3154,14 +3154,14 @@ i32.const 268435455 i32.and i32.eqz - else + else i32.const 0 end if global.get $~lib/rt/tlsf/ROOT local.get $4 call $~lib/rt/tlsf/freeBlock - else + else local.get $4 local.get $5 i32.const -2147483648 @@ -3251,7 +3251,7 @@ i32.lt_u select return - else + else i32.const 4 i32.const 5 local.get $0 @@ -3268,7 +3268,7 @@ return end unreachable - else + else local.get $0 i32.const 10000000 i32.lt_u @@ -3280,7 +3280,7 @@ i32.lt_u select return - else + else i32.const 9 i32.const 10 local.get $0 @@ -3424,7 +3424,7 @@ i32.add local.get $5 i32.store - else + else local.get $2 i32.const 1 i32.sub @@ -3503,16 +3503,8 @@ return ) (func $~lib/number/I32#toString (; 31 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - (local $1 i32) - (local $2 i32) local.get $0 call $~lib/util/number/itoa - local.tee $1 - call $~lib/rt/pure/__retain - local.set $2 - local.get $1 - call $~lib/rt/pure/__release - local.get $2 ) (func $~lib/string/String#get:length (; 32 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 @@ -3558,7 +3550,7 @@ i32.sub local.tee $5 i32.eqz - else + else i32.const 0 end i32.eqz @@ -3614,7 +3606,7 @@ i32.eq if (result i32) i32.const 1 - else + else local.get $1 i32.const 0 i32.eq @@ -3994,7 +3986,7 @@ i64.sub local.get $21 i64.ge_u - else + else i32.const 0 end if (result i32) @@ -4005,7 +3997,7 @@ i64.lt_u if (result i32) i32.const 1 - else + else local.get $20 local.get $22 i64.sub @@ -4016,7 +4008,7 @@ i64.sub i64.gt_u end - else + else i32.const 0 end i32.eqz @@ -4143,7 +4135,7 @@ i64.sub local.get $21 i64.ge_u - else + else i32.const 0 end if (result i32) @@ -4154,7 +4146,7 @@ i64.lt_u if (result i32) i32.const 1 - else + else local.get $20 local.get $22 i64.sub @@ -4165,7 +4157,7 @@ i64.sub i64.gt_u end - else + else i32.const 0 end i32.eqz @@ -4232,7 +4224,7 @@ local.get $3 i32.const 21 i32.le_s - else + else i32.const 0 end if @@ -4275,7 +4267,7 @@ i32.const 2 i32.add return - else + else local.get $3 i32.const 0 i32.gt_s @@ -4283,7 +4275,7 @@ local.get $3 i32.const 21 i32.le_s - else + else i32.const 0 end if @@ -4314,7 +4306,7 @@ i32.const 1 i32.add return - else + else i32.const -6 local.get $3 i32.lt_s @@ -4322,7 +4314,7 @@ local.get $3 i32.const 0 i32.le_s - else + else i32.const 0 end if @@ -4375,7 +4367,7 @@ local.get $4 i32.add return - else + else local.get $1 i32.const 1 i32.eq @@ -4429,7 +4421,7 @@ i32.const 2 i32.add return - else + else local.get $1 i32.const 1 i32.shl @@ -5019,7 +5011,7 @@ i32.const 1 i32.shl i32.eq - else + else i32.const 0 end if @@ -5129,7 +5121,7 @@ global.get $resolve-ternary/b if (result i32) i32.const 1 - else + else i32.const 2 end call $~lib/number/I32#toString @@ -5148,7 +5140,7 @@ global.get $resolve-ternary/b if (result f64) f64.const 1 - else + else f64.const 2 end i32.const 0 @@ -5171,7 +5163,7 @@ global.get $resolve-ternary/b if (result i32) i32.const 1 - else + else i32.const 2 end call_indirect (type $FUNCSIG$ii) @@ -5192,7 +5184,7 @@ global.get $resolve-ternary/b if (result i32) i32.const 3 - else + else i32.const 4 end call_indirect (type $FUNCSIG$ii) @@ -5213,7 +5205,7 @@ global.get $resolve-ternary/b if (result i32) i32.const 2 - else + else i32.const 4 end call_indirect (type $FUNCSIG$ii) From 57376d4261fbee73745162b9b8972ea29e62dc8b Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 14 Sep 2019 21:20:23 +0200 Subject: [PATCH 9/9] fix binaryen version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c91807258a..7d4f764b6a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@protobufjs/utf8": "^1.1.0", - "binaryen": "^89.0.0-nightly.20190914", + "binaryen": "89.0.0-nightly.20190914", "glob": "^7.1.4", "long": "^4.0.0", "opencollective-postinstall": "^2.0.0",