Встраивание scala 3 не выполняется - очень простой пример

Я изучаю возможности встраивания в scala3. Я составил простой пример, в котором я хочу, чтобы метод проверки, создающий запечатанный класс, применялся во время компиляции:

      import scala.compiletime.{ error, codeOf }

sealed abstract class OneOrTwo(val code: String)

object OneOrTwo {

    case object One extends OneOrTwo("one")
    case object Two extends OneOrTwo("two")

    def from(s: String): Option[OneOrTwo] = 
        s match {
            case One.code => Some(One)
            case Two.code => Some(Two)
            case _ => None
        }

    inline def inlinedFrom1(s: String): OneOrTwo = {
        inline s match {
            case "one" => One
            case "two" => Two
            case _ => error("can't make a OneOrTwo out of " + codeOf(s))
        } 
    }

    val test1 = OneOrTwo.inlinedFrom1("one") // compiles 
    val test12 = OneOrTwo.inlinedFrom1("three") // doesn't compile as expected -> can't make a OneOrTwo out of "three"
}

Все идет нормально. Но на самом деле я хочу иметь возможность повторно использовать fromфункция внутри встроенного. Вот я пытаюсь:

          // this goes in the OneOrTwo companion object as well

    inline def inlinedFrom2(s: String): OneOrTwo = {
        from(s).getOrElse(error("can't make a OneOrTwo out of " + codeOf(s)))
    }

    inline def inlinedFrom3(s: String): OneOrTwo = {
        s match {
            case One.code => One
            case Two.code => Two
            case _ => error("can't make a OneOrTwo out of " + codeOf(s))
        }
    }

    
    val test2 = OneOrTwo.inlinedFrom2("one") // doesn't compile -> can't make a OneOrTwo out of "one"
    val test3 = OneOrTwo.inlinedFrom3("one") // doesn't compile -> can't make a OneOrTwo out of "one"

является обобщением, чтобы показать, что если я сопоставляю код объектов напрямую, компилятор не видит, что они совпадают с входной строкой, и берет неправильную ветвь.

Я хотел бы понять, почему inlinedFrom3 не работает и есть ли способ заставить его работать.

Примечание: я использую scala 3.0.0-RC2

1 ответ

Решение

Хороший вопрос,

Прежде всего, учтите, что встраивание - это способ выполнять метапрограммирование во время компиляции в Scala (как вы это делали в своем примере).

Чтобы сделать ставку на вашу проблему, здесь компилятор не понимает, что это тип "one". Действительно, если вы попытаетесь напечатать One.code, вывод компилятора:

      OneOrTwo.One.code

и нет

      "one"

Но подождите, почему? Потому что компилятор не может ничего сделать о One.code во время компиляции. Чтобы передать недостающую информацию компилятору, вы можете:

  • указать тип одиночной строки
      sealed trait OneOrTwo {
  val code: String
}

object OneOrTwo {
    case object One extends OneOrTwo {
      override val code : "one" = "one" 
    }
    case object Two extends OneOrTwo {
      override val code : "two" = "two"
    }
}
  • в соответствии val определение
      sealed trait OneOrTwo {
  val code: String
}

object OneOrTwo {
    case object One extends OneOrTwo {
      override inline val code = "one" 
    }
    case object Two extends OneOrTwo {
      override inline val code = "two"
    }
}

Даже с этой модификацией ваш код продолжает терпеть неудачу при компиляции. Это вызвано тем, что предложение match не встроено. В самом деле, как упоминалось здесь, метод error предоставляет способ генерировать настраиваемые сообщения об ошибках. Ошибка будет выдана, если вызов error встроен и не устранен как мертвая ветвь. Итак, если вы положите error(...)в коде, который не встроен, всегда будет выдаваться ошибка. Например, такой код:

      if(false) { error("thrown..") } { }

выдает ошибку компиляции.

Наконец, чтобы решить вашу проблему, вам нужно встроить предложение соответствия:

      inline def inlinedFrom3(s: String): OneOrTwo = {
   inline s match {
       case One.code => One
       case Two.code => Two
       case _ => error("can't make a OneOrTwo out of " + codeOf(s))
   }
}

Сборник (для inlinedFrom3) удалось. inlineFrom2 продолжает выходить из строя из-за вышеупомянутой проблемы.

Надеюсь, я вам помог.

Другие вопросы по тегам