Skip to content

Commit 8cc0706

Browse files
committed
Lift arguments of explicitly constructed annotations
1 parent aa9db1f commit 8cc0706

File tree

5 files changed

+29
-9
lines changed

5 files changed

+29
-9
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ object Mode {
166166
*/
167167
val ForceInline: Mode = newMode(29, "ForceInline")
168168

169+
/** Are we typing an annotation? */
170+
val InAnnotation: Mode = newMode(30, "InAnnotation")
171+
169172
/** Skip inlining of methods. */
170173
val NoInline: Mode = newMode(31, "NoInline")
171174
}

compiler/src/dotty/tools/dotc/typer/Applications.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -694,9 +694,12 @@ trait Applications extends Compatibility {
694694
sym.is(JavaDefined) && sym.isConstructor && sym.owner.is(JavaAnnotation)
695695

696696

697-
/** Is `sym` a constructor of an annotation? */
698-
def isAnnotConstr(sym: Symbol): Boolean =
699-
sym.isConstructor && sym.owner.isAnnotation
697+
/** Is `sym` a constructor of an annotation class, and are we in an
698+
* annotation? If so, we don't lift arguments.
699+
* See #22035, #22526 and `dependent-annot-default-args.scala`.
700+
*/
701+
protected final def isAnnotConstr(sym: Symbol): Boolean =
702+
ctx.mode.is(Mode.InAnnotation) && sym.isConstructor && sym.owner.isAnnotation
700703

701704
/** Match re-ordered arguments against formal parameters
702705
* @param n The position of the first parameter in formals in `methType`.
@@ -994,9 +997,8 @@ trait Applications extends Compatibility {
994997
case (arg: NamedArg, _) => arg
995998
case (arg, name) => NamedArg(name, arg)
996999
}
997-
else if isAnnotConstr(methRef.symbol) then
998-
typedArgs
999-
else if !sameSeq(args, orderedArgs) && !typedArgs.forall(isSafeArg) then
1000+
else if !isAnnotConstr(methRef.symbol) && !sameSeq(args, orderedArgs) && !typedArgs.forall(isSafeArg)
1001+
then
10001002
// need to lift arguments to maintain evaluation order in the
10011003
// presence of argument reorderings.
10021004
// (never do this for Java annotation constructors, hence the 'else if')

compiler/src/dotty/tools/dotc/typer/Typer.scala

+6-3
Original file line numberDiff line numberDiff line change
@@ -2779,7 +2779,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27792779
def isInner(owner: Symbol) = owner == sym || sym.is(Param) && owner == sym.owner
27802780
val outer = ctx.outersIterator.dropWhile(c => isInner(c.owner)).next()
27812781
def local: FreshContext = outer.fresh.setOwner(newLocalDummy(sym.owner))
2782-
sym.owner.infoOrCompleter match
2782+
val ctx0 = sym.owner.infoOrCompleter match
27832783
case completer: Namer#Completer
27842784
if sym.is(Param) && completer.completerTypeParams(sym).nonEmpty =>
27852785
// Create a new local context with a dummy owner and a scope containing the
@@ -2788,6 +2788,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27882788
local.setScope(newScopeWith(completer.completerTypeParams(sym)*))
27892789
case _ =>
27902790
if outer.owner.isClass then local else outer
2791+
ctx0.addMode(Mode.InAnnotation)
27912792

27922793
def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(using Context): Unit = {
27932794
// necessary to force annotation trees to be computed.
@@ -2802,7 +2803,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28022803
}
28032804

28042805
def typedAnnotation(annot: untpd.Tree)(using Context): Tree =
2805-
checkAnnotClass(checkAnnotArgs(typed(annot)))
2806+
val typedAnnot = withMode(Mode.InAnnotation)(typed(annot))
2807+
checkAnnotClass(checkAnnotArgs(typedAnnot))
28062808

28072809
def registerNowarn(tree: Tree, mdef: untpd.Tree)(using Context): Unit =
28082810
val annot = Annotations.Annotation(tree)
@@ -3335,7 +3337,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33353337
end typedPackageDef
33363338

33373339
def typedAnnotated(tree: untpd.Annotated, pt: Type)(using Context): Tree = {
3338-
val annot1 = checkAnnotClass(typedExpr(tree.annot))
3340+
val annot0 = withMode(Mode.InAnnotation)(typedExpr(tree.annot))
3341+
val annot1 = checkAnnotClass(annot0)
33393342
val annotCls = Annotations.annotClass(annot1)
33403343
if annotCls == defn.NowarnAnnot then
33413344
registerNowarn(annot1, tree)

tests/printing/dependent-annot-default-args.check

+9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ package <empty> {
4141
@annot2(
4242
y = Array.apply[Any](["Hello",y : Any]*)(scala.reflect.ClassTag.Any))
4343
val z4: Int = 45
44+
val z5: annot2 =
45+
{
46+
val y$1: Array[Any] =
47+
Array.apply[Any](["World" : Any]*)(scala.reflect.ClassTag.Any)
48+
new annot2(x = 1, y = y$1)
49+
}
50+
val z6: annot2 =
51+
new annot2(x = 1,
52+
y = Array.apply[Any](["World" : Any]*)(scala.reflect.ClassTag.Any))
4453
()
4554
}
4655
}

tests/printing/dependent-annot-default-args.scala

+3
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ def test =
1313
@annot(44) val z3 = 45
1414
@annot2(y = Array("Hello", y)) val z4 = 45
1515

16+
// Arguments are still lifted if the annotation class is instantiated
17+
// explicitly. See #22526.
18+
val z5 = new annot2(y = Array("World"), x = 1)

0 commit comments

Comments
 (0)