Skip to content

Using nn without -Yexplicit-nulls Crashes in RC1 but not M3 #11631

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

Closed
AugustNagro opened this issue Mar 6, 2021 · 5 comments
Closed

Using nn without -Yexplicit-nulls Crashes in RC1 but not M3 #11631

AugustNagro opened this issue Mar 6, 2021 · 5 comments

Comments

@AugustNagro
Copy link
Contributor

Compiler version

3.0.0-RC1

(No crash in 3.0.0-M3)

Minimized code

trait MyTrait:
  def a(): String = ""

class MyClass:
  var myTrait: MyTrait|Null = null

  def printA(): Unit = println(myTrait.nn.a())

@main def runTest(): Unit =
  val mt = new MyTrait:
    override def a(): String = "hello world"

  val mc = MyClass()
  mc.myTrait = mt
  mc.printA()

Output

undefined: {
  val x$proxy1: (MyTrait | Null) = this.myTrait
  (scala.runtime.Scala3RunTime.nn[MyTrait](x$proxy1):x$proxy1.type & MyTrait)
}.a # -1: TermRef(OrType(TypeRef(ThisType(TypeRef(NoPrefix,module class <empty>)),trait MyTrait),TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Null)),a) at inlining

Enabling explicit nulls fixes this, but I think the program should still compile. I ran into this problem when making an (encapsulated) Scala.js Web Component. Web Components may only have 0-arg constructors.

@AugustNagro
Copy link
Contributor Author

Oh, I just read that Don't use .nn on mutable variables directly, because it may introduce an unknown type into the type of the variable.

Is that the case here? And would the solution be replacing nn with instanceof[MyTrait]?

@odersky
Copy link
Contributor

odersky commented Mar 7, 2021

Here's a minimization without nn or Yexplicit-nulls:

trait MyTrait:
  def a(): String = ""

class Nul

extension [T](x: T | Nul) inline def nnn: x.type & T = ???

class MyClass:
  var myTrait: MyTrait|Null = null

  def printA(): Unit = println(myTrait.nnn.a())

@main def runTest(): Unit =
  val mt = new MyTrait:
    override def a(): String = "hello world"

  val mc = MyClass()
  mc.myTrait = mt
  mc.printA()

It happens at inliner phase. Seems to be a consequence of moving inlining to its own phase.

@odersky
Copy link
Contributor

odersky commented Mar 7, 2021

In fact, things seem to work if we replace the definition of myTrait above with

var myTrait: MyTrait|Nul = ???

So it does seem to be related to Null handling in some way, after all.

Maybe a stopgap measure is to disallow nn unless -YexplicitNulls is set?

@AugustNagro
Copy link
Contributor Author

AugustNagro commented Mar 7, 2021 via email

@noti0na1 noti0na1 self-assigned this Mar 18, 2021
olhotak added a commit to dotty-staging/dotty that referenced this issue Sep 24, 2021
@OlivierBlanvillain
Copy link
Contributor

Closed in #13604

olsdavis pushed a commit to olsdavis/dotty that referenced this issue Apr 4, 2022
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