Skip to content

Commit

Permalink
Do not lift annotation arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
mbovel committed Nov 26, 2024
1 parent fcbb372 commit 84d83e3
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 37 deletions.
11 changes: 5 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,17 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>

/** All term arguments of an application in a single flattened list */
def allTermArguments(tree: Tree): List[Tree] = unsplice(tree) match {
case Apply(fn, args) => allTermArguments(fn) ::: args
case Apply(fn, args) => allTermArguments(fn) ::: args.map(stripNamedArg)
case TypeApply(fn, args) => allTermArguments(fn)
// TOOD(mbovel): is it really safe to skip all blocks here and in `allArguments`?
case Block(_, expr) => allTermArguments(expr)
case Block(Nil, expr) => allTermArguments(expr)
case _ => Nil
}

/** All type and term arguments of an application in a single flattened list */
def allArguments(tree: Tree): List[Tree] = unsplice(tree) match {
case Apply(fn, args) => allArguments(fn) ::: args
case TypeApply(fn, args) => allArguments(fn) ::: args
case Block(_, expr) => allArguments(expr)
case Apply(fn, args) => allArguments(fn) ::: args.map(stripNamedArg)
case TypeApply(fn, args) => allArguments(fn) ::: args.map(stripNamedArg)
case Block(Nil, expr) => allArguments(expr)
case _ => Nil
}

Expand Down
15 changes: 8 additions & 7 deletions compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,14 @@ extension (tree: Tree)
refs

/** The arguments of a @retains, @retainsCap or @retainsByName annotation */
def retainedElems(using Context): List[Tree] = tree match
case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) =>
elems
case _ =>
if tree.symbol.maybeOwner == defn.RetainsCapAnnot
then ref(defn.captureRoot.termRef) :: Nil
else Nil
def retainedElems(using Context): List[Tree] =
tpd.allTermArguments(tree) match
case List(Typed(SeqLiteral(elems, _), _)) =>
elems
case _ =>
if tree.symbol.maybeOwner == defn.RetainsCapAnnot
then ref(defn.captureRoot.termRef) :: Nil
else Nil

extension (tp: Type)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def recur(t: untpd.Tree): Text = t match
case Apply(fn, Nil) => recur(fn)
case Apply(fn, args) =>
val explicitArgs = args.filterNot(_.symbol.name.is(DefaultGetterName))
val explicitArgs = args.filterNot(untpd.stripNamedArg(_).symbol.name.is(DefaultGetterName))
recur(fn) ~ "(" ~ toTextGlobal(explicitArgs, ", ") ~ ")"
case TypeApply(fn, args) => recur(fn) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
case Select(qual, nme.CONSTRUCTOR) => recur(qual)
Expand Down
9 changes: 7 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ trait Applications extends Compatibility {
case tp => args.size
}

!isJavaAnnotConstr(methRef.symbol) &&
!isAnnotConstr(methRef.symbol) &&
args.size < requiredArgNum(funType)
}

Expand Down Expand Up @@ -662,6 +662,11 @@ trait Applications extends Compatibility {
def isJavaAnnotConstr(sym: Symbol): Boolean =
sym.is(JavaDefined) && sym.isConstructor && sym.owner.is(JavaAnnotation)


/** Is `sym` a constructor of an annotation? */
def isAnnotConstr(sym: Symbol): Boolean =
sym.isConstructor && sym.owner.isAnnotation

/** Match re-ordered arguments against formal parameters
* @param n The position of the first parameter in formals in `methType`.
*/
Expand Down Expand Up @@ -951,7 +956,7 @@ trait Applications extends Compatibility {
val app1 =
if !success then app0.withType(UnspecifiedErrorType)
else {
if isJavaAnnotConstr(methRef.symbol) then
if isAnnotConstr(methRef.symbol) then
// #19951 Make sure all arguments are NamedArgs for Java annotations
if typedArgs.exists(!_.isInstanceOf[NamedArg]) then
typedArgs = typedArgs.lazyZip(methType.asInstanceOf[MethodType].paramNames).map {
Expand Down
35 changes: 15 additions & 20 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1415,26 +1415,21 @@ trait Checking {
/** Check arguments of annotations */
private def checkAnnotTree(tree: Tree)(using Context): Tree =
val cls = Annotations.annotClass(tree)
tree match
case Apply(tycon, arg :: Nil) if cls == defn.TargetNameAnnot =>
arg match
case Literal(Constant("")) =>
report.error(em"target name cannot be empty", arg.srcPos)
case Literal(_) => // ok
case _ =>
report.error(em"@${cls.name} needs a string literal as argument", arg.srcPos)
tree
case _ =>
tree.find(!isValidAnnotSubtree(_)) match
case None => tree
case Some(invalidSubTree) =>
errorTree(
EmptyTree,
em"""Implementation restriction: expression cannot be used inside an annotation argument.
|Tree: ${invalidSubTree}
|Type: ${invalidSubTree.tpe}""",
invalidSubTree.srcPos
)
if cls == defn.TargetNameAnnot then
allArguments(tree) match
case List(Literal(Constant(name: String))) if !name.isEmpty => tree
case _ => errorTree(tree, em"@${cls.name} needs a non-empty string literal as argument")
else
tree.find(!isValidAnnotSubtree(_)) match
case None => tree
case Some(invalidSubTree) =>
errorTree(
EmptyTree,
em"""Implementation restriction: expression cannot be used inside an annotation argument.
|Tree: ${invalidSubTree}
|Type: ${invalidSubTree.tpe}""",
invalidSubTree.srcPos
)

/** Returns `true` if this tree can appear inside an annotation argument. */
private def isValidAnnotSubtree(subTree: Tree) =
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/annot-printing.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
5 |def x: Int @nowarn @main @Foo @Bar("hello") = "abc" // error
| ^^^^^
| Found: ("abc" : String)
| Required: Int @nowarn() @main @Foo @Bar("hello")
| Required: Int @nowarn() @main @Foo @Bar(s = "hello")
|
| longer explanation available when compiling with `-explain`

0 comments on commit 84d83e3

Please sign in to comment.