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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
package dotty.tools.dotc
package transform
import TreeTransforms._
import ast.Trees._
import core._
import Contexts._, Types._, Decorators._, Denotations._, Symbols._, SymDenotations._, Names._
/** Distribute applications into Block and If nodes
*/
class Splitter extends MiniPhaseTransform { thisTransform =>
import ast.tpd._
override def phaseName: String = "splitter"
/** Distribute arguments among splitted branches */
def distribute(tree: GenericApply[Type], rebuild: (Tree, List[Tree]) => Context => Tree)(implicit ctx: Context) = {
def recur(fn: Tree): Tree = fn match {
case Block(stats, expr) => Block(stats, recur(expr))
case If(cond, thenp, elsep) => If(cond, recur(thenp), recur(elsep))
case _ => rebuild(fn, tree.args)(ctx) withPos tree.pos
}
recur(tree.fun)
}
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo) =
distribute(tree, typeApply)
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
distribute(tree, apply)
private val typeApply = (fn: Tree, args: List[Tree]) => (ctx: Context) => TypeApply(fn, args)(ctx)
private val apply = (fn: Tree, args: List[Tree]) => (ctx: Context) => Apply(fn, args)(ctx)
/* The following is no longer necessary, since we select members on the join of an or type:
*
/** If we select a name, make sure the node has a symbol.
* If necessary, split the qualifier with type tests.
* Example: Assume:
*
* class A { def f(x: S): T }
* class B { def f(x: S): T }
* def p(): A | B
*
* Then p().f(a) translates to
*
* val ev$1 = p()
* if (ev$1.isInstanceOf[A]) ev$1.asInstanceOf[A].f(a)
* else ev$1.asInstanceOf[B].f(a)
*/
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = {
val Select(qual, name) = tree
def memberDenot(tp: Type): SingleDenotation = {
val mbr = tp.member(name)
if (!mbr.isOverloaded) mbr.asSingleDenotation
else tree.tpe match {
case tref: TermRefWithSignature => mbr.atSignature(tref.sig).checkUnique
case _ =>
def alts = mbr.alternatives.map(alt => i"$alt: ${alt.info}").mkString(", ")
ctx.error(s"cannot disambiguate overloaded members $alts", tree.pos)
NoDenotation
}
}
def candidates(tp: Type): List[Symbol] = {
val mbr = memberDenot(tp)
if (mbr.symbol.exists) mbr.symbol :: Nil
else tp.widen match {
case tref: TypeRef =>
tref.info match {
case TypeBounds(_, hi) => candidates(hi)
case _ => Nil
}
case OrType(tp1, tp2) =>
candidates(tp1) | candidates(tp2)
case AndType(tp1, tp2) =>
candidates(tp1) & candidates(tp2)
case tpw =>
Nil
}
}
def isStructuralSelect(tp: Type): Boolean = tp.stripTypeVar match {
case tp: RefinedType => tp.refinedName == name || isStructuralSelect(tp.parent)
case tp: TypeProxy => isStructuralSelect(tp.underlying)
case AndType(tp1, tp2) => isStructuralSelect(tp1) || isStructuralSelect(tp2)
case _ => false
}
if (tree.symbol.exists) tree
else {
def choose(qual: Tree, syms: List[Symbol]): Tree = {
def testOrCast(which: Symbol, mbr: Symbol) =
qual.select(which).appliedToType(mbr.owner.typeRef)
def select(sym: Symbol) = {
val qual1 =
if (qual.tpe derivesFrom sym.owner) qual
else testOrCast(defn.Any_asInstanceOf, sym)
qual1.select(sym).withPos(tree.pos)
}
syms match {
case Nil =>
def msg =
if (isStructuralSelect(qual.tpe))
s"cannot access member '$name' from structural type ${qual.tpe.widen.show}; use Dynamic instead"
else
s"no candidate symbols for ${tree.tpe.show} found in ${qual.tpe.show}"
ctx.error(msg, tree.pos)
tree
case sym :: Nil =>
select(sym)
case sym :: syms1 =>
If(testOrCast(defn.Any_isInstanceOf, sym), select(sym), choose(qual, syms1))
}
}
evalOnce(qual)(qual => choose(qual, candidates(qual.tpe)))
}
}
*/
}
|