@@ -5,6 +5,7 @@ import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._
5
5
import SymDenotations ._
6
6
import config .Printers ._
7
7
import Decorators ._
8
+ import StdNames ._
8
9
import util .SimpleMap
9
10
10
11
trait TypeOps { this : Context =>
@@ -76,6 +77,37 @@ trait TypeOps { this: Context =>
76
77
def apply (tp : Type ) = simplify(tp, this )
77
78
}
78
79
80
+ /** Approximate union type by intersection of its dominators.
81
+ * See Type#approximateUnion for an explanation.
82
+ */
83
+ def approximateUnion (tp : Type ): Type = {
84
+ /** a faster version of cs1 intersect cs2 */
85
+ def intersect (cs1 : List [ClassSymbol ], cs2 : List [ClassSymbol ]): List [ClassSymbol ] = {
86
+ val cs2AsSet = new util.HashSet [ClassSymbol ](100 )
87
+ cs2.foreach(cs2AsSet.addEntry)
88
+ cs1.filter(cs2AsSet.contains)
89
+ }
90
+ /** The minimal set of classes in `cs` which derive all other classes in `cs` */
91
+ def dominators (cs : List [ClassSymbol ], accu : List [ClassSymbol ]): List [ClassSymbol ] = (cs : @ unchecked) match {
92
+ case c :: rest =>
93
+ val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
94
+ if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
95
+ }
96
+ if (ctx.featureEnabled(defn.LanguageModuleClass , nme.keepUnions)) tp
97
+ else tp match {
98
+ case tp : OrType =>
99
+ val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
100
+ val doms = dominators(commonBaseClasses, Nil )
101
+ doms.map(tp.baseTypeWithArgs).reduceLeft(AndType .apply)
102
+ case tp @ AndType (tp1, tp2) =>
103
+ tp derived_& (approximateUnion(tp1), approximateUnion(tp2))
104
+ case tp : RefinedType =>
105
+ tp.derivedRefinedType(approximateUnion(tp.parent), tp.refinedName, tp.refinedInfo)
106
+ case _ =>
107
+ tp
108
+ }
109
+ }
110
+
79
111
/** A type is volatile if its DNF contains an alternative of the form
80
112
* {P1, ..., Pn}, {N1, ..., Nk}, where the Pi are parent typerefs and the
81
113
* Nj are refinement names, and one the 4 following conditions is met:
@@ -266,6 +298,44 @@ trait TypeOps { this: Context =>
266
298
}
267
299
parentRefs
268
300
}
301
+
302
+ /** Is `feature` enabled in class `owner`?
303
+ * This is the case if one of the following two alternatives holds:
304
+ *
305
+ * 1. The feature is imported by a named import
306
+ *
307
+ * import owner.feature
308
+ *
309
+ * (the feature may be bunched with others, or renamed, but wildcard imports
310
+ * don't count).
311
+ *
312
+ * 2. The feature is enabled by a compiler option
313
+ *
314
+ * - language:<prefix>feature
315
+ *
316
+ * where <prefix> is the full name of the owner followed by a "." minus
317
+ * the prefix "dotty.language.".
318
+ */
319
+ def featureEnabled (owner : ClassSymbol , feature : TermName ): Boolean = {
320
+ def toPrefix (sym : Symbol ): String =
321
+ if (sym eq defn.LanguageModuleClass ) " " else toPrefix(sym.owner) + sym.name + " ."
322
+ def featureName = toPrefix(owner) + feature
323
+ def hasImport (implicit ctx : Context ): Boolean = (
324
+ ctx.importInfo != null
325
+ && ( (ctx.importInfo.site.widen.typeSymbol eq owner)
326
+ && ctx.importInfo.originals.contains(feature)
327
+ ||
328
+ { var c = ctx.outer
329
+ while (c.importInfo eq ctx.importInfo) c = c.outer
330
+ hasImport(c)
331
+ }))
332
+ def hasOption = ctx.base.settings.language.value exists (s => s == featureName || s == " _" )
333
+ hasImport || hasOption
334
+ }
335
+
336
+ /** Is auto-tupling enabled? */
337
+ def canAutoTuple =
338
+ ! featureEnabled(defn.LanguageModuleClass , nme.noAutoTupling)
269
339
}
270
340
271
341
object TypeOps {
0 commit comments