Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Compiler assertion fires for callbacks with void return type with implicit return #1438

Open
jeffcharles opened this issue Aug 17, 2020 · 7 comments

Comments

@jeffcharles
Copy link
Contributor

jeffcharles commented Aug 17, 2020

I have code that looks like:

import { Encoder } from 'as-msgpack';
import { Console } from 'as-wasi';
export function run(): void {
  let arrayBuffer = new ArrayBuffer(2048);
  let encoder = new Encoder(arrayBuffer);
  let m = new Map<string, string>();
  m.set("key", "value");
  encoder.writeMap(m, (e, k) => e.writeString(k), (e, v) => e.writeString(v));
  let dv = new DataView(arrayBuffer, 0);
  let a = [] as Array<String>;
  for(let i = 0; i < 128; ++i) {
    a.push('0x' + dv.getUint8(i).toString(16));
  }
  Console.log('[' + a.join(', ') + ']');
}

with a package.json that has:

{
  "name": "msgpack-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "asp --verbose",
    "asbuild:untouched": "asc assembly/index.ts --target debug",
    "asbuild:optimized": "asc assembly/index.ts --target release",
    "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "as-msgpack": "git+https://github.com/wapc/as-msgpack.git",
    "as-wasi": "^0.2.0"
  },
  "devDependencies": {
    "assemblyscript": "^0.14.0",
    "@as-pect/cli": "^4.0.0"
  }
}

and when I run npm run asbuild, I get a compiler assertion error that looks like:

Error [AssertionError]: assertion failed
    at assert (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/std/portable/index.js:193:9)
    at Flow.canOverflow (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/flow.ts:1219:5)
    at Compiler.compileReturnedExpression (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:3581:15)
    at Compiler.compileFunctionBody (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:1521:23)
    at Compiler.compileFunction (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:1435:16)
    at Compiler.compileFunctionExpression (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:8261:17)
    at Compiler.compileExpression (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:3494:21)
    at Compiler.compileCallDirect (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:7039:30)
    at Compiler.compileCallExpression (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:6695:21)
    at Compiler.compileExpression (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/src/compiler.ts:3482:21)

/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/node_modules/binaryen/index.js:57
function q(b){if(a.onAbort)a.onAbort(b);v(b);Aa=!0;throw new za("abort("+b+"). Build with -s ASSERTIONS=1 for more info.");}function Ya(b){var d=Za;return String.prototype.startsWith?b.startsWith(d):0===b.indexOf(d)}var Za="data:application/octet-stream;base64,",$a="";if(!Ya($a)){var ab=$a;$a=a.locateFile?a.locateFile(ab,p):p+ab}var bb,cb;Ma.push({Ks:function(){db()}});var I={},eb=[];
                                                         ^
Error: abort(AssertionError: assertion failed). Build with -s ASSERTIONS=1 for more info.
    at process.q (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/node_modules/binaryen/index.js:57:58)
    at process.emit (events.js:315:20)
    at process.emit (/Users/jeffreycharles/src/github.com/AssemblyScript/assemblyscript/node_modules/source-map-support/source-map-support.js:495:21)
    at processPromiseRejections (internal/process/promises.js:209:33)
    at processTicksAndRejections (internal/process/task_queues.js:98:32)

when I change the line:

encoder.writeMap(m, (e, k) => e.writeString(k), (e, v) => e.writeString(v));

to

  encoder.writeMap(
    m,
    (e: Encoder , k: string): void => {
      e.writeString(k);
    },
    (e: Encoder, v: string): void => {
      e.writeString(v);
    }
  )

the compiler assertion no longer fires and the code builds successfully.

I also tried

encoder.writeMap(m, (e: Encoder, k: string): void => e.writeString(k), (e: Encoder, v: string): void => e.writeString(v));

but that still causes the assertion to fire.

The issue title is my best guess at what's causing this assertion to fire since all that changed was adding curly braces around the function body.

The behaviour I would expect in this case is the compiler to either compile my code successfully or reject the code complaining that the inferred return type of the function and declared type are different.

@jeffcharles jeffcharles changed the title Compiler assertion fires for callbacks with void return type with non-void inferred return type Compiler assertion fires for callbacks with void return type with implicit return Aug 17, 2020
@MaxGraey
Copy link
Member

MaxGraey commented Aug 17, 2020

I guess main problem is your callback's signatures has void return type. In JS / TS this valid:

encoder.writeMap(m, (e, k) => e.writeString(k), (e, v) => e.writeString(v));

but AS it seems has problem with case when return type of callback is void but in fact you return some value. It defenitely should be proper compiler error instead of internal assert error.

You could fix this just change code above to this:

encoder.writeMap(m, (e, k) => { e.writeString(k) }, (e, v) => { e.writeString(v) });

@letmaik
Copy link

letmaik commented Oct 9, 2020

I get the same error but in my case adding curly braces didn't help. I'm not sure which line it is anyway, is there a way to find out?
You can reproduce this by cloning https://github.com/letmaik/chip8 and running npm install & npm start.

Error [AssertionError]: assertion failed
    at assert (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\std\portable\index.js:199:9)
    at p.canOverflow (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\flow.ts:1233:5)
    at T.compileReturnedExpression (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:3584:15)
    at T.compileFunctionBody (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:1523:23)
    at T.compileFunction (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:1437:16)
    at T.compileFunctionExpression (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:8279:17)
    at T.compileExpression (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:3497:21)
    at T.compileCallDirect (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:7057:30)
    at T.compileCallExpression (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:6713:21)
    at T.compileExpression (C:\...\node_modules\assemblyscript\dist\webpack:\assemblyscript\src\compiler.ts:3485:21)

C:\...\node_modules\binaryen\index.js:55
function La(){var b=a.preRun.shift();Ga.unshift(b)}var Ma=Math.abs,Na=Math.ceil,Oa=Math.floor,Pa=Math.min,K=0,Qa=null,Ra=null;a.preloadedImages={};a.preloadedAudios={};function q(b){if(a.onAbort)a.onAbort(b);v(b);xa=!0;throw new wa("abort("+b+"). Build with -s ASSERTIONS=1 for more info.");}function Sa(b){var d=Ta;return String.prototype.startsWith?b.startsWith(d):0===b.indexOf(d)}var Ta="data:application/octet-stream;base64,",Ua="";

                                                                                                        ^
Error: abort(AssertionError: assertion failed). Build with -s ASSERTIONS=1 for more info.
    at process.q (C:\...\node_modules\binaryen\index.js:55:226)
    at process.emit (events.js:314:20)
    at process.emit (C:\...\node_modules\source-map-support\source-map-support.js:495:21) 
    at processPromiseRejections (internal/process/promises.js:245:33)
    at processTicksAndRejections (internal/process/task_queues.js:94:32)

@MaxGraey
Copy link
Member

MaxGraey commented Oct 9, 2020

@letmaik
I guess it's here:
https://github.com/letmaik/chip8/blob/master/src/wasm/chip8.ts#L48
and here:
https://github.com/letmaik/chip8/blob/master/src/wasm/chip8.ts#L21

try comment this line. It defenitely shoudn't compile due to AS doesn't support closures yet with free (captured) variables. this pointer or key (in second link) here are captured vars.

@letmaik
Copy link

letmaik commented Oct 10, 2020

I tried to change the code such that the CPU class implements KeyboardListener which I defined as interface:

interface KeyboardListener {
    onKeyDown: (key: u8) => void
}

Then I can do keyboard.registerListener(this)

However, asc complains about duplicate identifiers:

ERROR TS2300: Duplicate identifier '{0}'.

     onKeyDown(key: u8): void {
     ~~~~~~~~~
 in src/wasm/chip8.ts(106,5)

     onKeyDown: (key: u8) => void
     ~~~~~~~~~
 in src/wasm/chip8.ts(6,5)

The first is the implementation in the CPU class, the other is the declaration in the interface. Looks like AS doesn't support interfaces yet? Not using an interface doesn't throw an error.

@MaxGraey
Copy link
Member

Yes, interfaces have very basic support for now, so better use abstract classes or usual classes

@dcodeIO
Copy link
Member

dcodeIO commented Dec 16, 2021

I remember touching a related aspect a while ago. The simple test

function writeMap(fn: () => void): void {
}
writeMap(() => 1);

now works, but it is perfectly possible that there is more to it. @MaxGraey?

@MaxGraey
Copy link
Member

MaxGraey commented Dec 16, 2021

Yes, I think we can make an exception for single-line arrow functions, but only for the "void" case.
valid:

function writeMap(fn: () => void): void {
}
writeMap(() => 1);

not valid:

function writeMap(fn: () => void): void {
}
writeMap(() => {
  return 1;
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants