Skip to content

Commit 8681a2d

Browse files
committed
Don't skip the ValTypeCompleter in the AccessorTypeCompleter
When the AccessorTypeCompleter gets the type signature of the ValDef, ensure that the ValTypeCompleter runs (which sets the annotations on the field symbol) instead of just calling typeSig. Fixes scala/bug#10471
1 parent 6ac6da8 commit 8681a2d

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -919,11 +919,16 @@ trait Namers extends MethodSynthesis {
919919
// while `valDef` is the field definition that spawned the accessor
920920
// NOTE: `valTypeCompleter` handles abstract vals, trait vals and lazy vals, where the ValDef carries the getter's symbol
921921

922-
// reuse work done in valTypeCompleter if we already computed the type signature of the val
923-
// (assuming the field and accessor symbols are distinct -- i.e., we're not in a trait)
922+
valDef.symbol.rawInfo match {
923+
case c: ValTypeCompleter =>
924+
// If the field and accessor symbols are distinct, i.e., we're not in a trait, invoke the
925+
// valTypeCompleter. This ensures that field annotations are set correctly (scala/bug#10471).
926+
c.completeImpl(valDef.symbol)
927+
case _ =>
928+
}
924929
val valSig =
925-
if ((accessorSym ne valDef.symbol) && valDef.symbol.isInitialized) valDef.symbol.info
926-
else typeSig(valDef, Nil) // don't set annotations for the valdef -- we just want to compute the type sig (TODO: dig deeper and see if we can use memberSig)
930+
if (valDef.symbol.isInitialized) valDef.symbol.info // re-use an already computed type
931+
else typeSig(valDef, Nil) // Don't pass any annotations to set on the valDef.symbol, just compute the type sig (TODO: dig deeper and see if we can use memberSig)
927932

928933
// patch up the accessor's tree if the valdef's tpt was not known back when the tree was synthesized
929934
// can't look at `valDef.tpt` here because it may have been completed by now (this is why we pass in `missingTpt`)
@@ -1363,6 +1368,7 @@ trait Namers extends MethodSynthesis {
13631368

13641369
// provisionally assign `meth` a method type with inherited result type
13651370
// that way, we can leave out the result type even if method is recursive.
1371+
// this also prevents cycles in implicit search, see comment in scala/bug#10471
13661372
meth setInfo deskolemizedPolySig(vparamSymss, overriddenResTp)
13671373
overriddenResTp
13681374
} else resTpGiven

test/files/run/t10471.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import scala.tools.partest._
2+
3+
object Test extends StoreReporterDirectTest {
4+
override def extraSettings: String = "-usejavacp -Xprint:typer -Ystop-after:typer"
5+
6+
override def code =
7+
"""@scala.annotation.meta.field class blort extends scala.annotation.StaticAnnotation
8+
|class C1 {
9+
| @blort val foo = "hi"
10+
|}
11+
|object X {
12+
| def accessIt(c: C2) = c.foo
13+
|}
14+
|class C2 extends C1 {
15+
| @blort override val foo = "bye"
16+
|}
17+
""".stripMargin
18+
19+
def show(): Unit = {
20+
val baos = new java.io.ByteArrayOutputStream()
21+
Console.withOut(baos)(Console.withErr(baos)(compile()))
22+
val out = baos.toString("UTF-8")
23+
24+
val fooDefs = out.lines.filter(_.contains("private[this] val foo")).map(_.trim).toList
25+
assert(fooDefs.length == 2)
26+
assert(fooDefs.forall(_.startsWith("@blort private[this] val foo: String =")), fooDefs)
27+
}
28+
}

0 commit comments

Comments
 (0)