@@ -116,29 +116,43 @@ trait TypeAssigner {
116
116
val lo = ctx.typeComparer.instanceType(tp.origin, fromBelow = variance >= 0 )
117
117
val lo1 = apply(lo)
118
118
if (lo1 ne lo) lo1 else tp
119
+ case tp : LazyRef =>
120
+ mapOver(tp.ref)
119
121
case _ =>
120
122
mapOver(tp)
121
123
}
122
124
125
+ private [this ] var widenings : Set [Type ] = Set ()
126
+
123
127
/** Three deviations from standard derivedSelect:
124
128
* 1. We first try a widening conversion to the type's info with
125
129
* the original prefix. Since the original prefix is known to
126
130
* be a subtype of the returned prefix, this can improve results.
131
+ * However, we never try this more than once for a type in order to
132
+ * avoid looping, see pos/i2941.scala.
127
133
* 2. Then, if the approximation result is a singleton reference C#x.type, we
128
134
* replace by the widened type, which is usually more natural.
129
135
* 3. Finally, we need to handle the case where the prefix type does not have a member
130
136
* named `tp.name` anymmore. In that case, we need to fall back to Bot..Top.
131
137
*/
132
138
override def derivedSelect (tp : NamedType , pre : Type ) =
133
- if (pre eq tp.prefix)
134
- tp
135
- else tryWiden(tp, tp.prefix).orElse {
136
- if (tp.isTerm && variance > 0 && ! pre.isSingleton)
137
- apply(tp.info.widenExpr)
138
- else if (upper(pre).member(tp.name).exists)
139
- super .derivedSelect(tp, pre)
140
- else
141
- range(tp.bottomType, tp.topType)
139
+ if (pre eq tp.prefix) tp
140
+ else {
141
+ def derived =
142
+ if (tp.isTerm && variance > 0 && ! pre.isSingleton)
143
+ apply(tp.info.widenExpr)
144
+ else if (upper(pre).member(tp.name).exists)
145
+ super .derivedSelect(tp, pre)
146
+ else
147
+ range(tp.bottomType, tp.topType)
148
+ if (widenings.contains(tp))
149
+ derived
150
+ else {
151
+ widenings += tp
152
+ val widened = tryWiden(tp, tp.prefix)
153
+ widenings -= tp
154
+ if (widened.exists) widened else derived
155
+ }
142
156
}
143
157
}
144
158
0 commit comments