JSMonk / hegel

An advanced static type checker
https://hegel.js.org
MIT License
2.09k stars 59 forks source link

Add `--trace` flag or some other kind of debugging option #250

Open Raynos opened 4 years ago

Raynos commented 4 years ago

When trying to debug the behavior of the TypeChecker it would be useful to be able to turn on tracing.

I have an example of tracing behavior in https://github.com/Raynos/jsig

The method that checks function calls or checks that LHS & RHS are the same types should add traces, for example ( https://github.com/Raynos/jsig/blob/master/type-checker/meta.js#L513-L521 ).

Aka

./src/index.js:31
  29 | 
  30 | const y = "42"
> 31 | const y2: number = "42"
     |      ^^^^^^^^^^^^^^^^^ Type "'42'" is incompatible with type "number"
  32 | const x: null = createGlobalScope
  33 | 
  34 | const COMMAND = CLI.input[0];

Whatever code checks number and string should keep a trace of all checks even if they succeed the type checker. It should always trace, they are useful and cheap to keep around in memory

If tracing is enabled at the CLI, you can ask it to print errors with tracing, for example ( https://github.com/Raynos/jsig/blob/master/bin/jsig.js#L232-L238 ).

When printing errors I grab the start and end location of the error, for example above it would be line 31 and I loop over all traces in the ModuleScope / GlobalScope etc and if the location of a trace is within the location of an error I print them.

I also found it useful to have an extra CLI flag called --full-trace which just loops over the traces and prints them all ( https://github.com/Raynos/jsig/blob/4ec14c2039924243671d16d8a6c3a5318679cf0e/bin/jsig.js#L220-L224 ).

When printing a trace I would print something like

examples/1-hello.js
Found error: jsig.sub-type.type-class-mismatch
@5: Got unexpected type class. Expected Number but got String

4. function foo(x) {
// foo("hello world") is type error string + number
5.     return x * 10;
6. }

Expected : Number
Actual   : String

traces for error : 

    examples/1-hello.js
    TRACE: meta.infer-type
    4. function foo(x) {
    5.     return x * 10;
    6. }

    Expected : <InferredType>
    Actual : Number

    examples/1-hello.js
    TRACE: meta.check-sub-type
    4. function foo(x) {
    5.     return x * 10;
    6. }

    Expected : Number
    Actual : String

    examples/1-hello.js
    TRACE: meta.check-sub-type
    4. function foo(x) {
    5.     return x * 10;
    6. }

    Expected : Number
    Actual : Number

    examples/1-hello.js
    TRACE: meta.check-sub-type
    4. function foo(x) {
    5.     return x * 10;
    6. }

    Expected : %Void%%UnknownReturn
    Actual : Number
Raynos commented 4 years ago

Btw; great project.

I'm impressed the ./packages/cli package compiles and passes the HegelJS type checker.

It looks like the ./packages/core itself uses flow for bootstrapping atm.

JSMonk commented 4 years ago

Thank you. Yes, @hegel.core is developed with Hegel 😄