1+ package dotty .tools
2+ package dotc
3+ package transform
4+
5+ import core ._
6+ import Symbols ._ , Types ._ , Contexts ._ , Decorators ._ , SymDenotations ._ , Flags ._ , Scopes ._
7+ import DenotTransformers ._
8+ import ast .untpd
9+ import collection .{mutable , immutable }
10+ import TypeErasure ._
11+ import ValueClasses .isDerivedValueClass
12+
13+ /** A helper class for generating bridge methods in class `root`. */
14+ class Bridges (root : ClassSymbol )(implicit ctx : Context ) {
15+ import ast .tpd ._
16+
17+ assert(ctx.phase == ctx.erasurePhase.next)
18+ private val preErasureCtx = ctx.withPhase(ctx.erasurePhase)
19+
20+ private class BridgesCursor (implicit ctx : Context ) extends OverridingPairs .Cursor (root) {
21+
22+ /** Only use the superclass of `root` as a parent class. This means
23+ * overriding pairs that have a common implementation in a trait parent
24+ * are also counted. This is necessary because we generate bridge methods
25+ * only in classes, never in traits.
26+ */
27+ override def parents = Array (root.superClass)
28+ override def exclude (sym : Symbol ) = ! sym.is(Method ) || super .exclude(sym)
29+ }
30+
31+ // val site = root.thisType
32+
33+ private var toBeRemoved = immutable.Set [Symbol ]()
34+ private val bridges = mutable.ListBuffer [Tree ]()
35+ private val bridgesScope = newScope
36+ private val bridgeTarget = mutable.HashMap [Symbol , Symbol ]()
37+
38+ /** Add a bridge between `member` and `other`, where `member` overrides `other`
39+ * before erasure, if the following conditions are satisfied.
40+ *
41+ * - `member` and other have different signatures
42+ * - `member` is not inline
43+ * - there is not yet a bridge with the same name and signature in `root`
44+ *
45+ * The bridge has the erased info of `other` and forwards to `member`.
46+ */
47+ private def addBridgeIfNeeded (member : Symbol , other : Symbol ) = {
48+ val otherInfo = erasure(other.info)
49+ def bridgeExists =
50+ bridgesScope.lookupAll(member.name).exists(bridge =>
51+ bridgeTarget(bridge) == member && bridge.info =:= otherInfo)
52+ if (! (member.is(Inline ) || other.info =:= member.info || bridgeExists))
53+ addBridge(member, other)
54+ }
55+
56+ /** Generate bridge between `member` and `other`
57+ */
58+ private def addBridge (member : Symbol , other : Symbol ) = {
59+ val bridgePos = if (member.owner == root && member.pos.exists) member.pos else root.pos
60+ val bridge = other.copy(
61+ owner = root,
62+ flags = (member.flags | Method | Bridge | Artifact ) &~
63+ (Accessor | ParamAccessor | CaseAccessor | Deferred | Lazy | Module ),
64+ coord = bridgePos).enteredAfter(ctx.erasurePhase.asInstanceOf [DenotTransformer ]).asTerm
65+
66+ println(
67+ i """ generating bridge from ${other.showLocated}: ${other.info}
68+ |to ${member.showLocated}: ${member.info} @ ${member.pos}
69+ |bridge: ${bridge.showLocated} with flags: ${bridge.flags}""" )
70+
71+ bridgeTarget(bridge) = member
72+ bridgesScope.enter(bridge)
73+
74+ if (other.owner == root) {
75+ root.delete(other)
76+ toBeRemoved += other
77+ }
78+
79+ bridges +=
80+ DefDef (bridge, This (root).select(member).appliedToArgss(_)).withPos(bridge.pos)
81+ }
82+
83+ /** Add all necessary bridges to template statements `stats`, and remove at the same
84+ * time deferred methods in `stats` that are replaced by a bridge with the same signature.
85+ */
86+ def add (stats : List [untpd.Tree ]): List [untpd.Tree ] =
87+ if (root.is(Trait )) stats
88+ else {
89+ val opc = new BridgesCursor ()(preErasureCtx)
90+ while (opc.hasNext) {
91+ if (! opc.overriding.is(Deferred )) addBridgeIfNeeded(opc.overriding, opc.overridden)
92+ opc.next()
93+ }
94+ if (bridges.isEmpty) stats
95+ else stats.filterNot(stat => toBeRemoved contains stat.symbol) ::: bridges.toList
96+ }
97+ }
0 commit comments