diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 8437db43fb3b..41d5dfc6d282 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -87,6 +87,7 @@ class ScalaSettings extends Settings.SettingGroup { val YdisableFlatCpCaching = BooleanSetting("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.") val YnoImports = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.") + val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.") val YnoGenericSig = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.") val YnoPredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.") val Yskip = PhasesSetting("-Yskip", "Skip") @@ -126,7 +127,7 @@ class ScalaSettings extends Settings.SettingGroup { val YexplainLowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.") val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).") val YshowVarBounds = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds") - val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.") + val YshowNoInline = BooleanSetting("-Yshow-no-inline", "Show inlined code without the 'inlined from' info") /** Linker specific flags */ val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying local optimisations to the .program") withAbbreviation "-optimize" diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 2fda43a675a9..c126146ff20a 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -2,7 +2,7 @@ package dotty.tools package dotc package core -import Types._, Contexts._, Symbols._ +import Types._, Contexts._, Symbols._, Denotations.Denotation, SymDenotations.NoDenotation import Decorators._ import config.Config import config.Printers.{constr, typr} @@ -130,6 +130,11 @@ trait ConstraintHandling { res } + def addMemberBound(param: TypeParamRef, lower: Type, member: Denotation): Denotation = + (member /: member.alternatives.map(_.symbol.owner).distinct) { (mbr, baseCls) => + if (addUpperBound(param, lower.baseType(baseCls))) member else NoDenotation + } + /** Make p2 = p1, transfer all bounds of p2 to p1 * @pre less(p1)(p2) */ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5526e288fada..93e5bd1f76e6 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -591,7 +591,13 @@ object Types { ctx.typerState.constraint.entry(tp) match { case bounds: TypeBounds if bounds ne next => ctx.typerState.ephemeral = true - go(bounds.hi) + val upper = go(bounds.hi) + if (upper.exists) upper + else { + val lower = go(bounds.lo) + if (!lower.exists) upper + else ctx.typeComparer.addMemberBound(tp, bounds.lo, lower) + } case _ => go(next) } @@ -3374,7 +3380,8 @@ object Types { } /** Is the variable already instantiated? */ - def isInstantiated(implicit ctx: Context) = instanceOpt.exists + def isInstantiated(implicit ctx: Context) = + inst.exists || ctx.typerState.instType(this).exists /** Instantiate variable with given type */ def instantiateWith(tp: Type)(implicit ctx: Context): Type = { diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index e3bb7ce3ce2b..093da87ccba6 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -359,7 +359,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SeqLiteral(elems, elemtpt) => "[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]" case tree @ Inlined(call, bindings, body) => - (("/* inlined from " ~ toText(call) ~ "*/ ") provided !homogenizedView) ~ + (("/* inlined from " ~ toText(call) ~ "*/ ") provided !homogenizedView && !ctx.settings.YshowNoInline.value) ~ blockText(bindings :+ body) case tpt: untpd.DerivedTypeTree => "" diff --git a/compiler/src/dotty/tools/dotc/reporting/trace.scala b/compiler/src/dotty/tools/dotc/reporting/trace.scala index d0184c4c9e67..d42008500bbf 100644 --- a/compiler/src/dotty/tools/dotc/reporting/trace.scala +++ b/compiler/src/dotty/tools/dotc/reporting/trace.scala @@ -20,11 +20,18 @@ object trace { else op1 } + @inline + def apply[T](question: => String, printer: Printers.Printer, showOp: Any => String)(op: => T)(implicit ctx: Context): T = { + def op1 = op + if (!Config.tracingEnabled || printer.eq(config.Printers.noPrinter)) op1 + else doTrace[T](question, printer, showOp)(op1) + } + @inline def apply[T](question: => String, printer: Printers.Printer, show: Boolean)(op: => T)(implicit ctx: Context): T = { def op1 = op if (!Config.tracingEnabled || printer.eq(config.Printers.noPrinter)) op1 - else doTrace[T](question, printer, show)(op1) + else doTrace[T](question, printer, if (show) showShowable(_) else alwaysToString)(op1) } @inline @@ -39,16 +46,21 @@ object trace { def apply[T](question: => String)(op: => T)(implicit ctx: Context): T = apply[T](question, Printers.default, false)(op) - private def doTrace[T](question: => String, printer: Printers.Printer = Printers.default, show: Boolean = false) - (op: => T)(implicit ctx: Context): T = { - def resStr(res: Any): String = res match { - case res: printing.Showable if show => res.show - case _ => String.valueOf(res) - } + private def showShowable(x: Any)(implicit ctx: Context) = x match { + case x: printing.Showable => x.show + case _ => String.valueOf(x) + } + + private val alwaysToString = (x: Any) => String.valueOf(x) + + private def doTrace[T](question: => String, + printer: Printers.Printer = Printers.default, + showOp: Any => String = alwaysToString) + (op: => T)(implicit ctx: Context): T = { // Avoid evaluating question multiple time, since each evaluation // may cause some extra logging output. lazy val q: String = question - apply[T](s"==> $q?", (res: Any) => s"<== $q = ${resStr(res)}")(op) + apply[T](s"==> $q?", (res: Any) => s"<== $q = ${showOp(res)}")(op) } def apply[T](leading: => String, trailing: Any => String)(op: => T)(implicit ctx: Context): T = diff --git a/compiler/src/dotty/tools/dotc/util/SimpleMap.scala b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala similarity index 98% rename from compiler/src/dotty/tools/dotc/util/SimpleMap.scala rename to compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala index dbd5b1d1abbb..bdbba5605141 100644 --- a/compiler/src/dotty/tools/dotc/util/SimpleMap.scala +++ b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala @@ -2,6 +2,9 @@ package dotty.tools.dotc.util import collection.mutable.ListBuffer +/** A simple linked map with `eq` as the key comparison, optimized for small maps. + * It has linear complexity for `apply`, `updated`, and `remove`. + */ abstract class SimpleIdentityMap[K <: AnyRef, +V >: Null <: AnyRef] extends (K => V) { def size: Int def apply(k: K): V diff --git a/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala b/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala new file mode 100644 index 000000000000..969d7bdb6f70 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala @@ -0,0 +1,97 @@ +package dotty.tools.dotc.util + +import collection.mutable.ListBuffer + +/** A simple linked set with `eq` as the comparison, optimized for small sets. + * It has linear complexity for `contains`, `+`, and `-`. + */ +abstract class SimpleIdentitySet[+Elem <: AnyRef] { + def size: Int + def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] + def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] + def contains[E >: Elem <: AnyRef](x: E): Boolean + def foreach(f: Elem => Unit): Unit + def toList: List[Elem] = { + val buf = new ListBuffer[Elem] + foreach(buf += _) + buf.toList + } + def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]) = + ((this: SimpleIdentitySet[E]) /: that.toList)(_ + _) + def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]) = + (this /: that.toList)(_ - _) + override def toString = toList.mkString("(", ", ", ")") +} + +object SimpleIdentitySet { + object empty extends SimpleIdentitySet[Nothing] { + def size = 0 + def + [E <: AnyRef](x: E): SimpleIdentitySet[E] = + new Set1[E](x) + def - [E <: AnyRef](x: E): SimpleIdentitySet[Nothing] = + this + def contains[E <: AnyRef](x: E): Boolean = false + def foreach(f: Nothing => Unit): Unit = () + } + + private class Set1[+Elem <: AnyRef](x0: AnyRef) extends SimpleIdentitySet[Elem] { + def size = 1 + def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = + new Set2[E](x0, x) + def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] = + if (x `eq` x0) empty else this + def contains[E >: Elem <: AnyRef](x: E): Boolean = x `eq` x0 + def foreach(f: Elem => Unit): Unit = f(x0.asInstanceOf[Elem]) + } + + private class Set2[+Elem <: AnyRef](x0: AnyRef, x1: AnyRef) extends SimpleIdentitySet[Elem] { + def size = 2 + def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = { + val xs = new Array[AnyRef](3) + xs(0) = x0 + xs(1) = x1 + xs(2) = x + new SetN[E](xs) + } + def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] = + if (x `eq` x0) new Set1(x1) + else if (x `eq` x1) new Set1(x0) + else this + def contains[E >: Elem <: AnyRef](x: E): Boolean = (x `eq` x0) || (x `eq` x1) + def foreach(f: Elem => Unit): Unit = { f(x0.asInstanceOf[Elem]); f(x1.asInstanceOf[Elem]) } + } + + private class SetN[+Elem <: AnyRef](xs: Array[AnyRef]) extends SimpleIdentitySet[Elem] { + def size = xs.length + def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = { + val xs1 = new Array[AnyRef](size + 1) + Array.copy(xs, 0, xs1, 0, size) + xs1(size) = x + new SetN[E](xs1) + } + def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] = { + var i = 0 + while (i < size && (xs(i) `ne` x)) i += 1 + if (i == size) this + else if (size == 3) + if (i == 0) new Set2(xs(1), xs(2)) + else if (i == 1) new Set2(xs(0), xs(2)) + else new Set2(xs(0), xs(1)) + else { + val xs1 = new Array[AnyRef](size - 1) + Array.copy(xs, 0, xs1, 0, i) + Array.copy(xs, i + 1, xs1, i, size - (i + 1)) + new SetN(xs1) + } + } + def contains[E >: Elem <: AnyRef](x: E): Boolean = { + var i = 0 + while (i < size && (xs(i) `ne` x)) i += 1 + i < size + } + def foreach(f: Elem => Unit): Unit = { + var i = 0 + while (i < size) { f(xs(i).asInstanceOf[Elem]); i += 1 } + } + } +} \ No newline at end of file