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

Change assertion failure to unreachable statement #1205

Conversation

DuncanUszkay1
Copy link
Contributor

Issue: #1165

Right now if you have a global which fails to resolve its own type, and is also used in another constant, you get an assertion failure which prevents any errors from being printed to the console.

This PR just returns unreachable instead of panicking, allowing error messages to be printed.

Example:

const INNER: fake = 1;
const OUTER: i32 = SOME;

Before: AssertionFailure with stack trace
After:

ERROR TS2304: Cannot find name 'fake'.

 const INNER: fake = 1;
              ~~~~
 in main.ts(5,14)

ERROR: 1 compile error(s)
    at Object.main (/Users/duncanuszkay/src/github.com/Shopify/as-fork/assemblyscript/cli/asc.js:614:21)
    at /Users/duncanuszkay/src/github.com/Shopify/as-fork/assemblyscript/bin/asc:21:47

I don't think I need to add an error to the line where the assertion fails- there's not much useful information here since they didn't set their type to void, it's really just an internal thing. AFAIK there's no way to make this global void without causing another error, so the dev should always get enough information to fix the bug

@DuncanUszkay1
Copy link
Contributor Author

@dcodeIO any issues with this?

src/compiler.ts Outdated
@@ -7915,7 +7915,9 @@ export class Compiler extends DiagnosticEmitter {
return module.unreachable();
}
let globalType = global.type;
assert(globalType != Type.void);
if(globalType == Type.void) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a whitespace here, and wondering if the fix should instead make compileGlobal above return false. Might have unforeseen consequences.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't compile regardless- since a global resolving into a void is already an error:

if (resolvedType == Type.void) {
          this.error(
            DiagnosticCode.Type_expected,
            typeNode.range
          );
          return false;
        }

Given that, this is really just a question of what gets displayed when it does fail. I suppose the worst case here is that there is some edge case where this will append additional errors which don't make sense to the error which the dev needs to see, but that doesn't seem like huge problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this requires a fix, just questioning the chosen location. If compileGlobal would return false if it failed to compile that same global earlier already, which gives us an unreachable as well, this would be much clearer than checking for Type.void.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compileGlobal does in fact return false for the first statement- and that false was being ignored by compileTopLevelStatement. If I move the unreachable call there it will also work:

if (!this.compileGlobal(<Global>element)) this.module.unreachable();

Most other calls to compileGlobal do the same, checking its result and then returning unreachable if it failed. Is this what you mean?

For this to work however I'd still need to delete the globalType != void assertion, otherwise none of these errors will ever print.

Copy link
Member

@dcodeIO dcodeIO Apr 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most other calls to compileGlobal do the same, checking its result and then returning unreachable if it failed. Is this what you mean?

Yeah, plus that it currently seems that only the first call to compileGlobal for the same global returns false if compilation fails currently, while subsequent calls see that it is already CommonFlags.COMPILED and return true. I think we should fix that, instead of adding checks for Type.void that are only necessary due to a more general problem.

Copy link
Contributor Author

@DuncanUszkay1 DuncanUszkay1 May 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to move the unreachable call- looking into a more general fix as well

@DuncanUszkay1
Copy link
Contributor Author

Updated such that we don't return true on the second call to compileGlobal- the issue now is that if you do anything self referential:
var SELFREFERENCING: i32 = SELFREFERENCING then you get a stack overflow error on compilation. If we're worried about that, maybe we can add a COMPILING flag in addition to the COMPILED flag and fail whenever we try to compile a global that's already compiling?

@MaxGraey
Copy link
Member

MaxGraey commented May 6, 2020

var SELFREFERENCING: i32 = SELFREFERENCING should print TS2448: Block-scoped variable 'SELFREFERENCING' used before its declaration.. If it's not true for now I guess better make another PR which will handle this

@dcodeIO
Copy link
Member

dcodeIO commented May 6, 2020

What if we keep the COMPILED flag as-is, but add a Set holding all the globals that failed to compile earlier? Would that help?

  compileGlobal(global: Global): bool {
    if (global.is(CommonFlags.COMPILED)) return !this.failedGlobals.has(global);
    // whenever returning `false`, also add to `failedGlobals`

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

Successfully merging this pull request may close these issues.

3 participants