Hi! I read a bit about the class dependent types, aux pattern etc., but I do not understand why this minified example does not work with an implicit conversion. Is it possible to make it working? The solution may require macros.
import scala.language.implicitConversions
trait Block[T] {
type Result
def apply(bi: T): Result
}
object Block {
implicit def conv[T, R](f: T => R): Block[T] {type Result = R} = new Block[T] {
override type Result = R
def apply(value: T): Result = f(value)
}
}
object Main {
import Block.conv
def doSth[T](block: Block[T]): block.Result = ???
def main(args: Array[String]): Unit = {
val good: Int = doSth[Int](conv(_ + 5)) // ok
val bad: Int = doSth[Int](_ + 5)
//type mismatch;
// found : Int
// required: Block[Int]#Result
// val bad: Int = doSth[Int](_ + 5)
}
}
Of course, Block[T, R]
with def doSth[T, R]
would do the job, but I care not to give the result type as a type parameter.
I use Scala 2.13.16 and the typer result is:
❯ ./mill testing.compile
[44/44] testing.compile
[44] [info] compiling 1 Scala source to /Users/bkozak/IdeaProjects/macro3-z-bartusiem/out/testing/compile.dest/classes ...
[44] |-- <empty> APPSELmode-EXPRmode-POLYmode-QUALmode (site: package <root>)
[44] | \-> <empty>.type
[44] |-- scala.language APPSELmode-EXPRmode-POLYmode-QUALmode (site: package <empty>)
[44] | |-- scala APPSELmode-EXPRmode-POLYmode-QUALmode (site: package <empty>)
[44] | | \-> scala.type
[44] | \-> language.type
[44] |-- class Block[T] BYVALmode-EXPRmode (site: package <empty>)
[44] | |-- Result BYVALmode-EXPRmode (site: trait Block)
[44] | | \-> [type Result] Block.this.Result
[44] | |-- def apply BYVALmode-EXPRmode (site: trait Block)
[44] | | |-- Result TYPEmode (site: method apply in Block)
[44] | | | \-> Block.this.Result
[44] | | |-- T TYPEmode (site: value bi in Block)
[44] | | | \-> T
[44] | | \-> [def apply] (bi: T): Block.this.Result
[44] | \-> [trait Block] Block[T]
[44] |-- object Block BYVALmode-EXPRmode (site: package <empty>)
[44] | |-- super APPSELmode-EXPRmode-POLYmode-QUALmode (silent: <init> in Block)
[44] | | |-- this EXPRmode (silent: <init> in Block)
[44] | | | \-> Block.type
[44] | | \-> Block.type
[44] | |-- def conv[T, R] BYVALmode-EXPRmode (site: object Block)
[44] | | |-- Block[T] { type Result = R } TYPEmode (site: method conv in Block)
[44] | | | |-- Block[T] TYPEmode (site: method conv in Block)
[44] | | | | |-- T TYPEmode (site: method conv in Block)
[44] | | | | | \-> T
[44] | | | | \-> Block[T]
[44] | | | |-- R TYPEmode (site: type Result in <refinement>)
[44] | | | | \-> R
[44] | | | [adapt] Block[T] { type Result = R } is now a TypeTree(Block[T]{type Result = R})
[44] | | | \-> Block[T]{type Result = R}
[44] | | |-- _root_.scala.Function1[T, R] TYPEmode (site: value f in Block)
[44] | | | |-- T TYPEmode (site: value f in Block)
[44] | | | | \-> T
[44] | | | |-- R TYPEmode (site: value f in Block)
[44] | | | | \-> R
[44] | | | \-> T => R
[44] | | |-- { final class $anon extends Block[T] { def <init>() = { s... : pt=Block[T]{type Result = R} EXPRmode (site: method conv in Block)
[44] | | | |-- Block FUNmode-TYPEmode (site: anonymous class $anon)
[44] | | | | \-> Block
[44] | | | |-- Block[T] TYPEmode (site: anonymous class $anon)
[44] | | | | |-- T TYPEmode (site: anonymous class $anon)
[44] | | | | | \-> T
[44] | | | | \-> Block[T]
[44] | | | |-- Result TYPEmode (site: method apply in $anon)
[44] | | | | |-- R TYPEmode (site: type Result in $anon)
[44] | | | | | \-> R
[44] | | | | [adapt] R is now a TypeTree(this.Result)
[44] | | | | \-> this.Result
[44] | | | |-- T TYPEmode (site: value value in $anon)
[44] | | | | \-> T
[44] | | | |-- class $anon BYVALmode-EXPRmode (site: method conv in Block)
[44] | | | | |-- [T]AnyRef { type Result def apply(bi: T): Block.this.Resu... TYPEmode (site: anonymous class $anon)
[44] | | | | | \-> Block[T]
[44] | | | | |-- super APPSELmode-EXPRmode-POLYmode-QUALmode (silent: <init> in $anon)
[44] | | | | | |-- this EXPRmode (silent: <init> in $anon)
[44] | | | | | | \-> Block[T]
[44] | | | | | \-> super.type (with underlying type AnyRef)
[44] | | | | |-- Result BYVALmode-EXPRmode (site: anonymous class $anon)
[44] | | | | | \-> [type Result] this.Result
[44] | | | | |-- def apply BYVALmode-EXPRmode (site: anonymous class $anon)
[44] | | | | | |-- f(value) : pt=this.Result EXPRmode (site: method apply in $anon)
[44] | | | | | | |-- f APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method apply in $anon)
[44] | | | | | | | |-- f.apply APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method apply in $anon)
[44] | | | | | | | | \-> (v1: T): R
[44] | | | | | | | [adapt] T => R adapted to (v1: T1): R
[44] | | | | | | | \-> (v1: T): R
[44] | | | | | | |-- value : pt=T BYVALmode-EXPRmode (silent: method apply in $anon)
[44] | | | | | | | \-> T
[44] | | | | | | \-> R
[44] | | | | | \-> [def apply] (value: T): this.Result
[44] | | | | \-> [class $anon] Block[T]
[44] | | | |-- new $anon() : pt=Block[T]{type Result = R} EXPRmode (site: method conv in Block)
[44] | | | | |-- new $anon APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method conv in Block)
[44] | | | | | |-- new $anon APPSELmode-EXPRmode-POLYmode-QUALmode (silent: method conv in Block)
[44] | | | | | | |-- $anon FUNmode-TYPEmode (silent: method conv in Block)
[44] | | | | | | | \-> Block[T]
[44] | | | | | | \-> Block[T]
[44] | | | | | \-> (): Block[T]
[44] | | | | \-> Block[T]
[44] | | | \-> Block[T]
[44] | | \-> [def conv] [T, R](f: T => R): Block[T]{type Result = R}
[44] | \-> [object Block] Block.type
[44] |-- object Main BYVALmode-EXPRmode (site: package <empty>)
[44] | |-- super APPSELmode-EXPRmode-POLYmode-QUALmode (silent: <init> in Main)
[44] | | |-- this EXPRmode (silent: <init> in Main)
[44] | | | \-> Main.type
[44] | | \-> Main.type
[44] | |-- Block APPSELmode-EXPRmode-POLYmode-QUALmode (site: object Main)
[44] | | \-> Block.type
[44] | |-- def doSth[T] BYVALmode-EXPRmode (site: object Main)
[44] | | |-- block.Result TYPEmode (site: method doSth in Main)
[44] | | | |-- block APPSELmode-EXPRmode-QUALmode (site: method doSth in Main) implicits disabled
[44] | | | | |-- Block[T] TYPEmode (site: value block in Main) implicits disabled
[44] | | | | | |-- T TYPEmode (site: value block in Main) implicits disabled
[44] | | | | | | \-> T
[44] | | | | | \-> Block[T]
[44] | | | | \-> block.type (with underlying type Block[T])
[44] | | | \-> block.Result
[44] | | |-- $qmark$qmark$qmark : pt=block.Result EXPRmode (site: method doSth in Main)
[44] | | | \-> Nothing
[44] | | \-> [def doSth] [T](block: Block[T]): block.Result
[44] | |-- def main BYVALmode-EXPRmode (site: object Main)
[44] | | |-- Unit TYPEmode (site: method main in Main)
[44] | | | \-> Unit
[44] | | |-- Array[String] TYPEmode (site: value args in Main)
[44] | | | |-- String TYPEmode (site: value args in Main)
[44] | | | | [adapt] String is now a TypeTree(String)
[44] | | | | \-> String
[44] | | | \-> Array[String]
[44] | | |-- { val good: Int = doSth[Int](conv(((x$1) => x$1.$plus(5))... : pt=Unit EXPRmode (site: method main in Main)
[44] | | | |-- <?> BYVALmode-EXPRmode (site: method main in Main)
[44] | | | | |-- Int TYPEmode (site: value good in Main)
[44] | | | | | \-> Int
[44] | | | | |-- doSth[Int](conv(((x$1) => x$1.$plus(5)))) : pt=Int BYVALmode-EXPRmode (site: value good in Main)
[44] | | | | | |-- doSth[Int] APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value good in Main)
[44] | | | | | | |-- doSth APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode-TAPPmode (silent: value good in Main)
[44] | | | | | | | \-> [T](block: Block[T]): block.Result
[44] | | | | | | |-- Int TYPEmode (silent: value good in Main)
[44] | | | | | | | \-> Int
[44] | | | | | | \-> (block: Block[Int]): block.Result
[44] | | | | | |-- conv(((x$1) => x$1.$plus(5))) : pt=Block[Int] BYVALmode-EXPRmode (site: value good in Main)
[44] | | | | | | |-- conv APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value good in Main)
[44] | | | | | | | [adapt] [T, R](f: T => R): Block[T]{type Result = R} adapted to [T, R](f: T => R): Block[T]{type Result = R}
[44] | | | | | | | \-> (f: T => R): Block[T]{type Result = R}
[44] | | | | | | |-- ((x$1) => x$1.$plus(5)) : pt=Int => ? BYVALmode-EXPRmode-POLYmode (site: value good in Main)
[44] | | | | | | | |-- x$1.$plus(5) EXPRmode (site: value $anonfun in Main)
[44] | | | | | | | | |-- x$1.$plus APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in Main)
[44] | | | | | | | | | |-- x$1 APPSELmode-EXPRmode-POLYmode-QUALmode (silent: value $anonfun in Main)
[44] | | | | | | | | | | \-> x$1.type (with underlying type Int)
[44] | | | | | | | | | \-> (x: Double): Double <and> (x: Float): Float <and> (x: Long): Long <and> (x: Int): Int <and> (x: Char): Int <and> (x: Short): Int <and> (x: Byte): Int <and> (x: String): String
[44] | | | | | | | | |-- 5 BYVALmode-EXPRmode (silent: value $anonfun in Main)
[44] | | | | | | | | | \-> Int(5)
[44] | | | | | | | | \-> Int
[44] | | | | | | | \-> Int => Int
[44] | | | | | | solving for (T: ?T, R: ?R)
[44] | | | | | | \-> Block[Int]{type Result = Int}
[44] | | | | | \-> Int
[44] | | | | \-> [val good] Int
[44] | | | |-- <?> BYVALmode-EXPRmode (site: method main in Main)
[44] | | | | |-- Int TYPEmode (site: value bad in Main)
[44] | | | | | \-> Int
[44] | | | | |-- doSth[Int](((x$2) => x$2.$plus(5))) : pt=Int BYVALmode-EXPRmode (site: value bad in Main)
[44] | | | | | |-- doSth[Int] APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value bad in Main)
[44] | | | | | | |-- doSth APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode-TAPPmode (silent: value bad in Main)
[44] | | | | | | | \-> [T](block: Block[T]): block.Result
[44] | | | | | | |-- Int TYPEmode (silent: value bad in Main)
[44] | | | | | | | \-> Int
[44] | | | | | | \-> (block: Block[Int]): block.Result
[44] | | | | | |-- ((x$2) => x$2.$plus(5)) : pt=Block[Int] BYVALmode-EXPRmode (site: value bad in Main)
[44] | | | | | | |-- x$2.$plus(5) : pt=Block[Int]#Result EXPRmode (site: value $anonfun in Main)
[44] | | | | | | | |-- x$2.$plus APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in Main)
[44] | | | | | | | | |-- x$2 APPSELmode-EXPRmode-POLYmode-QUALmode (silent: value $anonfun in Main)
[44] | | | | | | | | | \-> x$2.type (with underlying type Int)
[44] | | | | | | | | \-> (x: Double): Double <and> (x: Float): Float <and> (x: Long): Long <and> (x: Int): Int <and> (x: Char): Int <and> (x: Short): Int <and> (x: Byte): Int <and> (x: String): String
[44] | | | | | | | [search #1] start `<notype>`, searching for adaptation to pt=Double => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | [search #2] start `<notype>`, searching for adaptation to pt=(=> Double) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | [search #3] start `<notype>`, searching for adaptation to pt=Float => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 4 implicits in companion scope
[44] | | | | | | | [search #4] start `<notype>`, searching for adaptation to pt=(=> Float) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 4 implicits in companion scope
[44] | | | | | | | [search #5] start `<notype>`, searching for adaptation to pt=Long => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 4 implicits in companion scope
[44] | | | | | | | [search #6] start `<notype>`, searching for adaptation to pt=(=> Long) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 4 implicits in companion scope
[44] | | | | | | | [search #7] start `<notype>`, searching for adaptation to pt=Int => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | [search #8] start `<notype>`, searching for adaptation to pt=(=> Int) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | [search #9] start `<notype>`, searching for adaptation to pt=Int => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #10] start `<notype>`, searching for adaptation to pt=(=> Int) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #11] start `<notype>`, searching for adaptation to pt=Int => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #12] start `<notype>`, searching for adaptation to pt=(=> Int) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #13] start `<notype>`, searching for adaptation to pt=Int => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #14] start `<notype>`, searching for adaptation to pt=(=> Int) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #15] start `<notype>`, searching for adaptation to pt=String => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | [search #16] start `<notype>`, searching for adaptation to pt=(=> String) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | 3 implicits in companion scope
[44] | | | | | | | |-- 5 BYVALmode-EXPRmode (silent: value $anonfun in Main)
[44] | | | | | | | | \-> Int(5)
[44] | | | | | | | [search #17] start `(x: Int): Int`, searching for adaptation to pt=Int => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] | | | | | | | [search #18] start `(x: Int): Int`, searching for adaptation to pt=(=> Int) => Block[Int]#Result (silent: value $anonfun in Main) implicits disabled
[44] [error] /Users/bkozak/IdeaProjects/macro3-z-bartusiem/testing/src/Main.scala:26:33: type mismatch;
[44] [error] found : Int
[44] [error] required: Block[Int]#Result
[44] [error] val bad: Int = doSth[Int](_ + 5)
[44] [error] ^
[44] | | | | | | | \-> <error>
[44] | | | | | | \-> <error>
[44] | | | | | \-> <error>
[44] | | | | \-> [val bad] Int
[44] | | | \-> Unit
[44] | | \-> [def main] (args: Array[String]): Unit
[44] | \-> [object Main] Main.type
[44] |-- Result BYVALmode-EXPRmode (site: <refinement>)
[44] | \-> [type Result] this.Result
[44] [adapt] implicitConversions adapted to languageFeature.implicitConversions based on pt scala.languageFeature.implicitConversions
[44] [error] one error found