inko-lang / inko

A language for building concurrent software with confidence
http://inko-lang.org/
Mozilla Public License 2.0
883 stars 38 forks source link

Debug information isn't always correct when inlining code #766

Open yorickpeterse opened 3 hours ago

yorickpeterse commented 3 hours ago

Please describe the bug

I'm seeing this with inko-markdown when the tests fail: the line numbers reported aren't correct. This isn't the case when using inko test --opt=none.

Operating system

Fedora

Inko version

main

yorickpeterse commented 3 hours ago

The test failure that reveals this in turn seems to be caused by the incremental compilation changes (as in, a test fails with main but not with 0.16.0). Oddly enough this happens with --opt=none as well, suggesting it's not the inliner itself but some other change in the commit that broke things.

yorickpeterse commented 52 minutes ago

This appears to be due to a bug in pattern matching. inko-markdown has the following code:

  fn mut text_line -> String {
    let mut buffer = ByteArray.new

    loop {
      match next_token {
        case Some({ @kind = SoftBreak or EmptyLine }) -> break
        case Some({ @offset = offset, @size = size }) -> {
          buffer.append(@lexer.input.slice(offset, size))
        }
        case _ -> break
      }
    }

    buffer.into_string
  }

Even when encountering a SoftBreak node, it seems the second case wins which is wrong. Similarly, the following program hangs indefinitely:

import std.stdio (Stdout)

class enum Letter {
  case A
  case B
  case C
}

class Thing {
  let @letter: Letter
  let @number: Int
}

class async Main {
  fn async main {
    let out = Stdout.new
    let thing = Thing(letter: Letter.C, number: 42)

    match thing {
      case { @letter = C } -> out.print('A or C')
      case { @number = _ } -> out.print('wtf')
    }
  }
}
yorickpeterse commented 41 minutes ago

It seems that with the above code snippet, switch instructions are miscompiled. These are the interesting blocks in question when using 0.16.0:

image

And when using main:

image

Note how block b4 lists the destination for case 2 as b7 instead of b8.

I'm guessing that the unreachable block removal code isn't entirely correct, resulting in these miscompilations.