@@ -39,18 +39,84 @@ trait TypeAssigner {
39
39
}
40
40
}
41
41
42
+ /** Given a class info, the intersection of its parents, refined by all
43
+ * non-private fields, methods, and type members.
44
+ */
45
+ def classBound (info : ClassInfo )(implicit ctx : Context ): Type = {
46
+ val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _))
47
+ def addRefinement (parent : Type , decl : Symbol ) = {
48
+ val inherited =
49
+ parentType.findMember(decl.name, info.cls.thisType, Private )
50
+ .suchThat(decl.matches(_))
51
+ val inheritedInfo = inherited.info
52
+ if (inheritedInfo.exists && decl.info <:< inheritedInfo && ! (inheritedInfo <:< decl.info)) {
53
+ val r = RefinedType (parent, decl.name, decl.info)
54
+ typr.println(i " add ref $parent $decl --> " + r)
55
+ r
56
+ }
57
+ else
58
+ parent
59
+ }
60
+ val refinableDecls = info.decls.filter(
61
+ sym => ! (sym.is(TypeParamAccessor | Private ) || sym.isConstructor))
62
+ val raw = (parentType /: refinableDecls)(addRefinement)
63
+ RecType .closeOver(rt => raw.substThis(info.cls, RecThis (rt)))
64
+ }
65
+
42
66
/** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`.
43
- * Approximation steps are:
44
- *
45
- * - follow aliases and upper bounds if the original refers to a forbidden symbol
46
- * - widen termrefs that refer to a forbidden symbol
47
- * - replace ClassInfos of forbidden classes by the intersection of their parents, refined by all
48
- * non-private fields, methods, and type members.
49
- * - if the prefix of a class refers to a forbidden symbol, first try to replace the prefix,
50
- * if this is not possible, replace the ClassInfo as above.
51
- * - drop refinements referring to a forbidden symbol.
52
67
*/
53
68
def avoid (tp : Type , symsToAvoid : => List [Symbol ])(implicit ctx : Context ): Type = {
69
+ val wmap = new ApproximatingTypeMap {
70
+ lazy val forbidden = symsToAvoid.toSet
71
+ def toAvoid (sym : Symbol ) = ! sym.isStatic && forbidden.contains(sym)
72
+ def partsToAvoid = new NamedPartsAccumulator (tp => toAvoid(tp.symbol))
73
+ def apply (tp : Type ): Type = tp match {
74
+ case tp : TermRef
75
+ if toAvoid(tp.symbol) || partsToAvoid(mutable.Set .empty, tp.info).nonEmpty =>
76
+ tp.info.widenExpr match {
77
+ case info : SingletonType => apply(info)
78
+ case info => range(tp.info.bottomType, apply(info))
79
+ }
80
+ case tp : TypeRef if toAvoid(tp.symbol) =>
81
+ val avoided = tp.info match {
82
+ case TypeAlias (alias) =>
83
+ apply(alias)
84
+ case TypeBounds (lo, hi) =>
85
+ range(atVariance(- variance)(apply(lo)), apply(hi))
86
+ case info : ClassInfo =>
87
+ range(tp.bottomType, apply(classBound(info)))
88
+ case _ =>
89
+ range(tp.bottomType, tp.topType) // should happen only in error cases
90
+ }
91
+ avoided
92
+ case tp : ThisType if toAvoid(tp.cls) =>
93
+ range(tp.bottomType, apply(classBound(tp.cls.classInfo)))
94
+ case tp : TypeVar if ctx.typerState.constraint.contains(tp) =>
95
+ val lo = ctx.typeComparer.instanceType(tp.origin, fromBelow = true )
96
+ val lo1 = apply(lo)
97
+ // println(i"INST $tp --> $lo --> $lo1")
98
+ if (lo1 ne lo) lo1 else tp
99
+ case tp : TermRef if false =>
100
+ val saved = variance
101
+ variance = 0
102
+ val prefix1 = this (tp.prefix)
103
+ variance = saved
104
+ if (isRange(prefix1)) range(tp.bottomType, apply(tp.info.widenExpr))
105
+ else derivedSelect(tp, prefix1)
106
+ case _ =>
107
+ mapOver(tp)
108
+ }
109
+
110
+ /** Needs to handle the case where the prefix type does not have a member
111
+ * named `tp.name` anymmore.
112
+ */
113
+ override def derivedSelect (tp : NamedType , pre : Type ) =
114
+ if (pre eq tp.prefix) tp
115
+ else if (tp.isTerm && variance > 0 && ! pre.isInstanceOf [SingletonType ])
116
+ apply(tp.info.widenExpr)
117
+ else if (upper(pre).member(tp.name).exists) super .derivedSelect(tp, pre)
118
+ else range(tp.bottomType, tp.topType)
119
+ }
54
120
val widenMap = new TypeMap {
55
121
lazy val forbidden = symsToAvoid.toSet
56
122
def toAvoid (tp : Type ): Boolean =
@@ -128,7 +194,10 @@ trait TypeAssigner {
128
194
mapOver(tp)
129
195
}
130
196
}
131
- widenMap(tp)
197
+ // val was = widenMap(tp)
198
+ val now = wmap(tp)
199
+ // if (was.show != now.show) println(i"difference for avoid $tp, ${tp.toString}, forbidden = $symsToAvoid%, %, was: $was, now: $now")
200
+ now
132
201
}
133
202
134
203
def avoidingType (expr : Tree , bindings : List [Tree ])(implicit ctx : Context ): Type =
0 commit comments