Skip to content

Getting Cannot reduce inline even though equivalent code compiles #12715

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
note opened this issue Jun 4, 2021 · 2 comments · Fixed by #12902
Closed

Getting Cannot reduce inline even though equivalent code compiles #12715

note opened this issue Jun 4, 2021 · 2 comments · Fixed by #12902
Assignees
Milestone

Comments

@note
Copy link

note commented Jun 4, 2021

Compiler version

Both 3.0.0 and 3.0.1-RC1-bin-20210604-cbb1e07-NIGHTLY

Minimized code

I couldn't minimize it further. It seems that the combination of recursive inline call and inline pattern matching result being checked in inline if somehow triggers that.

package repro

import compiletime.{constValue, erasedValue}

sealed trait ValidateExprInt

class And[A <: ValidateExprInt, B <: ValidateExprInt] extends ValidateExprInt
class GreaterThan[T <: Int]                           extends ValidateExprInt

object Repro:
  inline def validate[E <: ValidateExprInt](v: Int): String =
    inline val failMsg = validateV[E](v)
    inline if failMsg == "neverPass" then "neverPass"
    else "something else"

  transparent inline def validateV[E <: ValidateExprInt](v: Int): String =
    inline erasedValue[E] match
      case _: GreaterThan[t] =>
        "GreaterThan"
      case _: And[a, b] =>
        inline validateV[a](v) match
          case "" =>
            validateV[b](v)
          case other =>
            other

  // This one works fine:
  transparent inline def validateV_fixed[E <: ValidateExprInt](v: Int): String =
    inline erasedValue[E] match
      case _: GreaterThan[t] =>
        "GreaterThan"
      case _: And[a, b] =>
        inline val res = validateV[a](v)
        inline res match
          case "" =>
            validateV[b](v)
          case _ =>
            res

  @main def test(): Unit =
    println(validate[And[GreaterThan[10], GreaterThan[12]]](5))

Output

Compilation fails with

41 |    println(validate[And[GreaterThan[10], GreaterThan[12]]](5))
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |Cannot reduce `inline if` because its condition is not a constant value: failMsg.==("neverPass")
   | This location contains code that was inlined from Repro.scala:13

Expectation

I would expect the code to compile. If I use validateV_fixed then the code compiles

@anatoliykmetyuk
Copy link
Contributor

Minimised to:

transparent inline def f: String =
  inline 10 match
    case _ =>
      inline "foo" match
        case x => x

def test =
  inline val failMsg = f

Error:

-- Error: /Users/kmetiuk/Projects/scala3/playground/wip/Bad.scala:8:23 ---------                                                                      
8 |  inline val failMsg = f
  |                       ^
  |                       inline value must have a literal constant type
1 error found

Compiling example:

transparent inline def f: String =
  inline 10 match
    case _ =>
      inline val x = "foo"
      inline x match
        case _ => x

def test =
  inline val failMsg = f

Apparently the case x => x loses the precise type of x and hence the compiler doesn't know that the result of that transparent inline is a "literal constant type".

@nicolasstucki
Copy link
Contributor

That seems to be the usual lack of type refinement issue. While inlining we need to refine the type of the binding and its references.

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.

4 participants