aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/Compiler.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala21
-rw-r--r--compiler/src/dotty/tools/dotc/core/Periods.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeApplications.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala28
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeOps.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java1
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/transform/MoveStatics.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala40
-rw-r--r--compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala24
14 files changed, 109 insertions, 55 deletions
diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala
index f413fc902..efde897cd 100644
--- a/compiler/src/dotty/tools/dotc/Compiler.scala
+++ b/compiler/src/dotty/tools/dotc/Compiler.scala
@@ -92,12 +92,12 @@ class Compiler {
new ElimStaticThis, // Replace `this` references to static objects by global identifiers
new Flatten, // Lift all inner classes to package scope
new RestoreScopes), // Repair scopes rendered invalid by moving definitions in prior phases of the group
- List(new ExpandPrivate, // Widen private definitions accessed from nested classes
+ List(new MoveStatics, // Move static methods to companion classes
+ new ExpandPrivate, // Widen private definitions accessed from nested classes
new SelectStatic, // get rid of selects that would be compiled into GetStatic
new CollectEntryPoints, // Find classes with main methods
new CollectSuperCalls, // Find classes that are called with super
new DropInlined, // Drop Inlined nodes, since backend has no use for them
- new MoveStatics, // Move static methods to companion classes
new LabelDefs), // Converts calls to labels to jumps
List(new GenBCode) // Generate JVM bytecode
)
diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
index 40e2b083b..318295751 100644
--- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -64,6 +64,7 @@ class ScalaSettings extends Settings.SettingGroup {
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync")
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
+ val debugAlias = BooleanSetting("-Ydebug-alias", "Never follow alias when printing types")
val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names")
val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions")
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 2a1f4ee6e..a12936c58 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -35,15 +35,6 @@ trait ConstraintHandling {
/** If the constraint is frozen we cannot add new bounds to the constraint. */
protected var frozenConstraint = false
- protected var alwaysFluid = false
-
- /** Perform `op` in a mode where all attempts to set `frozen` to true are ignored */
- def fluidly[T](op: => T): T = {
- val saved = alwaysFluid
- alwaysFluid = true
- try op finally alwaysFluid = saved
- }
-
/** If set, align arguments `S1`, `S2`when taking the glb
* `T1 { X = S1 } & T2 { X = S2 }` of a constraint upper bound for some type parameter.
* Aligning means computing `S1 =:= S2` which may change the current constraint.
@@ -156,16 +147,24 @@ trait ConstraintHandling {
up.forall(addOneBound(_, lo, isUpper = false))
}
+
+ protected def isSubType(tp1: Type, tp2: Type, whenFrozen: Boolean): Boolean = {
+ if (whenFrozen)
+ isSubTypeWhenFrozen(tp1, tp2)
+ else
+ isSubType(tp1, tp2)
+ }
+
final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
- frozenConstraint = !alwaysFluid
+ frozenConstraint = true
try isSubType(tp1, tp2)
finally frozenConstraint = saved
}
final def isSameTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
- frozenConstraint = !alwaysFluid
+ frozenConstraint = true
try isSameType(tp1, tp2)
finally frozenConstraint = saved
}
diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala
index 29d9d208f..892a1f59a 100644
--- a/compiler/src/dotty/tools/dotc/core/Periods.scala
+++ b/compiler/src/dotty/tools/dotc/core/Periods.scala
@@ -46,9 +46,9 @@ object Periods {
* It is coded as follows:
*
* sign, always 0 1 bit
- * runid 19 bits
- * last phase id: 6 bits
- * #phases before last: 6 bits
+ * runid 17 bits
+ * last phase id: 7 bits
+ * #phases before last: 7 bits
*
* // Dmitry: sign == 0 isn't actually always true, in some cases phaseId == -1 is used for shifts, that easily creates code < 0
*/
@@ -108,6 +108,7 @@ object Periods {
else
Nowhere
+ /** The smallest period containing two periods */
def | (that: Period): Period =
Period(this.runId,
this.firstPhaseId min that.firstPhaseId,
diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
index c713cd542..ba3e6a461 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -1,4 +1,5 @@
-package dotty.tools.dotc
+package dotty.tools
+package dotc
package core
import Types._
@@ -412,8 +413,8 @@ class TypeApplications(val self: Type) extends AnyVal {
val followAlias = Config.simplifyApplications && {
dealiased.resType match {
case AppliedType(tyconBody, _) =>
- variancesConform(typParams, tyconBody.typeParams)
- // Reducing is safe for type inference, as kind of type constructor does not change
+ sameLength(dealiased.typeParams, tyconBody.typeParams)
+ // Reducing is safe for type inference, as kind arity of type constructor does not change
case _ => false
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index 21a12dbb7..57dde3288 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -384,7 +384,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
// So if the constraint is not yet frozen, we do the same comparison again
// with a frozen constraint, which means that we get a chance to do the
// widening in `fourthTry` before adding to the constraint.
- if (frozenConstraint || alwaysFluid) isSubType(tp1, bounds(tp2).lo)
+ if (frozenConstraint) isSubType(tp1, bounds(tp2).lo)
else isSubTypeWhenFrozen(tp1, tp2)
alwaysTrue || {
if (canConstrain(tp2)) addConstraint(tp2, tp1.widenExpr, fromBelow = true)
@@ -1143,19 +1143,20 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
((defn.AnyType: Type) /: tps)(glb)
/** The least upper bound of two types
+ * @param canConstrain If true, new constraints might be added to simplify the lub.
* @note We do not admit singleton types in or-types as lubs.
*/
- def lub(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"lub(${tp1.show}, ${tp2.show})", subtyping, show = true) /*<|<*/ {
+ def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type = /*>|>*/ ctx.traceIndented(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain)", subtyping, show = true) /*<|<*/ {
if (tp1 eq tp2) tp1
else if (!tp1.exists) tp1
else if (!tp2.exists) tp2
else if ((tp1 isRef AnyClass) || (tp2 isRef NothingClass)) tp1
else if ((tp2 isRef AnyClass) || (tp1 isRef NothingClass)) tp2
else {
- val t1 = mergeIfSuper(tp1, tp2)
+ val t1 = mergeIfSuper(tp1, tp2, canConstrain)
if (t1.exists) t1
else {
- val t2 = mergeIfSuper(tp2, tp1)
+ val t2 = mergeIfSuper(tp2, tp1, canConstrain)
if (t2.exists) t2
else {
val tp1w = tp1.widen
@@ -1169,7 +1170,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** The least upper bound of a list of types */
final def lub(tps: List[Type]): Type =
- ((defn.NothingType: Type) /: tps)(lub)
+ ((defn.NothingType: Type) /: tps)(lub(_,_, canConstrain = false))
/** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
*/
@@ -1192,17 +1193,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
/** Merge `tp1` into `tp2` if tp1 is a supertype of some |-summand of tp2.
+ * @param canConstrain If true, new constraints might be added to make the merge possible.
*/
- private def mergeIfSuper(tp1: Type, tp2: Type): Type =
- if (isSubTypeWhenFrozen(tp2, tp1))
- if (isSubTypeWhenFrozen(tp1, tp2)) tp2 else tp1 // keep existing type if possible
+ private def mergeIfSuper(tp1: Type, tp2: Type, canConstrain: Boolean): Type =
+ if (isSubType(tp2, tp1, whenFrozen = !canConstrain))
+ if (isSubType(tp1, tp2, whenFrozen = !canConstrain)) tp2 else tp1 // keep existing type if possible
else tp2 match {
case tp2 @ OrType(tp21, tp22) =>
- val higher1 = mergeIfSuper(tp1, tp21)
+ val higher1 = mergeIfSuper(tp1, tp21, canConstrain)
if (higher1 eq tp21) tp2
else if (higher1.exists) higher1 | tp22
else {
- val higher2 = mergeIfSuper(tp1, tp22)
+ val higher2 = mergeIfSuper(tp1, tp22, canConstrain)
if (higher2 eq tp22) tp2
else if (higher2.exists) tp21 | higher2
else NoType
@@ -1491,9 +1493,9 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
super.hasMatchingMember(name, tp1, tp2)
}
- override def lub(tp1: Type, tp2: Type) =
- traceIndented(s"lub(${show(tp1)}, ${show(tp2)})") {
- super.lub(tp1, tp2)
+ override def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false) =
+ traceIndented(s"lub(${show(tp1)}, ${show(tp2)}, canConstrain=$canConstrain)") {
+ super.lub(tp1, tp2, canConstrain)
}
override def glb(tp1: Type, tp2: Type) =
diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
index 6c40794e3..3d2906320 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
@@ -282,7 +282,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
*/
def harmonizeUnion(tp: Type): Type = tp match {
case tp: OrType =>
- joinIfScala2(typeComparer.fluidly(tp.tp1 | tp.tp2))
+ joinIfScala2(ctx.typeComparer.lub(harmonizeUnion(tp.tp1), harmonizeUnion(tp.tp2), canConstrain = true))
case tp @ AndType(tp1, tp2) =>
tp derived_& (harmonizeUnion(tp1), harmonizeUnion(tp2))
case tp: RefinedType =>
diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 3d952f425..8a33472b8 100644
--- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -130,7 +130,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (defn.isTupleClass(cls)) return toTextTuple(args)
return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close
case tp: TypeRef =>
- val hideType = tp.symbol is AliasPreferred
+ val hideType = !ctx.settings.debugAlias.value && (tp.symbol is AliasPreferred)
if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) {
tp.info match {
case TypeAlias(alias) => return toText(alias)
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
index 7b56c8ed4..6ea168b99 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
@@ -55,6 +55,7 @@ public enum ErrorMessageID {
RecursiveValueNeedsResultTypeID,
CyclicReferenceInvolvingID,
CyclicReferenceInvolvingImplicitID,
+ SuperQualMustBeParentID,
;
public int errorNumber() {
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 4c53fa496..6fa056646 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -1192,4 +1192,21 @@ object messages {
|""".stripMargin
}
+ case class SuperQualMustBeParent(qual: untpd.Ident, cls: Symbols.ClassSymbol)(implicit ctx: Context)
+ extends Message(SuperQualMustBeParentID) {
+
+ val msg = hl"""|$qual does not name a parent of $cls"""
+
+ val kind = "Reference"
+
+ private val parents: Seq[String] = (cls.info.parents map (_.name.show)).sorted
+
+ val explanation =
+ hl"""|When a qualifier ${"T"} is used in a ${"super"} prefix of the form ${"C.super[T]"},
+ |${"T"} must be a parent type of ${"C"}.
+ |
+ |In this case, the parents of $cls are:
+ |${parents.mkString(" - ", "\n - ", "")}
+ |""".stripMargin
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala
index 83cd395ff..8f99ef1d0 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala
@@ -3,7 +3,7 @@ package transform
import core._
import dotty.tools.dotc.ast.tpd
-import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer}
+import dotty.tools.dotc.core.DenotTransformers.{IdentityDenotTransformer, SymTransformer}
import Contexts.Context
import Symbols._
import Scopes._
@@ -11,13 +11,16 @@ import Flags._
import StdNames._
import SymDenotations._
import Types._
+
import collection.mutable
import TreeTransforms._
import Decorators._
import ast.Trees._
import TreeTransforms._
import java.io.File.separatorChar
+
import ValueClasses._
+import dotty.tools.dotc.core.Phases.Phase
/** Make private term members that are accessed from another class
* non-private by resetting the Private flag and expanding their name.
@@ -38,6 +41,9 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
override def phaseName: String = "expandPrivate"
+ // This phase moves methods around (in infotransform) so it may need to make other methods public
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[MoveStatics])
+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
tree match {
case t: DefDef =>
diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala
index 5c2cd3145..b0ee0930d 100644
--- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala
+++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala
@@ -9,6 +9,7 @@ import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.NameOps._
import dotty.tools.dotc.core.{Flags, Names}
import dotty.tools.dotc.core.Names.Name
+import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Types.MethodType
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
@@ -19,7 +20,6 @@ class MoveStatics extends MiniPhaseTransform with SymTransformer { thisTransform
import tpd._
override def phaseName = "moveStatic"
-
def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = {
if (sym.hasAnnotation(defn.ScalaStaticAnnot) && sym.owner.is(Flags.Module) && sym.owner.companionClass.exists) {
sym.owner.asClass.delete(sym.symbol)
diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 6e774e38e..6d0fc08f9 100644
--- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -291,26 +291,28 @@ trait TypeAssigner {
def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context) = {
val mix = tree.mix
- val qtype @ ThisType(_) = qual.tpe
- val cls = qtype.cls
-
- def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix.name) match {
- case p :: Nil =>
- p
- case Nil =>
- errorType(em"$mix does not name a parent class of $cls", tree.pos)
- case p :: q :: _ =>
- errorType("ambiguous parent class qualifier", tree.pos)
+ qual.tpe match {
+ case err: ErrorType => untpd.cpy.Super(tree)(qual, mix).withType(err)
+ case qtype @ ThisType(_) =>
+ val cls = qtype.cls
+ def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix.name) match {
+ case p :: Nil =>
+ p
+ case Nil =>
+ errorType(SuperQualMustBeParent(mix, cls), tree.pos)
+ case p :: q :: _ =>
+ errorType("ambiguous parent class qualifier", tree.pos)
+ }
+ val owntype =
+ if (mixinClass.exists) mixinClass.typeRef
+ else if (!mix.isEmpty) findMixinSuper(cls.info)
+ else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent
+ else {
+ val ps = cls.classInfo.parentsWithArgs
+ if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
+ }
+ tree.withType(SuperType(cls.thisType, owntype))
}
- val owntype =
- if (mixinClass.exists) mixinClass.typeRef
- else if (!mix.isEmpty) findMixinSuper(cls.info)
- else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent
- else {
- val ps = cls.classInfo.parentsWithArgs
- if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
- }
- tree.withType(SuperType(cls.thisType, owntype))
}
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
index f11c6dd96..be160ac7f 100644
--- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
+++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
@@ -304,5 +304,29 @@ class ErrorMessagesTests extends ErrorMessagesTest {
assertEquals("x", tree.name.show)
}
+ @Test def superQualMustBeParent =
+ checkMessagesAfter("frontend") {
+ """
+ |class A {
+ | def foo(): Unit = ()
+ |}
+ |
+ |class B {
+ |}
+ |
+ |class C extends A {
+ | super[B].foo
+ |}
+ """.stripMargin
+ }
+ .expect { (ictx, messages) =>
+ implicit val ctx: Context = ictx
+ val defn = ictx.definitions
+ assertMessageCount(1, messages)
+ val SuperQualMustBeParent(qual, cls) :: Nil = messages
+
+ assertEquals("B", qual.show)
+ assertEquals("class C", cls.show)
+ }
}