From d80e1d7c7bd4638ef87899c815f741bbf83337ab Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Jun 2021 13:14:43 +0200 Subject: [PATCH] Let annotations on parameters see preceding type parameters Fixes #12953 --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 17 +++++++++++++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 13 ++++++++++++- tests/pos/i12953.scala | 7 +++++++ 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i12953.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 6a47cf143d62..33c7cb499d33 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -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))) @@ -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) @@ -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 @@ -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) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 989f65215377..ad773799d8ad 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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 = { diff --git a/tests/pos/i12953.scala b/tests/pos/i12953.scala new file mode 100644 index 000000000000..a50bbda70187 --- /dev/null +++ b/tests/pos/i12953.scala @@ -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) = ()