aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala
blob: ca06938dc53aabf072665e178c7d0f352c2c8374 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package dotty.tools.dotc
package transform

import core._
import TreeTransforms._
import Contexts.Context
import Flags._
import SymUtils._
import Symbols._
import SymDenotations._
import Types._
import Decorators._
import DenotTransformers._
import StdNames._
import NameOps._
import Phases._
import ast.untpd
import ast.Trees._
import collection.mutable

/** Rewrite calls
 *
 *    super[M].f(args)
 *
 *  where M is a Scala2 trait implemented by the current class to
 *
 *    M$class.f(this, args)
 *
 *  provided the implementation class M$class defines a corresponding function `f`.
 */
class LinkScala2ImplClasses extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
  import ast.tpd._

  override def phaseName: String = "linkScala2ImplClasses"

  override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])

  override def transformApply(app: Apply)(implicit ctx: Context, info: TransformerInfo) = {
    def currentClass = ctx.owner.enclosingClass.asClass
    app match {
      case Apply(sel @ Select(Super(_, _), _), args)
      if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) =>
        val impl = implMethod(sel.symbol)
        if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos)
        else app // could have been an abstract method in a trait linked to from a super constructor
      case _ =>
        app
    }
  }

  private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
    val implInfo = meth.owner.implClass.info
    if (meth.isConstructor)
      implInfo.decl(nme.TRAIT_CONSTRUCTOR).symbol
    else
      implInfo.decl(meth.name)
      .suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
      .symbol
  }

  private val Scala2xTrait = allOf(Scala2x, Trait)
}