airframe icon indicating copy to clipboard operation
airframe copied to clipboard

Scala 3 unnecessarily resolves type aliases in function argument types

Open xerial opened this issue 2 years ago • 1 comments

object MyMacros {
  def typeNameOf[A: Type](using Quotes): Expr[String] = {
    val name = Type.show[A]
    Expr(name)
  }
}

object Test extends App {
  inline def typeNameOf[A]: String = ${
    MyMacros.typeNameOf[A]
  }

  inline def typeNameOfF1[A](f: A => Unit): String = ${
    MyMacros.typeNameOf[A]
  }

  type MyString = String

  println(typeNameOf[MyString]) 
  // MyString (OK)
  println(typeNameOfF1 { (x: MyString) =>  })   
  // java.lang.String <---------- NG: This should be MyString
  println(typeNameOfF1[MyString] { (x: MyString) =>  })  
  // MyString <--- OK. If the type name is given as type param, the alias is preserved 
  
  println(typeNameOfF1 { (x: Seq[MyString]) => })
  // scala.colleciton.immutable.Seq[MyString]
  prinrln(typeNameOfF1 { (x: (MyString, Int)) => })
  // scala.Tuple2[MyString, scala.Int]
}

Scala 3 (3.1.2) shows inconsistent behavior in resolving type aliases.

xerial avatar May 28 '22 05:05 xerial

It looks like a bug of Scala 3 inline methods. Reported this issue https://github.com/lampepfl/dotty/issues/15304

xerial avatar May 28 '22 07:05 xerial

Related https://github.com/lampepfl/dotty/issues/9421

xerial avatar Oct 18 '22 23:10 xerial

This problem causes an issue in DI if provider binding with alias type arguments:

type MyString = String

Design.newDesign
  .bind[MyString].toInstance("hello")
  .bind[X].toProvider{ (s: MyString) => println(s) }      /// MISSING_DEPENDENCY String

xerial avatar Jun 16 '23 18:06 xerial

A workaround is using type tag (@@):

import wvlet.airframe.surface.tag.* 
trait Env

Design.newDesign
  .bind[String @@ Env].toInstance("hello")
  .bind[X].toProvider{ (s: String @@ Env) => println(s) }

Let's close this ticket as Scala 3 might not be fixed to make type resolver lazy.

xerial avatar Jan 09 '24 02:01 xerial