@@ -64,9 +64,19 @@ trait TypeAssigner {
64
64
}
65
65
66
66
/** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`.
67
+ * We need to approximate with ranges:
68
+ *
69
+ * term references to symbols in `symsToAvoid`,
70
+ * term references that have a widened type of which some part refers
71
+ * to a symbol in `symsToAvoid`,
72
+ * type references to symbols in `symsToAvoid`,
73
+ * this types of classes in `symsToAvoid`.
74
+ *
75
+ * Type variables that would be interpolated to a type that
76
+ * needs to be widened are replaced by the widened interpolation instance.
67
77
*/
68
78
def avoid (tp : Type , symsToAvoid : => List [Symbol ])(implicit ctx : Context ): Type = {
69
- val wmap = new ApproximatingTypeMap {
79
+ val widenMap = new ApproximatingTypeMap {
70
80
lazy val forbidden = symsToAvoid.toSet
71
81
def toAvoid (sym : Symbol ) = ! sym.isStatic && forbidden.contains(sym)
72
82
def partsToAvoid = new NamedPartsAccumulator (tp => toAvoid(tp.symbol))
@@ -92,23 +102,18 @@ trait TypeAssigner {
92
102
case tp : ThisType if toAvoid(tp.cls) =>
93
103
range(tp.bottomType, apply(classBound(tp.cls.classInfo)))
94
104
case tp : TypeVar if ctx.typerState.constraint.contains(tp) =>
95
- val lo = ctx.typeComparer.instanceType(tp.origin, fromBelow = true )
105
+ val lo = ctx.typeComparer.instanceType(tp.origin, fromBelow = variance >= 0 )
96
106
val lo1 = apply(lo)
97
- // println(i"INST $tp --> $lo --> $lo1")
98
107
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
108
case _ =>
107
109
mapOver(tp)
108
110
}
109
111
110
- /** Needs to handle the case where the prefix type does not have a member
111
- * named `tp.name` anymmore.
112
+ /** Two deviations from standard derivedSelect:
113
+ * 1. The teh approximation result is a singleton references C#x.type, we
114
+ * replace by the widened type, which is usually more natural.
115
+ * 2. We need to handle the case where the prefix type does not have a member
116
+ * named `tp.name` anymmore.
112
117
*/
113
118
override def derivedSelect (tp : NamedType , pre : Type ) =
114
119
if (pre eq tp.prefix) tp
@@ -117,87 +122,8 @@ trait TypeAssigner {
117
122
else if (upper(pre).member(tp.name).exists) super .derivedSelect(tp, pre)
118
123
else range(tp.bottomType, tp.topType)
119
124
}
120
- val widenMap = new TypeMap {
121
- lazy val forbidden = symsToAvoid.toSet
122
- def toAvoid (tp : Type ): Boolean =
123
- // TODO: measure the cost of using `existsPart`, and if necessary replace it
124
- // by a `TypeAccumulator` where we have set `stopAtStatic = true`.
125
- tp existsPart {
126
- case tp : TermRef => forbidden.contains(tp.symbol) || toAvoid(tp.underlying)
127
- case tp : TypeRef => forbidden.contains(tp.symbol)
128
- case tp : ThisType => forbidden.contains(tp.cls)
129
- case _ => false
130
- }
131
- def apply (tp : Type ): Type = tp match {
132
- case tp : TermRef
133
- if toAvoid(tp) && (variance > 0 || tp.info.widenExpr <:< tp) =>
134
- // Can happen if `x: y.type`, then `x.type =:= y.type`, hence we can widen `x.type`
135
- // to y.type in all contexts, not just covariant ones.
136
- apply(tp.info.widenExpr)
137
- case tp : TypeRef if toAvoid(tp) =>
138
- tp.info match {
139
- case TypeAlias (ref) =>
140
- apply(ref)
141
- case info : ClassInfo if variance > 0 =>
142
- if (! (forbidden contains tp.symbol)) {
143
- val prefix = apply(tp.prefix)
144
- val tp1 = tp.derivedSelect(prefix)
145
- if (tp1.typeSymbol.exists)
146
- return tp1
147
- }
148
- val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _))
149
- def addRefinement (parent : Type , decl : Symbol ) = {
150
- val inherited =
151
- parentType.findMember(decl.name, info.cls.thisType, Private )
152
- .suchThat(decl.matches(_))
153
- val inheritedInfo = inherited.info
154
- if (inheritedInfo.exists && decl.info <:< inheritedInfo && ! (inheritedInfo <:< decl.info)) {
155
- val r = RefinedType (parent, decl.name, decl.info)
156
- typr.println(i " add ref $parent $decl --> " + r)
157
- r
158
- }
159
- else
160
- parent
161
- }
162
- val refinableDecls = info.decls.filter(
163
- sym => ! (sym.is(TypeParamAccessor | Private ) || sym.isConstructor))
164
- val fullType = (parentType /: refinableDecls)(addRefinement)
165
- apply(fullType)
166
- case TypeBounds (lo, hi) if variance > 0 =>
167
- apply(hi)
168
- case _ =>
169
- mapOver(tp)
170
- }
171
- case tp @ HKApply (tycon, args) if toAvoid(tycon) =>
172
- apply(tp.superType)
173
- case tp @ AppliedType (tycon, args) if toAvoid(tycon) =>
174
- val base = apply(tycon)
175
- var args = tp.baseArgInfos(base.typeSymbol)
176
- if (base.typeParams.length != args.length)
177
- args = base.typeParams.map(_.paramInfo)
178
- apply(base.appliedTo(args))
179
- case tp @ RefinedType (parent, name, rinfo) if variance > 0 =>
180
- val parent1 = apply(tp.parent)
181
- val refinedInfo1 = apply(rinfo)
182
- if (toAvoid(refinedInfo1)) {
183
- typr.println(s " dropping refinement from $tp" )
184
- if (name.isTypeName) tp.derivedRefinedType(parent1, name, TypeBounds .empty)
185
- else parent1
186
- } else {
187
- tp.derivedRefinedType(parent1, name, refinedInfo1)
188
- }
189
- case tp : TypeVar if ctx.typerState.constraint.contains(tp) =>
190
- val lo = ctx.typerState.constraint.fullLowerBound(tp.origin)
191
- val lo1 = avoid(lo, symsToAvoid)
192
- if (lo1 ne lo) lo1 else tp
193
- case _ =>
194
- mapOver(tp)
195
- }
196
- }
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
125
+
126
+ widenMap(tp)
201
127
}
202
128
203
129
def avoidingType (expr : Tree , bindings : List [Tree ])(implicit ctx : Context ): Type =
0 commit comments