Skip to content

Commit

Permalink
Let annotations on parameters see preceding type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
odersky authored and BarkingBad committed Jul 23, 2021
1 parent 24e5777 commit d80e1d7
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 5 deletions.
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ class Namer { typer: Typer =>
case original: DefDef =>
val typer1 = ctx.typer.newLikeThis
nestedTyper(sym) = typer1
typer1.defDefSig(original, sym)(using localContext(sym).setTyper(typer1))
typer1.defDefSig(original, sym, this)(using localContext(sym).setTyper(typer1))
case imp: Import =>
try
val expr1 = typedImportQualifier(imp, typedAheadExpr(_, _)(using ctx.withOwner(sym)))
Expand Down Expand Up @@ -733,6 +733,15 @@ class Namer { typer: Typer =>
completer.complete(denot)
}

private var completedTypeParamSyms: List[TypeSymbol] = null

def setCompletedTypeParams(tparams: List[TypeSymbol]) =
completedTypeParamSyms = tparams

override def completerTypeParams(sym: Symbol)(using Context): List[TypeSymbol] =
if completedTypeParamSyms != null then completedTypeParamSyms
else Nil

protected def addAnnotations(sym: Symbol): Unit = original match {
case original: untpd.MemberDef =>
lazy val annotCtx = annotContext(original, sym)
Expand Down Expand Up @@ -1639,7 +1648,7 @@ class Namer { typer: Typer =>
}

/** The type signature of a DefDef with given symbol */
def defDefSig(ddef: DefDef, sym: Symbol)(using Context): Type = {
def defDefSig(ddef: DefDef, sym: Symbol, completer: Namer#Completer)(using Context): Type = {
// Beware: ddef.name need not match sym.name if sym was freshened!
val isConstructor = sym.name == nme.CONSTRUCTOR

Expand Down Expand Up @@ -1668,8 +1677,8 @@ class Namer { typer: Typer =>
// 5. Info of CP is copied to DP and DP is completed.
index(ddef.leadingTypeParams)
if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
for (tparam <- ddef.leadingTypeParams) typedAheadExpr(tparam)

completer.setCompletedTypeParams(
for tparam <- ddef.leadingTypeParams yield typedAheadExpr(tparam).symbol.asType)
ddef.trailingParamss.foreach(completeParams)
val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
sym.setParamss(paramSymss)
Expand Down
13 changes: 12 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2081,10 +2081,21 @@ class Typer extends Namer
def annotContext(mdef: untpd.Tree, sym: Symbol)(using Context): Context = {
def isInner(owner: Symbol) = owner == sym || sym.is(Param) && owner == sym.owner
val outer = ctx.outersIterator.dropWhile(c => isInner(c.owner)).next()
outer.property(ExprOwner) match {
var adjusted = outer.property(ExprOwner) match {
case Some(exprOwner) if outer.owner.isClass => outer.exprContext(mdef, exprOwner)
case _ => outer
}
sym.owner.infoOrCompleter match
case completer: Namer#Completer if sym.is(Param) =>
val tparams = completer.completerTypeParams(sym)
if tparams.nonEmpty then
// Create a new local context with a dummy owner and a scope containing the
// type parameters of the enclosing method or class. This annotations can see
// these type parameters. See i12953.scala for a test case.
val dummyOwner = newLocalDummy(sym.owner)
adjusted = adjusted.fresh.setOwner(dummyOwner).setScope(newScopeWith(tparams*))
case _ =>
adjusted
}

def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(using Context): Unit = {
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i12953.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Schema(impl: Class[_]) extends scala.annotation.StaticAnnotation

class Ann[A] extends scala.annotation.StaticAnnotation

case class Foo[A](@Schema(classOf[List[A]]) foo: String)
case class Bar[A](@Ann[A] foo: String)
def baz[A](@Ann[A] foo: String) = ()

0 comments on commit d80e1d7

Please sign in to comment.