Add an error for missing initializers on default params, fixes #121; Fix detection of terminated switch cases and improve tests, fixes #122

This commit is contained in:
dcodeIO 2018-05-27 12:24:16 +02:00
parent 113925fa7e
commit d0244a9b0f
9 changed files with 1366 additions and 148 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1468,7 +1468,7 @@ export class Compiler extends DiagnosticEmitter {
let stmt = this.compileStatement(statements[i]);
if (getExpressionId(stmt) != ExpressionId.Nop) {
stmts[count++] = stmt;
if (flow.isAny(FlowFlags.BREAKS | FlowFlags.CONTINUES | FlowFlags.RETURNS)) break;
if (flow.isAny(FlowFlags.TERMINATED)) break;
}
}
stmts.length = count;
@ -1774,14 +1774,18 @@ export class Compiler extends DiagnosticEmitter {
var module = this.module;
var currentFunction = this.currentFunction;
var cases = statement.cases;
var numCases = cases.length;
if (!numCases) {
return this.compileExpression(statement.condition, Type.void, ConversionKind.IMPLICIT, WrapMode.NONE);
}
// Everything within a switch uses the same break context
var context = currentFunction.enterBreakContext();
// introduce a local for evaluating the condition (exactly once)
var tempLocal = currentFunction.getTempLocal(Type.u32, false);
var tempLocalIndex = tempLocal.index;
var cases = statement.cases;
var numCases = cases.length;
// Prepend initializer to inner block. Does not initiate a new branch, yet.
var breaks = new Array<ExpressionRef>(1 + numCases);
@ -1833,31 +1837,37 @@ export class Compiler extends DiagnosticEmitter {
let breakLabel = "break|" + context;
flow.breakLabel = breakLabel;
let fallsThrough = i != numCases - 1;
let nextLabel = !fallsThrough ? breakLabel : "case" + (i + 1).toString(10) + "|" + context;
let isLast = i == numCases - 1;
let nextLabel = isLast ? breakLabel : "case" + (i + 1).toString(10) + "|" + context;
let stmts = new Array<ExpressionRef>(1 + numStatements);
stmts[0] = currentBlock;
let count = 1;
let terminated = false;
for (let j = 0; j < numStatements; ++j) {
let stmt = this.compileStatement(statements[j]);
if (getExpressionId(stmt) != ExpressionId.Nop) {
stmts[count++] = stmt;
if (flow.is(FlowFlags.BREAKS | FlowFlags.CONTINUES | FlowFlags.RETURNS)) break;
if (flow.isAny(FlowFlags.TERMINATED)) {
terminated = true;
break;
}
}
}
stmts.length = count;
if (!(fallsThrough || flow.is(FlowFlags.RETURNS))) alwaysReturns = false; // ignore fall-throughs
if (!(fallsThrough || flow.is(FlowFlags.RETURNS_WRAPPED))) alwaysReturnsWrapped = false; // ignore fall-throughs
if (!(fallsThrough || flow.is(FlowFlags.THROWS))) alwaysThrows = false;
if (!(fallsThrough || flow.is(FlowFlags.ALLOCATES))) alwaysAllocates = false;
if (terminated || isLast) {
if (!flow.is(FlowFlags.RETURNS)) alwaysReturns = false;
if (!flow.is(FlowFlags.RETURNS_WRAPPED)) alwaysReturnsWrapped = false;
if (!flow.is(FlowFlags.THROWS)) alwaysThrows = false;
if (!flow.is(FlowFlags.ALLOCATES)) alwaysAllocates = false;
}
// Switch back to the parent flow
currentFunction.flow = flow.leaveBranchOrScope();
currentFunction.flow = flow.leaveBranchOrScope(false);
currentBlock = module.createBlock(nextLabel, stmts, NativeType.None); // must be a labeled block
}
currentFunction.leaveBreakContext();
// If the switch has a default and always returns, propagate that
// If the switch has a default (guaranteed to handle any value), propagate common flags
if (defaultIndex >= 0) {
let flow = currentFunction.flow;
if (alwaysReturns) flow.set(FlowFlags.RETURNS);
@ -5101,7 +5111,7 @@ export class Compiler extends DiagnosticEmitter {
let stmt = this.compileStatement(statements[i]);
if (getExpressionId(stmt) != ExpressionId.Nop) {
body.push(stmt);
if (flow.is(FlowFlags.RETURNS)) break;
if (flow.isAny(FlowFlags.TERMINATED)) break;
}
}
} else {
@ -5122,8 +5132,8 @@ export class Compiler extends DiagnosticEmitter {
this.currentFunction.flow = previousFlow;
this.currentType = returnType;
// Check that all branches return
if (returnType != Type.void && !flow.is(FlowFlags.RETURNS)) {
// Check that all branches are terminated
if (returnType != Type.void && !flow.isAny(FlowFlags.TERMINATED)) {
this.error(
DiagnosticCode.A_function_whose_declared_type_is_not_void_must_return_a_value,
declaration.signature.returnType.range
@ -5224,16 +5234,28 @@ export class Compiler extends DiagnosticEmitter {
]);
for (let i = 0; i < numOptional; ++i, ++operandIndex) {
let type = originalParameterTypes[minArguments + i];
body = module.createBlock(names[i + 1], [
body,
module.createSetLocal(operandIndex,
let declaration = originalParameterDeclarations[minArguments + i];
let initializer = declaration.initializer;
let initExpr: ExpressionRef;
if (initializer) {
initExpr = module.createSetLocal(operandIndex,
this.compileExpression(
assert(originalParameterDeclarations[minArguments + i].initializer),
initializer,
type,
ConversionKind.IMPLICIT,
WrapMode.WRAP
)
)
);
} else {
this.error(
DiagnosticCode.Optional_parameter_must_have_an_initializer,
declaration.range
);
initExpr = module.createUnreachable();
}
body = module.createBlock(names[i + 1], [
body,
initExpr,
]);
forwardedOperands[operandIndex] = module.createGetLocal(operandIndex, type.toNativeType());
}
@ -5326,9 +5348,10 @@ export class Compiler extends DiagnosticEmitter {
let parameterNodes = instance.prototype.declaration.signature.parameterTypes;
let allOptionalsAreConstant = true;
for (let i = numArguments; i < maxArguments; ++i) {
let initializer = assert(parameterNodes[i].initializer);
if (initializer.kind != NodeKind.LITERAL) {
let initializer = parameterNodes[i].initializer;
if (!(initializer && initializer.kind == NodeKind.LITERAL)) {
// TODO: other kinds might be constant as well
// NOTE: if the initializer is missing this is reported in ensureTrampoline below
allOptionalsAreConstant = false;
break;
}

View File

@ -24,6 +24,7 @@ export enum DiagnosticCode {
Decorator_0_is_not_valid_here = 212,
Duplicate_decorator = 213,
An_allocator_must_be_declared_to_allocate_memory_Try_importing_allocator_arena_or_allocator_tlsf = 214,
Optional_parameter_must_have_an_initializer = 215,
Unterminated_string_literal = 1002,
Identifier_expected = 1003,
_0_expected = 1005,
@ -133,6 +134,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 212: return "Decorator '{0}' is not valid here.";
case 213: return "Duplicate decorator.";
case 214: return "An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.";
case 215: return "Optional parameter must have an initializer.";
case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected.";
case 1005: return "'{0}' expected.";

View File

@ -16,6 +16,7 @@
"Decorator '{0}' is not valid here.": 212,
"Duplicate decorator.": 213,
"An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.": 214,
"Optional parameter must have an initializer.": 215,
"Unterminated string literal.": 1002,
"Identifier expected.": 1003,

View File

@ -3589,7 +3589,10 @@ export const enum FlowFlags {
/** This branch explicitly requests no bounds checking. */
UNCHECKED_CONTEXT = 1 << 11,
/** This branch returns a properly wrapped value. */
RETURNS_WRAPPED = 1 << 12
RETURNS_WRAPPED = 1 << 12,
/** This branch is terminated if any of these flags is set. */
TERMINATED = FlowFlags.RETURNS | FlowFlags.THROWS | FlowFlags.BREAKS | FlowFlags.CONTINUES
}
/** A control flow evaluator. */
@ -3639,7 +3642,7 @@ export class Flow {
/** Tests if this flow has the specified flag or flags. */
is(flag: FlowFlags): bool { return (this.flags & flag) == flag; }
/** Tests if this flow has one of the specified flags. */
isAny(flag: CommonFlags): bool { return (this.flags & flag) != 0; }
isAny(flag: FlowFlags): bool { return (this.flags & flag) != 0; }
/** Sets the specified flag or flags. */
set(flag: FlowFlags): void { this.flags |= flag; }
/** Unsets the specified flag or flags. */
@ -3662,7 +3665,7 @@ export class Flow {
}
/** Leaves the current branch or scope and returns the parent flow. */
leaveBranchOrScope(): Flow {
leaveBranchOrScope(propagate: bool = true): Flow {
var parent = assert(this.parent);
// Free block-scoped locals
@ -3676,22 +3679,23 @@ export class Flow {
}
// Propagate conditionaal flags to parent
if (this.is(FlowFlags.RETURNS)) {
parent.set(FlowFlags.CONDITIONALLY_RETURNS);
if (propagate) {
if (this.is(FlowFlags.RETURNS)) {
parent.set(FlowFlags.CONDITIONALLY_RETURNS);
}
if (this.is(FlowFlags.THROWS)) {
parent.set(FlowFlags.CONDITIONALLY_THROWS);
}
if (this.is(FlowFlags.BREAKS) && parent.breakLabel == this.breakLabel) {
parent.set(FlowFlags.CONDITIONALLY_BREAKS);
}
if (this.is(FlowFlags.CONTINUES) && parent.continueLabel == this.continueLabel) {
parent.set(FlowFlags.CONDITIONALLY_CONTINUES);
}
if (this.is(FlowFlags.ALLOCATES)) {
parent.set(FlowFlags.CONDITIONALLY_ALLOCATES);
}
}
if (this.is(FlowFlags.THROWS)) {
parent.set(FlowFlags.CONDITIONALLY_THROWS);
}
if (this.is(FlowFlags.BREAKS) && parent.breakLabel == this.breakLabel) {
parent.set(FlowFlags.CONDITIONALLY_BREAKS);
}
if (this.is(FlowFlags.CONTINUES) && parent.continueLabel == this.continueLabel) {
parent.set(FlowFlags.CONDITIONALLY_CONTINUES);
}
if (this.is(FlowFlags.ALLOCATES)) {
parent.set(FlowFlags.CONDITIONALLY_ALLOCATES);
}
return parent;
}

View File

@ -1,11 +1,13 @@
(module
(type $ii (func (param i32) (result i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $v (func))
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
(memory $0 1)
(export "doSwitch" (func $switch/doSwitch))
(export "doSwitchDefaultFirst" (func $switch/doSwitchDefaultFirst))
(export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted))
(data (i32.const 8) "\t\00\00\00s\00w\00i\00t\00c\00h\00.\00t\00s")
(export "memory" (memory $0))
(func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32)
(start $start)
(func $switch/doSwitch (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $case4|0
(block $case2|0
@ -47,40 +49,6 @@
)
(i32.const 23)
)
(func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $case3|0
(if
(i32.ne
(tee_local $1
(get_local $0)
)
(i32.const 1)
)
(block
(br_if $case3|0
(i32.or
(i32.eq
(get_local $1)
(i32.const 2)
)
(i32.eq
(get_local $1)
(i32.const 3)
)
)
)
(return
(i32.const 0)
)
)
)
(return
(i32.const 1)
)
)
(i32.const 23)
)
(func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
@ -118,4 +86,525 @@
)
(i32.const 0)
)
(func $switch/doSwitchBreakCase (; 3 ;) (type $ii) (param $0 i32) (result i32)
(if
(i32.ne
(get_local $0)
(i32.const 1)
)
(return
(i32.const 2)
)
)
(i32.const 1)
)
(func $switch/doSwitchBreakDefault (; 4 ;) (type $ii) (param $0 i32) (result i32)
(if
(i32.eq
(get_local $0)
(i32.const 1)
)
(return
(i32.const 1)
)
)
(i32.const 2)
)
(func $switch/doSwitchEmpty (; 5 ;) (type $ii) (param $0 i32) (result i32)
(i32.const 2)
)
(func $start (; 6 ;) (type $v)
(if
(call $switch/doSwitch
(i32.const 0)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 10)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 11)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 2)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 12)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 3)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 13)
(i32.const 0)
)
(unreachable)
)
)
(if
(call $switch/doSwitch
(i32.const 4)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 14)
(i32.const 0)
)
(unreachable)
)
)
(if
(call $switch/doSwitch
(i32.const 0)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 24)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 25)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 2)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 26)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitch
(i32.const 3)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 27)
(i32.const 0)
)
(unreachable)
)
)
(if
(call $switch/doSwitch
(i32.const 4)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 28)
(i32.const 0)
)
(unreachable)
)
)
(if
(call $switch/doSwitchDefaultOmitted
(i32.const 0)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 38)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchDefaultOmitted
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 39)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchDefaultOmitted
(i32.const 2)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 40)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchDefaultOmitted
(i32.const 3)
)
(i32.const 23)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 41)
(i32.const 0)
)
(unreachable)
)
)
(if
(call $switch/doSwitchDefaultOmitted
(i32.const 4)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 42)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 0)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 51)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 52)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 2)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 53)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 0)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 62)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 63)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 2)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 64)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 0)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 73)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 74)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakCase
(i32.const 2)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 75)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 0)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 84)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 1)
)
(i32.const 1)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 85)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchBreakDefault
(i32.const 2)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 86)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchEmpty
(i32.const 0)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 92)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchEmpty
(i32.const 1)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 93)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $switch/doSwitchEmpty
(i32.const 2)
)
(i32.const 2)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 94)
(i32.const 0)
)
(unreachable)
)
)
)
)

View File

@ -1,35 +1,94 @@
export function doSwitch(n: i32): i32 {
function doSwitch(n: i32): i32 {
switch (n) {
case 1:
return 1;
case 1: return 1;
case 0:
default:
return 0;
default: return 0;
case 2:
case 3:
return 23;
case 3: return 23;
}
}
assert(doSwitch(0) == 0);
assert(doSwitch(1) == 1);
assert(doSwitch(2) == 23);
assert(doSwitch(3) == 23);
assert(doSwitch(4) == 0);
export function doSwitchDefaultFirst(n: i32): i32 {
function doSwitchDefaultFirst(n: i32): i32 {
switch (n) {
default:
return 0;
case 1:
return 1;
default: return 0;
case 1: return 1;
case 2:
case 3:
return 23;
case 3: return 23;
}
}
assert(doSwitch(0) == 0);
assert(doSwitch(1) == 1);
assert(doSwitch(2) == 23);
assert(doSwitch(3) == 23);
assert(doSwitch(4) == 0);
export function doSwitchDefaultOmitted(n: i32): i32 {
function doSwitchDefaultOmitted(n: i32): i32 {
switch (n) {
case 1:
return 1;
case 1: return 1;
case 2:
case 3:
return 23;
case 3: return 23;
}
return 0;
}
assert(doSwitchDefaultOmitted(0) == 0);
assert(doSwitchDefaultOmitted(1) == 1);
assert(doSwitchDefaultOmitted(2) == 23);
assert(doSwitchDefaultOmitted(3) == 23);
assert(doSwitchDefaultOmitted(4) == 0);
function doSwitchBreakCase(n: i32): i32 {
switch (n) {
case 1: break;
default: return 2;
}
return 1;
}
assert(doSwitchBreakCase(0) == 2);
assert(doSwitchBreakCase(1) == 1);
assert(doSwitchBreakCase(2) == 2);
function doSwitchBreakDefault(n: i32): i32 {
switch (n) {
case 1: return 1;
default: break;
}
return 2;
}
assert(doSwitchBreakDefault(0) == 2);
assert(doSwitchBreakDefault(1) == 1);
assert(doSwitchBreakDefault(2) == 2);
function doSwitchFallThroughCase(n: i32): i32 {
switch (n) {
default: return 2;
case 1:
}
return 1;
}
assert(doSwitchFallThroughCase(0) == 2);
assert(doSwitchFallThroughCase(1) == 1);
assert(doSwitchFallThroughCase(2) == 2);
function doSwitchFallThroughDefault(n: i32): i32 {
switch (n) {
case 1: return 1;
default:
}
return 2;
}
assert(doSwitchFallThroughDefault(0) == 2);
assert(doSwitchFallThroughDefault(1) == 1);
assert(doSwitchFallThroughDefault(2) == 2);
function doSwitchEmpty(n: i32): i32 {
switch (n) {} // (drop n)
return 2;
}
assert(doSwitchEmpty(0) == 2);
assert(doSwitchEmpty(1) == 2);
assert(doSwitchEmpty(2) == 2);

View File

@ -1,12 +1,14 @@
(module
(type $ii (func (param i32) (result i32)))
(global $HEAP_BASE i32 (i32.const 8))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $v (func))
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
(global $HEAP_BASE i32 (i32.const 32))
(memory $0 1)
(export "doSwitch" (func $switch/doSwitch))
(export "doSwitchDefaultFirst" (func $switch/doSwitchDefaultFirst))
(export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted))
(data (i32.const 8) "\t\00\00\00s\00w\00i\00t\00c\00h\00.\00t\00s\00")
(export "memory" (memory $0))
(func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32)
(start $start)
(func $switch/doSwitch (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case4|0
@ -58,50 +60,6 @@
)
)
)
(func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case3|0
(block $case2|0
(block $case1|0
(block $case0|0
(set_local $1
(get_local $0)
)
(br_if $case1|0
(i32.eq
(get_local $1)
(i32.const 1)
)
)
(br_if $case2|0
(i32.eq
(get_local $1)
(i32.const 2)
)
)
(br_if $case3|0
(i32.eq
(get_local $1)
(i32.const 3)
)
)
(br $case0|0)
)
(return
(i32.const 0)
)
)
(return
(i32.const 1)
)
)
)
(return
(i32.const 23)
)
)
)
(func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
@ -144,4 +102,686 @@
(i32.const 0)
)
)
(func $switch/doSwitchBreakCase (; 3 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case1|0
(block $case0|0
(set_local $1
(get_local $0)
)
(br_if $case0|0
(i32.eq
(get_local $1)
(i32.const 1)
)
)
(br $case1|0)
)
(br $break|0)
)
(return
(i32.const 2)
)
)
(return
(i32.const 1)
)
)
(func $switch/doSwitchBreakDefault (; 4 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case1|0
(block $case0|0
(set_local $1
(get_local $0)
)
(br_if $case0|0
(i32.eq
(get_local $1)
(i32.const 1)
)
)
(br $case1|0)
)
(return
(i32.const 1)
)
)
(br $break|0)
)
(return
(i32.const 2)
)
)
(func $switch/doSwitchFallThroughCase (; 5 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case1|0
(block $case0|0
(set_local $1
(get_local $0)
)
(br_if $case1|0
(i32.eq
(get_local $1)
(i32.const 1)
)
)
(br $case0|0)
)
(return
(i32.const 2)
)
)
)
(return
(i32.const 1)
)
)
(func $switch/doSwitchFallThroughDefault (; 6 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0
(block $case1|0
(block $case0|0
(set_local $1
(get_local $0)
)
(br_if $case0|0
(i32.eq
(get_local $1)
(i32.const 1)
)
)
(br $case1|0)
)
(return
(i32.const 1)
)
)
)
(return
(i32.const 2)
)
)
(func $switch/doSwitchEmpty (; 7 ;) (type $ii) (param $0 i32) (result i32)
(drop
(get_local $0)
)
(return
(i32.const 2)
)
)
(func $start (; 8 ;) (type $v)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 0)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 10)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 11)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 2)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 12)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 3)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 13)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 4)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 14)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 0)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 24)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 25)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 2)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 26)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 3)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 27)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitch
(i32.const 4)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 28)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchDefaultOmitted
(i32.const 0)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 38)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchDefaultOmitted
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 39)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchDefaultOmitted
(i32.const 2)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 40)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchDefaultOmitted
(i32.const 3)
)
(i32.const 23)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 41)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchDefaultOmitted
(i32.const 4)
)
(i32.const 0)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 42)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakCase
(i32.const 0)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 51)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakCase
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 52)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakCase
(i32.const 2)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 53)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakDefault
(i32.const 0)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 62)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakDefault
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 63)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchBreakDefault
(i32.const 2)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 64)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughCase
(i32.const 0)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 73)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughCase
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 74)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughCase
(i32.const 2)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 75)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughDefault
(i32.const 0)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 84)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughDefault
(i32.const 1)
)
(i32.const 1)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 85)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchFallThroughDefault
(i32.const 2)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 86)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchEmpty
(i32.const 0)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 92)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchEmpty
(i32.const 1)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 93)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $switch/doSwitchEmpty
(i32.const 2)
)
(i32.const 2)
)
)
(block
(call $~lib/env/abort
(i32.const 0)
(i32.const 8)
(i32.const 94)
(i32.const 0)
)
(unreachable)
)
)
)
)