Skip to content

Commit d21642b

Browse files
committed
Introduce MethodTypeKind to quotes reflection API
It allows to create Contextual and Implicit MethodTypes. MethodTypeKind abstracts away the MethodTypeCompanion implementation into a simple enum style choice for a newly added MethodType apply. The MethodType unapply is kept as it was for source compatibility, instead users are encouraged to use isImplicit and isContextual methods.
1 parent 95a8a9c commit d21642b

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
22042204
case _ => None
22052205
end MethodOrPolyTypeTest
22062206

2207+
type MethodTypeKind = dotc.core.Types.MethodTypeCompanion
2208+
2209+
object MethodTypeKind extends MethodTypeKindModule:
2210+
def Plain: MethodTypeKind = Types.MethodType
2211+
def Contextual: MethodTypeKind = Types.ContextualMethodType
2212+
def Implicit: MethodTypeKind = Types.ImplicitMethodType
2213+
22072214
type MethodType = dotc.core.Types.MethodType
22082215

22092216
object MethodTypeTypeTest extends TypeTest[TypeRepr, MethodType]:
@@ -2215,6 +2222,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
22152222
object MethodType extends MethodTypeModule:
22162223
def apply(paramNames: List[String])(paramInfosExp: MethodType => List[TypeRepr], resultTypeExp: MethodType => TypeRepr): MethodType =
22172224
Types.MethodType(paramNames.map(_.toTermName))(paramInfosExp, resultTypeExp)
2225+
def apply(kind: MethodTypeKind)(paramNames: List[String])(paramInfosExp: MethodType => List[TypeRepr], resultTypeExp: MethodType => TypeRepr): MethodType =
2226+
kind.apply(paramNames.map(_.toTermName))(paramInfosExp, resultTypeExp)
22182227
def unapply(x: MethodType): (List[String], List[TypeRepr], TypeRepr) =
22192228
(x.paramNames.map(_.toString), x.paramTypes, x.resType)
22202229
end MethodType
@@ -2223,6 +2232,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
22232232
extension (self: MethodType)
22242233
def isErased: Boolean = false
22252234
def isImplicit: Boolean = self.isImplicitMethod
2235+
def isContextual: Boolean = self.isContextualMethod
22262236
def param(idx: Int): TypeRepr = self.newParamRef(idx)
22272237

22282238
def erasedParams: List[Boolean] = self.erasedParams

library/src/scala/quoted/Quotes.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
211211
* +- MatchCase
212212
* +- TypeBounds
213213
* +- NoPrefix
214+
*
215+
* +- MethodTypeKind
214216
*
215217
* +- Selector -+- SimpleSelector
216218
* +- RenameSelector
@@ -3234,6 +3236,22 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
32343236
/** `TypeTest` that allows testing at runtime in a pattern match if a `TypeRepr` is a `MethodOrPoly` */
32353237
given MethodOrPolyTypeTest: TypeTest[TypeRepr, MethodOrPoly]
32363238

3239+
/** Type which decides on the kind of parameter list represented by `MethodType`. */
3240+
type MethodTypeKind
3241+
3242+
/** Module object of `type MethodKind` */
3243+
val MethodTypeKind: MethodTypeKindModule
3244+
3245+
/** Methods of the module object `val MethodKind` */
3246+
trait MethodTypeKindModule { this: MethodTypeKind.type =>
3247+
/** Represents a parameter list without any implicitness of parameters, like (x1: X1, x2: X2, ...) */
3248+
def Plain: MethodTypeKind
3249+
/** Represents a parameter list with implicit parameters, like `(implicit X1, ..., Xn)`, `(using X1, ..., Xn)`, `(using x1: X1, ..., xn: Xn)` */
3250+
def Implicit: MethodTypeKind
3251+
/** Represents a parameter list of a contextual method, like `(using X1, ..., Xn)` or `(using x1: X1, ..., xn: Xn)` */
3252+
def Contextual: MethodTypeKind
3253+
}
3254+
32373255
/** Type of the definition of a method taking a single list of parameters. It's return type may be a MethodType. */
32383256
type MethodType <: MethodOrPoly
32393257

@@ -3246,6 +3264,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
32463264
/** Methods of the module object `val MethodType` */
32473265
trait MethodTypeModule { this: MethodType.type =>
32483266
def apply(paramNames: List[String])(paramInfosExp: MethodType => List[TypeRepr], resultTypeExp: MethodType => TypeRepr): MethodType
3267+
def apply(kind: MethodTypeKind)(paramNames: List[String])(paramInfosExp: MethodType => List[TypeRepr], resultTypeExp: MethodType => TypeRepr): MethodType
32493268
def unapply(x: MethodType): (List[String], List[TypeRepr], TypeRepr)
32503269
}
32513270

@@ -3255,8 +3274,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
32553274
/** Extension methods of `MethodType` */
32563275
trait MethodTypeMethods:
32573276
extension (self: MethodType)
3258-
/** Is this the type of using parameter clause `(implicit X1, ..., Xn)`, `(using X1, ..., Xn)` or `(using x1: X1, ..., xn: Xn)` */
3277+
/** Is this the type of parameter clause like `(implicit X1, ..., Xn)`, `(using X1, ..., Xn)` or `(using x1: X1, ..., xn: Xn)` */
32593278
def isImplicit: Boolean
3279+
/** Is this the type of parameter clause like `(using X1, ..., Xn)` or `(using x1: X1, x2: X2, ... )` */
3280+
def isContextual: Boolean
32603281
/** Is this the type of erased parameter clause `(erased x1: X1, ..., xn: Xn)` */
32613282
@deprecated("Use `hasErasedParams` and `erasedParams`", "3.4")
32623283
def isErased: Boolean
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
trait Foo
2+
trait Bar
3+
4+
object Methods:
5+
def implicitMethod(implicit foo: Foo, int: Int): Bar = ???
6+
def contextualMethod(using foo: Foo, int: Int): Bar = ???
7+
def plainMethod(foo: Foo, int: Int): Bar = ???
8+
9+
object Macro:
10+
import scala.quoted._
11+
inline def macroCall(): Unit = ${ macroCallImpl }
12+
def macroCallImpl(using Quotes): Expr[Unit] =
13+
testReadingMethodTypeKind
14+
testCreatingMethodTypeKind
15+
'{()}
16+
17+
def testReadingMethodTypeKind(using Quotes) =
18+
import quotes.reflect._
19+
def getFromMethods(name: String): TypeRepr =
20+
val typeRepr = TypeRepr.of[Methods.type]
21+
val symbol =
22+
typeRepr.typeSymbol.methodMember(name).headOption.getOrElse(
23+
typeRepr.typeSymbol.fieldMember(name)
24+
)
25+
typeRepr.memberType(symbol)
26+
27+
assert(getFromMethods("implicitMethod").asInstanceOf[MethodType].isImplicit)
28+
assert(!getFromMethods("implicitMethod").asInstanceOf[MethodType].isContextual)
29+
30+
assert(getFromMethods("contextualMethod").asInstanceOf[MethodType].isImplicit)
31+
assert(getFromMethods("contextualMethod").asInstanceOf[MethodType].isContextual)
32+
33+
assert(!getFromMethods("plainMethod").asInstanceOf[MethodType].isImplicit)
34+
assert(!getFromMethods("plainMethod").asInstanceOf[MethodType].isContextual)
35+
36+
37+
def testCreatingMethodTypeKind(using Quotes) =
38+
import quotes.reflect._
39+
val paramTypes = List(TypeRepr.of[Foo], TypeRepr.of[Int])
40+
val resType = TypeRepr.of[Bar]
41+
val implicitMethodType = MethodType.apply(MethodTypeKind.Implicit)(List("foo", "int"))(mt => paramTypes, mt => resType)
42+
assert(implicitMethodType.isImplicit)
43+
assert(!implicitMethodType.isContextual)
44+
45+
val contextualMethodType = MethodType.apply(MethodTypeKind.Contextual)(List("foo", "int"))(mt => paramTypes, mt => resType)
46+
assert(contextualMethodType.isImplicit)
47+
assert(contextualMethodType.isContextual)
48+
49+
val plainMethodType = MethodType.apply(MethodTypeKind.Plain)(List("foo", "int"))(mt => paramTypes, mt => resType)
50+
assert(!plainMethodType.isContextual)
51+
assert(!plainMethodType.isImplicit)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test:
2+
def main(args: Array[String]): Unit =
3+
Macro.macroCall()

0 commit comments

Comments
 (0)