Skip to content

Commit 27c6866

Browse files
committed
Various tests and test-fixes for erasedDefinitions feature
- Change tests in accordance to new erased parameter Quotes API - Add quotes test for some erased parameters APIs - Add tests for Reflect `hasErasedParams`/`erasedParams` and creating an erased method
1 parent c52881f commit 27c6866

26 files changed

+152
-22
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1834,7 +1834,7 @@ object desugar {
18341834
cpy.ByNameTypeTree(parent)(annotate(tpnme.retainsByName, restpt))
18351835
case _ =>
18361836
annotate(tpnme.retains, parent)
1837-
case f: FunctionWithMods if f.erasedParams.contains(true) => makeFunctionWithValDefs(f, pt)
1837+
case f: FunctionWithMods if f.hasErasedParams => makeFunctionWithValDefs(f, pt)
18381838
}
18391839
desugared.withSpan(tree.span)
18401840
}

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
8080
class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers, val erasedParams: List[Boolean])(implicit @constructorOnly src: SourceFile)
8181
extends Function(args, body) {
8282
assert(args.length == erasedParams.length)
83+
84+
def hasErasedParams = erasedParams.contains(true)
8385
}
8486

8587
/** A polymorphic function type */

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,11 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
648648
case tp: MethodType =>
649649
def paramErasure(tpToErase: Type) =
650650
erasureFn(sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK)(tpToErase)
651-
val (names, formals0) = if (tp.hasErasedParams)
651+
val (names, formals0) = if tp.hasErasedParams then
652652
tp.paramNames
653653
.zip(tp.paramInfos)
654654
.zip(tp.erasedParams)
655-
.flatMap((p, e) => if e then None else Some(p))
655+
.collect{ case (param, isErased) if !isErased => param }
656656
.unzip
657657
else (tp.paramNames, tp.paramInfos)
658658
val formals = formals0.mapConserve(paramErasure)

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3734,7 +3734,7 @@ object Types {
37343734
val params = if (hasErasedParams)
37353735
tp.paramInfos
37363736
.zip(tp.erasedParams)
3737-
.flatMap((p, e) => if e then None else Some(p))
3737+
.collect { case (param, isErased) if !isErased => param }
37383738
else tp.paramInfos
37393739
resultSignature.prependTermParams(params, sourceLanguage)
37403740
case tp: PolyType =>

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ class PlainPrinter(_ctx: Context) extends Printer {
235235
changePrec(GlobalPrec) {
236236
"("
237237
~ keywordText("using ").provided(tp.isContextualMethod)
238-
~ keywordText("erased ").provided(tp.isErasedMethod)
239238
~ keywordText("implicit ").provided(tp.isImplicitMethod && !tp.isContextualMethod)
240239
~ paramsText(tp)
241240
~ ")"

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
287287
case tp @ FunProto(args, resultType) =>
288288
"[applied to ("
289289
~ keywordText("using ").provided(tp.isContextualMethod)
290-
~ keywordText("erased ").provided(tp.isErasedMethod)
291290
~ argsTreeText(args)
292291
~ ") returning "
293292
~ toText(resultType)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,9 +1584,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
15841584
def isErased: Boolean = false
15851585

15861586
def erasedArgs: List[Boolean] =
1587-
self.map(param => param.tpe.hasAnnotation(dotc.core.Symbols.defn.ErasedParamAnnot))
1587+
self.map(_.symbol.is(dotc.core.Flags.Erased))
15881588
def hasErasedArgs: Boolean =
1589-
self.exists(param => param.tpe.hasAnnotation(dotc.core.Symbols.defn.ErasedParamAnnot))
1589+
self.exists(_.symbol.is(dotc.core.Flags.Erased))
15901590
end TermParamClauseMethods
15911591

15921592
type TypeParamClause = List[tpd.TypeDef]

library/src/scala/quoted/Quotes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2374,7 +2374,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
23742374
/** Is this a given parameter clause `(using X1, ..., Xn)` or `(using x1: X1, ..., xn: Xn)` */
23752375
def isGiven: Boolean
23762376
/** Is this a erased parameter clause `(erased x1: X1, ..., xn: Xn)` */
2377-
// TODO:deprecate in 3.4 and stabilize `erasedParams` and `hasErasedParams`.
2377+
// TODO:deprecate in 3.4 and stabilize `erasedArgs` and `hasErasedArgs`.
23782378
// @deprecated("Use `hasErasedArgs`","3.4")
23792379
def isErased: Boolean
23802380

tests/neg/safeThrowsStrawman2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def bar(x: Boolean)(using CanThrow[Fail]): Int =
2424
val x = new CanThrow[Fail]() // OK, x is erased
2525
val y: Any = new CanThrow[Fail]() // error: illegal reference to erased class CanThrow
2626
val y2: Any = new CTF() // error: illegal reference to erased class CanThrow
27-
println(foo(true, ctf)) // error: ctf is declared as erased, but is in fact used
27+
println(foo(true, ctf)) // not error: ctf will be erased at erasure
2828
val a = (1, new CanThrow[Fail]()) // error: illegal reference to erased class CanThrow
2929
def b: (Int, CanThrow[Fail]) = ???
3030
def c = b._2 // ok; we only check creation sites

tests/run-custom-args/erased/erased-15.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.compiletime.ErasedFunction
1+
import scala.runtime.ErasedFunction
22

33
object Test {
44

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
block
2-
x
32
foo
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
x
21
foo
3-
x
42
bar
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
27
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test {
2+
erased class Erased() {
3+
println("Oh no!!!")
4+
}
5+
6+
def f(x: Erased, y: Int = 0): Int = y + 5
7+
8+
def g() = Erased()
9+
10+
def main(args: Array[String]) =
11+
val y = Erased()
12+
val z = 10
13+
println(f(Erased()) + z + f(g(), 7))
14+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import scala.annotation.MacroAnnotation
2+
import scala.annotation.internal.ErasedParam
3+
import scala.quoted._
4+
5+
class NewAnnotation extends scala.annotation.Annotation
6+
7+
class erasedParamsMethod extends MacroAnnotation:
8+
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
9+
import quotes.reflect._
10+
tree match
11+
case ClassDef(name, ctr, parents, self, body) =>
12+
val erasedInt = AnnotatedType(TypeRepr.of[Int], '{ new ErasedParam }.asTerm)
13+
val methType = MethodType(List("x", "y"))(_ => List(erasedInt, TypeRepr.of[Int]), _ => TypeRepr.of[Int])
14+
15+
assert(methType.hasErasedParams)
16+
assert(methType.erasedParams == List(true, false))
17+
18+
val methSym = Symbol.newMethod(tree.symbol, "takesErased", methType, Flags.EmptyFlags, Symbol.noSymbol)
19+
val methDef = DefDef(methSym, _ => Some(Literal(IntConstant(1))))
20+
21+
val clsDef = ClassDef.copy(tree)(name, ctr, parents, self, methDef :: body)
22+
23+
List(clsDef)
24+
case _ =>
25+
report.error("Annotation only supports `class`")
26+
List(tree)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import scala.language.experimental.erasedDefinitions
2+
3+
class TakesErased {
4+
def takesErased(erased x: Int, y: Int): Int = ???
5+
}
6+
7+
@erasedParamsMethod class Foo extends TakesErased
8+
9+
@main def Test() =
10+
val foo = Foo()
11+
val v = foo.takesErased(1, 2)
12+
println(v)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
method <init>: () isGiven=false isImplicit=false erasedArgs=List()
2+
method m1: (i: scala.Int) isGiven=true isImplicit=false erasedArgs=List(false)
3+
method m2: (i: scala.Int) isGiven=false isImplicit=false erasedArgs=List(true)
4+
method m3: (i: scala.Int, j: scala.Int) isGiven=false isImplicit=false erasedArgs=List(false, true)
5+
method m4: (i: EC) isGiven=false isImplicit=false erasedArgs=List(true)
6+
val l1: scala.ContextFunction1[scala.Int, scala.Int]
7+
val l2: scala.runtime.ErasedFunction with apply: (x$0: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true)
8+
val l3: scala.runtime.ErasedFunction with apply: (x$0: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=true erasedParams=List(true)
9+
val l4: scala.runtime.ErasedFunction with apply: (x$0: scala.Int, x$1: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(false, true)
10+
val l5: scala.runtime.ErasedFunction with apply: (x$0: EC @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import scala.quoted.*
2+
3+
inline def inspect[A]: String =
4+
${ inspect2[A] }
5+
6+
def inspect2[A: Type](using Quotes): Expr[String] = {
7+
import quotes.reflect.*
8+
9+
val methods = TypeRepr.of[A].typeSymbol.declarations
10+
val names = methods.map { m =>
11+
m.tree match
12+
case dd @ DefDef(name, params, r, body) =>
13+
val paramStr =
14+
params.map {
15+
case ps: TermParamClause =>
16+
val params = ps.params.map(p => s"${p.name}: ${p.tpt.show}").mkString("(", ", ", ")")
17+
s"$params isGiven=${ps.isGiven} isImplicit=${ps.isImplicit} erasedArgs=${ps.erasedArgs}"
18+
case ps: TypeParamClause => ps.params.map(_.show).mkString("[", ", ", "]")
19+
}.mkString("")
20+
s"method $name: $paramStr"
21+
case vd @ ValDef(name, tpt, body) =>
22+
tpt.tpe match
23+
case Refinement(parent, "apply", tpe: MethodType) if parent == defn.ErasedFunctionClass.typeRef =>
24+
assert(tpt.tpe.isErasedFunctionType)
25+
26+
val params = tpe.paramNames.zip(tpe.paramTypes).map((n, t) => s"$n: ${t.show}").mkString("(", ", ", ")")
27+
s"val $name: ${parent.show} with apply: ${params} isImplicit=${tpe.isImplicit} erasedParams=${tpe.erasedParams}"
28+
case _ =>
29+
s"val $name: ${tpt.show}"
30+
case td @ TypeDef(name, tpt) => s"type $name: ${tpt.show}"
31+
case _ => s"something else: $m"
32+
}
33+
34+
Expr(names.mkString("\n"))
35+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import scala.language.experimental.erasedDefinitions
2+
3+
erased class EC
4+
5+
trait X {
6+
def m1(using i: Int): Int
7+
def m2(erased i: Int): Int
8+
def m3(i: Int, erased j: Int): Int
9+
def m4(i: EC): Int
10+
11+
val l1 = (x: Int) ?=> 5
12+
val l2 = (erased x: Int) => 5
13+
val l3 = (erased x: Int) ?=> 5
14+
val l4 = (x: Int, erased y: Int) => 5
15+
val l5 = (x: EC) => 5
16+
}
17+
18+
@main def Test = {
19+
println(inspect[X])
20+
}

tests/run-custom-args/run-macros-erased/macro-erased/1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ object Macro {
1313
def case1(erased i: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
1414
def case2 (i: Int)(erased j: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
1515
def case3(erased i: Expr[Int]) (j: Int)(using Quotes): Expr[Int] = '{ 0 }
16-
def case4 (h: Int)(erased i: Expr[Int], j: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
17-
def case5(erased i: Expr[Int], j: Expr[Int]) (h: Int)(using Quotes): Expr[Int] = '{ 0 }
16+
def case4 (h: Int)(erased i: Expr[Int], erased j: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
17+
def case5(erased i: Expr[Int], erased j: Expr[Int]) (h: Int)(using Quotes): Expr[Int] = '{ 0 }
1818
def case6 (h: Int)(erased i: Expr[Int])(erased j: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
1919
def case7(erased i: Expr[Int]) (h: Int)(erased j: Expr[Int])(using Quotes): Expr[Int] = '{ 0 }
2020
def case8(erased i: Expr[Int])(erased j: Expr[Int]) (h: Int)(using Quotes): Expr[Int] = '{ 0 }

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ val experimentalDefinitionInLibrary = Set(
8181
"scala.quoted.Quotes.reflectModule.SymbolModule.newModule",
8282
"scala.quoted.Quotes.reflectModule.SymbolModule.freshName",
8383
"scala.quoted.Quotes.reflectModule.SymbolMethods.info",
84+
// Quotes for functions with erased parameters.
85+
"scala.quoted.Quotes.reflectModule.MethodTypeMethods.erasedParams",
86+
"scala.quoted.Quotes.reflectModule.MethodTypeMethods.hasErasedParams",
87+
"scala.quoted.Quotes.reflectModule.TermParamClauseMethods.erasedArgs",
88+
"scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs",
89+
"scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass",
8490

8591
// New feature: functions with erased parameters.
8692
// Need erasedDefinitions enabled.

tests/run-macros/i12021.check

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
X1: (i: scala.Int) isImplicit=true, isGiven=false, isErased=false
2-
X2: (i: scala.Int) isImplicit=false, isGiven=true, isErased=false
3-
X3: (i: scala.Int) isImplicit=false, isGiven=false, isErased=true
1+
X1: (i: scala.Int) isImplicit=true, isGiven=false, erasedArgs=List(false)
2+
X2: (i: scala.Int) isImplicit=false, isGiven=true, erasedArgs=List(false)
3+
X3: (i: scala.Int) isImplicit=false, isGiven=false, erasedArgs=List(true)
4+
X4: (i: scala.Int, j: scala.Int) isImplicit=false, isGiven=false, erasedArgs=List(false, true)
5+
X5: (i: EC) isImplicit=false, isGiven=false, erasedArgs=List(true)

tests/run-macros/i12021/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ def inspect2[A: Type](using Quotes): Expr[String] = {
1414

1515
val names = ps.params.map(p => s"${p.name}: ${p.tpt.show}").mkString("(", ", ", ")")
1616

17-
Expr(s"${Type.show[A]}: $names isImplicit=${ps.isImplicit}, isGiven=${ps.isGiven}, isErased=${ps.isErased}")
17+
Expr(s"${Type.show[A]}: $names isImplicit=${ps.isImplicit}, isGiven=${ps.isGiven}, erasedArgs=${ps.erasedArgs}")
1818
}

tests/run-macros/i12021/Test_2.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import scala.language.experimental.erasedDefinitions
22

3+
erased class EC
4+
35
class X1(implicit i: Int)
46
class X2(using i: Int)
57
class X3(erased i: Int)
8+
class X4(i: Int, erased j: Int)
9+
class X5(i: EC)
610

711
@main def Test = {
812
println(inspect[X1])
913
println(inspect[X2])
1014
println(inspect[X3])
11-
}
15+
println(inspect[X4])
16+
println(inspect[X5])
17+
}

tests/run-macros/tasty-definitions-1.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ ContextFunction24
108108
ContextFunction24
109109
ContextFunction25
110110
ContextFunction25
111-
class java.lang.Exception: Erased function classes are not supported. Use a refined `ErasedFunctionClass`
111+
class java.lang.Exception: Erased function classes are not supported. Use a refined `scala.runtime.ErasedFunction`
112112
ErasedFunction
113113
Tuple2
114114
Tuple3

0 commit comments

Comments
 (0)