Skip to content

Commit e5bafcc

Browse files
committed
Add reflect TypeLambda.declaredVariances
Fixes #16734
1 parent ca7c29f commit e5bafcc

File tree

6 files changed

+120
-0
lines changed

6 files changed

+120
-0
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -2212,6 +2212,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
22122212
extension (self: TypeLambda)
22132213
def param(idx: Int): TypeRepr = self.newParamRef(idx)
22142214
def paramBounds: List[TypeBounds] = self.paramInfos
2215+
def declaredVariances: List[Flags] =
2216+
if self.isDeclaredVarianceLambda then self.declaredVariances
2217+
else self.paramNames.map(_ => Flags.EmptyFlags)
22152218
end extension
22162219
end TypeLambdaMethods
22172220

library/src/scala/quoted/Quotes.scala

+8
Original file line numberDiff line numberDiff line change
@@ -3235,8 +3235,16 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
32353235
/** Extension methods of `TypeLambda` */
32363236
trait TypeLambdaMethods:
32373237
extension (self: TypeLambda)
3238+
/** Reference to the i-th parameter */
3239+
/** Type bounds of the i-th parameter */
32383240
def param(idx: Int) : TypeRepr
32393241
def paramBounds: List[TypeBounds]
3242+
/** Variance flags for the i-th parameter
3243+
*
3244+
* Variance flags can be one of `Flags.{Covariant, Contravariant, EmptyFlags}`.
3245+
*/
3246+
@experimental
3247+
def declaredVariances: List[Flags]
32403248
end extension
32413249
end TypeLambdaMethods
32423250

tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ val experimentalDefinitionInLibrary = Set(
6666
// Should be stabilized in 3.4.0
6767
"scala.quoted.Quotes.reflectModule.defnModule.FunctionClass",
6868
"scala.quoted.Quotes.reflectModule.FlagsModule.AbsOverride",
69+
"scala.quoted.Quotes.reflectModule.TypeLambdaMethods.declaredVariances",
6970
// Can be stabilized in 3.4.0 (unsure) or later
7071
"scala.quoted.Quotes.reflectModule.CompilationInfoModule.XmacroSettings",
7172
"scala.quoted.Quotes.reflectModule.FlagsModule.JavaAnnotation",

tests/run-macros/i16734.check

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
trait K1Inv
2+
F
3+
A
4+
5+
trait K1Cov
6+
F
7+
+A
8+
9+
trait K1Con
10+
F
11+
-A
12+
13+
trait K2InvInv
14+
F
15+
A, B
16+
17+
trait K2InvCov
18+
F
19+
A, +B
20+
21+
trait K2InvCon
22+
F
23+
A, -B
24+
25+
trait K2CovInv
26+
F
27+
+A, B
28+
29+
trait K2CovCov
30+
F
31+
+A, +B
32+
33+
trait K2CovCon
34+
F
35+
+A, -B
36+
37+
trait K2ConInv
38+
F
39+
-A, B
40+
41+
trait K2ConCov
42+
F
43+
-A, +B
44+
45+
trait K2ConCon
46+
F
47+
-A, -B
48+
49+
trait KFunky
50+
G
51+
A, +B, -C, D, +E, -F
52+
X1, +Y1, -Z1
53+
X2, +Y2, -Z2
54+
X3, +Y3, -Z3
55+

tests/run-macros/i16734/Macro_1.scala

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted.*
2+
3+
inline def variances[A <: AnyKind]: String =
4+
${variancesImpl[A]}
5+
6+
def variancesImpl[A <: AnyKind: Type](using Quotes): Expr[String] =
7+
import quotes.reflect.*
8+
def loop(tpe: TypeRepr): List[String] =
9+
tpe match
10+
case tpe: TypeLambda =>
11+
tpe.paramNames.zip(tpe.declaredVariances).map { (name, variance) =>
12+
if variance == Flags.Covariant then "+" + name
13+
else if variance == Flags.Contravariant then "-" + name
14+
else name
15+
}.mkString(", ") :: tpe.paramTypes.flatMap(loop)
16+
case tpe: TypeBounds =>
17+
loop(tpe.low) ++ loop(tpe.hi)
18+
case _ =>
19+
Nil
20+
val res = (TypeRepr.of[A].typeSymbol :: loop(TypeRepr.of[A])).mkString("", "\n", "\n")
21+
Expr(res)

tests/run-macros/i16734/Test_2.scala

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
trait K1Inv[F[A]]
2+
trait K1Cov[F[+A]]
3+
trait K1Con[F[-A]]
4+
5+
trait K2InvInv[F[A, B]]
6+
trait K2InvCov[F[A, +B]]
7+
trait K2InvCon[F[A, -B]]
8+
trait K2CovInv[F[+A, B]]
9+
trait K2CovCov[F[+A, +B]]
10+
trait K2CovCon[F[+A, -B]]
11+
trait K2ConInv[F[-A, B]]
12+
trait K2ConCov[F[-A, +B]]
13+
trait K2ConCon[F[-A, -B]]
14+
15+
16+
trait KFunky[G[A, +B, -C, D[X1, +Y1, -Z1], +E[X2, +Y2, -Z2], -F[X3, +Y3, -Z3]]]
17+
18+
19+
@main def Test =
20+
println(variances[K1Inv])
21+
println(variances[K1Cov])
22+
println(variances[K1Con])
23+
println(variances[K2InvInv])
24+
println(variances[K2InvCov])
25+
println(variances[K2InvCon])
26+
println(variances[K2CovInv])
27+
println(variances[K2CovCov])
28+
println(variances[K2CovCon])
29+
println(variances[K2ConInv])
30+
println(variances[K2ConCov])
31+
println(variances[K2ConCon])
32+
println(variances[KFunky])

0 commit comments

Comments
 (0)