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