Skip to content

inline if over an inline def doesn't work when overriding a method #12072

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
japgolly opened this issue Apr 13, 2021 · 4 comments · Fixed by #12080
Closed

inline if over an inline def doesn't work when overriding a method #12072

japgolly opened this issue Apr 13, 2021 · 4 comments · Fixed by #12080

Comments

@japgolly
Copy link
Contributor

Compiler version

Both:

  • 3.0.0-RC1
  • 3.0.1-RC1-bin-20210411-b44cafa-NIGHTLY

Minimized code

object T {

  transparent inline def f(inline s: String): String | Null =
    null

  inline val V = "V"
  inline def D = "D"

  trait Trait { def s: String }

  // ===========================================================================
  // inline {if,match} over inline {val,def}

  transparent inline def if_v: String =
    inline if V == "V" then "o" else "x"

  transparent inline def if_d: String =
    inline if D == "D" then "o" else "x"

  transparent inline def match_v: String =
    inline V match { case "V" => "o"; case _   => "x" }

  transparent inline def match_d: String =
    inline D match { case "D" => "o"; case _   => "x" }

  // ===========================================================================
  // inline {if,match} over inline f(inline {val,def})

  transparent inline def if_fv: String =
    inline if f(V) == "V" then "o" else "x"

  transparent inline def if_fd: String =
    inline if f(D) == "D" then "o" else "x"

  transparent inline def match_fv: String =
    inline f(V) match { case "V" => "o"; case _   => "x" }

  transparent inline def match_fd: String =
    inline f(D) match { case "D" => "o"; case _   => "x" }

  // ===========================================================================
  // inline {if,match} over inline {val,def} in overridden method

  object IfV extends Trait {
    override transparent inline def s: String =
      inline if V == "V" then "o" else "x"
  }

  object IfD extends Trait {
    override transparent inline def s: String =
      inline if D == "D" then "o" else "x" // <--------------------------- error
  }

  object MatchV extends Trait {
    override transparent inline def s: String =
      inline V match { case "V" => "o"; case _   => "x" }
  }

  object MatchD extends Trait {
    override transparent inline def s: String =
      inline D match { case "D" => "o"; case _   => "x" }
  }

  // ===========================================================================
  // inline {if,match} over inline f(inline {val,def}) in overridden method

  object IfFV extends Trait {
    override transparent inline def s: String =
      inline if f(V) == "V" then "o" else "x" // <------------------------ error
  }

  object IfFD extends Trait {
    override transparent inline def s: String =
      inline if f(D) == "D" then "o" else "x" // <------------------------ error
  }

  object MatchFV extends Trait {
    override transparent inline def s: String =
      inline f(V) match { case "V" => "o"; case _   => "x" }
  }

  object MatchFD extends Trait {
    override transparent inline def s: String =
      inline f(D) match { case "D" => "o"; case _   => "x" }
  }
}

Output

[error] -- Error: BUG.scala:51:6 --------------
[error] 51 |      inline if D == "D" then "o" else "x" // <--------------------------- error
[error]    |      ^
[error]    |Cannot reduce `inline if` because its condition is not a constant value: ("D":String).==("D")
[error]    | This location contains code that was inlined from BUG.scala:51
[error] -- Error: BUG.scala:69:6 --------------
[error] 69 |      inline if f(V) == "V" then "o" else "x" // <------------------------ error
[error]    |      ^
[error]    |Cannot reduce `inline if` because its condition is not a constant value: null.==("V")
[error]    | This location contains code that was inlined from BUG.scala:69
[error] -- Error: BUG.scala:74:6 --------------
[error] 74 |      inline if f(D) == "D" then "o" else "x" // <------------------------ error
[error]    |      ^
[error]    |Cannot reduce `inline if` because its condition is not a constant value: null.==("D")
[error]    | This location contains code that was inlined from BUG.scala:74
[error] three errors found

Expectation

It should all compile.

What's even more interesting about this is that you change

  transparent inline def f(inline s: String): String | Null = null

to

  transparent inline def f(inline s: String): String | Null = "f"

then errors 2 and 3 disappear, but the first error remains.

@japgolly
Copy link
Contributor Author

FYI this situation was a little bit worse in 3.0.0-RC1. Here's a very similar case where calling Expr.valueOrError results in another new error, and is fixed in RC2.

import scala.quoted.*

object M {

  transparent inline def f(inline s: String): String | Null =
    ${ f('s) }

  def f(s: Expr[String])(using Quotes): Expr[String | Null] = {
    s.valueOrError // required
    '{ null }
  }
}
object T2 {
  import M.f

  private inline val V = "V"
  private inline def D = "D"

  trait Trait { def s: String }

  object MatchFV extends Trait {
    override transparent inline def s: String =
      inline f(V) match { case "V" => "o"; case _   => "x" } // error in RC1
  }

  object MatchFD extends Trait {
    override transparent inline def s: String =
      inline f(D) match { case "D" => "o"; case _   => "x" }
  }
}
[error] 11 |      inline f(V) match { case "V" => "o"; case _   => "x" } // error in RC1
[error]    |             ^
[error]    |Expected a known value. 
[error]    |
[error]    |The value of: T2.V
[error]    |could not be extracted using scala.quoted.FromExpr$PrimitiveFromExpr@22d08388
[error]    | This location contains code that was inlined from BUG.scala:11
[error]    | This location contains code that was inlined from BUG.scala:11
[error] one error found

@nicolasstucki
Copy link
Contributor

Minimized

inline def c: Int = 2

trait A:
  def f: Unit

class B extends A:
  override inline def f: Unit =
    inline if c == 2 then () else ()

@nicolasstucki
Copy link
Contributor

Mimimized null example

transparent inline def f: Null = null

inline def g: Unit =
  inline if f == "V" then () else ()

def test = g

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
* Better handling of inlined expression
* Handle `null` in `==` and `!=`

Fixes scala#12072
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
* Better handling of inlined expression
* Constant fold `String.!=`
* Handle `null` in `==` and `!=`

Fixes scala#12072
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
* Better handling of inlined expression
* Constant fold `String.!=`
* Handle `null` in `==` and `!=`

Fixes scala#12072
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
* Better handling of inlined expression
* Constant fold `String.!=`
* Handle `null` in `==` and `!=`

Fixes scala#12072
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
* Better handling of inlined expression
* Constant fold `String.!=`
* Handle `null` in `==` and `!=`

Fixes scala#12072
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 14, 2021
* Better handling of inlined expression
* Constant fold `String.!=`
* Handle `null` in `==` and `!=`

Fixes scala#12072
@japgolly
Copy link
Contributor Author

Hey btw, just wanted to say thanks @nicolasstucki. You're fixing many a bug and pretty quickly too. It's appreciated! 🙂 🌹

@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants