@@ -39,18 +39,84 @@ trait TypeAssigner {
3939 }
4040 }
4141
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+
4266 /** 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.
5267 */
5368 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+ }
54120 val widenMap = new TypeMap {
55121 lazy val forbidden = symsToAvoid.toSet
56122 def toAvoid (tp : Type ): Boolean =
@@ -128,7 +194,10 @@ trait TypeAssigner {
128194 mapOver(tp)
129195 }
130196 }
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
132201 }
133202
134203 def avoidingType (expr : Tree , bindings : List [Tree ])(implicit ctx : Context ): Type =
0 commit comments