aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/config/CompilerCommand.scala10
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala15
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala19
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala5
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala25
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala22
-rw-r--r--src/dotty/tools/dotc/core/Types.scala5
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala39
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala12
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala30
-rw-r--r--test/test/DottyTest.scala5
-rw-r--r--tests/pending/pos/annot.scala5
-rw-r--r--tests/pos/annot.scala6
-rw-r--r--tests/pos/i0268.scala15
14 files changed, 124 insertions, 89 deletions
diff --git a/src/dotty/tools/dotc/config/CompilerCommand.scala b/src/dotty/tools/dotc/config/CompilerCommand.scala
index ec8b17b0d..aa8e7abbf 100644
--- a/src/dotty/tools/dotc/config/CompilerCommand.scala
+++ b/src/dotty/tools/dotc/config/CompilerCommand.scala
@@ -19,11 +19,13 @@ object CompilerCommand extends DotClass {
|Where multiple values are accepted, they should be comma-separated.
| example: -Xplugin:plugin1,plugin2
|<phases> means one or a comma-separated list of:
- | (partial) phase names, phase ids, phase id ranges, or the string "all".
+ | - (partial) phase names with an optional "+" suffix to include the next phase
+ | - the string "all"
| example: -Xprint:all prints all phases.
- | example: -Xprint:expl,24-26 prints phases explicitouter, closelim, dce, jvm.
- | example: -Xprint:-4 prints only the phases up to typer.
- |
+ | example: -Xprint:front,mixin prints the frontend and mixin phases.
+ | example: -Ylog:erasure+ logs the erasure phase and the phase after the erasure phase.
+ | This is useful because during the tree transform of phase X, we often
+ | already are in phase X+1.
""".stripMargin.trim + "\n"
def shortUsage = s"Usage: $cmdName <options> <source files>"
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 98a71dd98..635390ef5 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -146,6 +146,11 @@ object Contexts {
protected def diagnostics_=(diagnostics: Option[StringBuilder]) = _diagnostics = diagnostics
def diagnostics: Option[StringBuilder] = _diagnostics
+ /** The current bounds in force for type parameters appearing in a GADT */
+ private var _gadt: GADTMap = _
+ protected def gadt_=(gadt: GADTMap) = _gadt = gadt
+ def gadt: GADTMap = _gadt
+
/** A map in which more contextual properties can be stored */
private var _moreProperties: Map[String, Any] = _
protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties
@@ -418,6 +423,8 @@ object Contexts {
def setSetting[T](setting: Setting[T], value: T): this.type =
setSettings(setting.updateIn(sstate, value))
+ def setFreshGADTBounds: this.type = { this.gadt = new GADTMap(gadt.bounds); this }
+
def setDebug = setSetting(base.settings.debug, true)
}
@@ -439,6 +446,7 @@ object Contexts {
moreProperties = Map.empty
typeComparer = new TypeComparer(this)
searchHistory = new SearchHistory(0, Map())
+ gadt = new GADTMap(SimpleMap.Empty)
}
object NoContext extends Context {
@@ -593,6 +601,13 @@ object Contexts {
implicit val ctx: Context = initctx
}
+ class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) {
+ private var myBounds = initBounds
+ def setBounds(sym: Symbol, b: TypeBounds): Unit =
+ myBounds = myBounds.updated(sym, b)
+ def bounds = myBounds
+ }
+
/** Initial size of superId table */
private final val InitialSuperIdsSize = 4096
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index e0d7fae33..882729063 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -128,15 +128,22 @@ object Decorators {
def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value)
}
- /** Implements a test whether a list of strings representing phases contains
- * a given phase. The test returns true if the given phase starts with
- * one of the names in the list of strings, or if the list of strings
- * contains "all".
+ /** Test whether a list of strings representing phases contains
+ * a given phase. See [[config.CompilerCommand#explainAdvanced]] for the
+ * exact meaning of "contains" here.
*/
implicit class PhaseListDecorator(val names: List[String]) extends AnyVal {
- def containsPhase(phase: Phase): Boolean = phase match {
+ def containsPhase(phase: Phase): Boolean = phase match {
case phase: TreeTransformer => phase.transformations.exists(trans => containsPhase(trans.phase))
- case _ => names exists (n => n == "all" || phase.phaseName.startsWith(n))
+ case _ =>
+ names exists { name =>
+ name == "all" || {
+ val strippedName = name.stripSuffix("+")
+ val logNextPhase = name ne strippedName
+ phase.phaseName.startsWith(strippedName) ||
+ (logNextPhase && phase.prev.phaseName.startsWith(strippedName))
+ }
+ }
}
}
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 0e86a2936..53beae838 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -301,9 +301,6 @@ object Flags {
/** Method is assumed to be stable */
final val Stable = termFlag(24, "<stable>")
- /** Info can be refined during GADT pattern match */
- final val GADTFlexType = typeFlag(24, "<gadt-flex-type>")
-
/** A case parameter accessor */
final val CaseAccessor = termFlag(25, "<caseaccessor>")
@@ -553,7 +550,7 @@ object Flags {
/** A Java interface, potentially with default methods */
final val JavaTrait = allOf(JavaDefined, Trait, NoInits)
-
+
/** A Java interface */
final val JavaInterface = allOf(JavaDefined, Trait)
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 9817c12ee..13b61c0fd 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -450,31 +450,6 @@ object Symbols {
*/
def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition
-// -------- GADT handling -----------------------------------------------
-
- /** Perform given operation `op` where this symbol allows tightening of
- * its type bounds.
- */
- private[dotc] def withGADTFlexType[T](op: () => T)(implicit ctx: Context): () => T = { () =>
- assert((denot is TypeParam) && denot.owner.isTerm)
- val saved = denot
- denot = denot.copySymDenotation(initFlags = denot.flags | GADTFlexType)
- try op()
- finally denot = saved
- }
-
- /** Disallow tightening of type bounds for this symbol from now on */
- private[dotc] def resetGADTFlexType()(implicit ctx: Context): Unit = {
- assert(denot is GADTFlexType)
- denot = denot.copySymDenotation(initFlags = denot.flags &~ GADTFlexType)
- }
-
- /** Change info of this symbol to new, tightened type bounds */
- private[core] def changeGADTInfo(bounds: TypeBounds)(implicit ctx: Context): Unit = {
- assert(denot is GADTFlexType)
- denot = denot.copySymDenotation(info = bounds)
- }
-
// -------- Printing --------------------------------------------------------
/** The prefix string to be used when displaying this symbol without denotation */
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 34f9bfbb9..cae4500e4 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -618,9 +618,12 @@ class TypeComparer(initctx: Context) extends DotClass {
secondTry(OrType.make(derivedRef(tp11), derivedRef(tp12)), tp2)
*/
case TypeBounds(lo1, hi1) =>
- if ((ctx.mode is Mode.GADTflexible) && (tp1.symbol is GADTFlexType) &&
- !isSubTypeWhenFrozen(hi1, tp2))
- trySetType(tp1, TypeBounds(lo1, hi1 & tp2))
+ val gbounds1 = ctx.gadt.bounds(tp1.symbol)
+ if (gbounds1 != null)
+ isSubTypeWhenFrozen(gbounds1.hi, tp2) ||
+ (ctx.mode is Mode.GADTflexible) &&
+ narrowGADTBounds(tp1, TypeBounds(gbounds1.lo, gbounds1.hi & tp2)) ||
+ tryRebase2nd
else if (lo1 eq hi1) isSubType(hi1, tp2)
else tryRebase2nd
case _ =>
@@ -637,9 +640,12 @@ class TypeComparer(initctx: Context) extends DotClass {
}
def compareNamed: Boolean = tp2.info match {
case TypeBounds(lo2, hi2) =>
- if ((ctx.mode is Mode.GADTflexible) && (tp2.symbol is GADTFlexType) &&
- !isSubTypeWhenFrozen(tp1, lo2))
- trySetType(tp2, TypeBounds(lo2 | tp1, hi2))
+ val gbounds2 = ctx.gadt.bounds(tp2.symbol)
+ if (gbounds2 != null)
+ isSubTypeWhenFrozen(tp1, gbounds2.lo) ||
+ (ctx.mode is Mode.GADTflexible) &&
+ narrowGADTBounds(tp2, TypeBounds(gbounds2.lo | tp1, gbounds2.hi)) ||
+ tryRebase3rd
else
((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2)
|| tryRebase3rd)
@@ -912,9 +918,9 @@ class TypeComparer(initctx: Context) extends DotClass {
tp.exists && !tp.isLambda
}
- def trySetType(tr: NamedType, bounds: TypeBounds): Boolean =
+ def narrowGADTBounds(tr: NamedType, bounds: TypeBounds): Boolean =
isSubType(bounds.lo, bounds.hi) &&
- { tr.symbol.changeGADTInfo(bounds); true }
+ { ctx.gadt.setBounds(tr.symbol, bounds); true }
// Tests around `matches`
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 5862a934a..e520ea172 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2515,10 +2515,7 @@ object Types {
object TypeAlias {
def apply(alias: Type, variance: Int = 0)(implicit ctx: Context) =
ctx.uniqueTypeAliases.enterIfNew(alias, variance)
- def unapply(tp: TypeAlias): Option[Type] = tp match {
- case tp: TypeAlias => Some(tp.alias)
- case _ => None
- }
+ def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias)
}
// ----- Annotated and Import types -----------------------------------------------
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index ef5f48047..a8be0bb94 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -553,12 +553,15 @@ class ClassfileParser(
newType
}
- /** Add a synthetic constructor and potentially also default getters which
+ /** Add synthetic constructor(s) and potentially also default getters which
* reflects the fields of the annotation with given `classInfo`.
* Annotations in Scala are assumed to get all their arguments as constructor
* parameters. For Java annotations we need to fake it by making up the constructor.
* Note that default getters have type Nothing. That's OK because we need
* them only to signal that the corresponding parameter is optional.
+ * If the constructor takes as last parameter an array, it can also accept
+ * a vararg argument. We solve this by creating two constructors, one with
+ * an array, the other with a repeated parameter.
*/
def addAnnotationConstructor(classInfo: Type, tparams: List[Symbol] = Nil)(implicit ctx: Context): Unit = {
def addDefaultGetter(attr: Symbol, n: Int) =
@@ -574,21 +577,33 @@ class ClassfileParser(
case classInfo: TempClassInfoType =>
val attrs = classInfo.decls.toList.filter(_.isTerm)
val targs = tparams.map(_.typeRef)
- val methType = MethodType(
- attrs.map(_.name.asTermName),
- attrs.map(_.info.resultType),
- classRoot.typeRef.appliedTo(targs))
- val constr = ctx.newSymbol(
+ val paramNames = attrs.map(_.name.asTermName)
+ val paramTypes = attrs.map(_.info.resultType)
+
+ def addConstr(ptypes: List[Type]) = {
+ val mtype = MethodType(paramNames, ptypes, classRoot.typeRef.appliedTo(targs))
+ val constrType = if (tparams.isEmpty) mtype else TempPolyType(tparams, mtype)
+ val constr = ctx.newSymbol(
owner = classRoot.symbol,
name = nme.CONSTRUCTOR,
flags = Flags.Synthetic,
- info = if (tparams.isEmpty) methType else TempPolyType(tparams, methType)
+ info = constrType
).entered
- for ((attr, i) <- attrs.zipWithIndex)
- if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) {
- constr.setFlag(Flags.HasDefaultParams)
- addDefaultGetter(attr, i)
- }
+ for ((attr, i) <- attrs.zipWithIndex)
+ if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) {
+ constr.setFlag(Flags.HasDefaultParams)
+ addDefaultGetter(attr, i)
+ }
+ }
+
+ addConstr(paramTypes)
+ if (paramTypes.nonEmpty)
+ paramTypes.last match {
+ case defn.ArrayType(elemtp) =>
+ addConstr(paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp))
+ case _ =>
+ }
+
}
}
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index dc6d8c6ab..41f007e66 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -101,16 +101,12 @@ trait Reporting { this: Context =>
def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
reporter.incomplete(new Error(msg, pos))(ctx)
- /** Log msg if current phase or its precedessor is mentioned in
- * settings.log.
- * The reason we also pick the predecessor is that during the
- * tree transform of phase X, we often are already in phase X+1.
- * It's convenient to have logging work independently of whether
- * we have advanced the phase or not.
+ /** Log msg if settings.log contains the current phase.
+ * See [[config.CompilerCommand#explainAdvanced]] for the exact meaning of
+ * "contains" here.
*/
def log(msg: => String): Unit =
- if (this.settings.log.value.containsPhase(phase) ||
- this.settings.log.value.containsPhase(phase.prev))
+ if (this.settings.log.value.containsPhase(phase))
echo(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg")
def debuglog(msg: => String): Unit =
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 7f1ff1ad1..dedff0e3a 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -628,10 +628,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedCases(cases: List[untpd.CaseDef], selType: Type, pt: Type)(implicit ctx: Context) = {
/** gadtSyms = "all type parameters of enclosing methods that appear
- * non-variantly in the selector type" todo: should typevars
- * which appear with variances +1 and -1 (in different
- * places) be considered as well?
- */
+ * non-variantly in the selector type" todo: should typevars
+ * which appear with variances +1 and -1 (in different
+ * places) be considered as well?
+ */
val gadtSyms: Set[Symbol] = ctx.traceIndented(i"GADT syms of $selType", gadts) {
val accu = new TypeAccumulator[Set[Symbol]] {
def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = {
@@ -650,9 +650,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
cases mapconserve (typedCase(_, pt, selType, gadtSyms))
}
+ /** Type a case. Overridden in ReTyper, that's why it's separate from
+ * typedCases.
+ */
def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") {
+ val originalCtx = ctx
+
def caseRest(pat: Tree)(implicit ctx: Context) = {
- gadtSyms foreach (_.resetGADTFlexType)
pat foreachSubTree {
case b: Bind =>
if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol)
@@ -661,11 +665,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val guard1 = typedExpr(tree.guard, defn.BooleanType)
val body1 = typedExpr(tree.body, pt)
+ .ensureConforms(pt)(originalCtx) // insert a cast if body does not conform to expected type if we disregard gadt bounds
assignType(cpy.CaseDef(tree)(pat, guard1, body1), body1)
}
- val doCase: () => CaseDef =
- () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope)
- (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))()
+
+ val gadtCtx =
+ if (gadtSyms.isEmpty) ctx
+ else {
+ val c = ctx.fresh.setFreshGADTBounds
+ for (sym <- gadtSyms)
+ if (!c.gadt.bounds.contains(sym))
+ c.gadt.setBounds(sym, TypeBounds.empty)
+ c
+ }
+ val pat1 = typedPattern(tree.pat, selType)(gadtCtx)
+ caseRest(pat1)(gadtCtx.fresh.setNewScope)
}
def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") {
diff --git a/test/test/DottyTest.scala b/test/test/DottyTest.scala
index 90a0154ec..21eebd660 100644
--- a/test/test/DottyTest.scala
+++ b/test/test/DottyTest.scala
@@ -14,7 +14,7 @@ import dotty.tools.dotc.Compiler
import dotty.tools.dotc
import dotty.tools.dotc.core.Phases.Phase
-class DottyTest extends ContextEscapeDetection{
+class DottyTest /*extends ContextEscapeDetection*/ {
dotty.tools.dotc.parsing.Scanners // initialize keywords
@@ -36,11 +36,12 @@ class DottyTest extends ContextEscapeDetection{
base.definitions.init(ctx)
ctx
}
-
+/*
override def getCtx: Context = ctx
override def clearCtx() = {
ctx = null
}
+*/
private def compilerWithChecker(phase: String)(assertion:(tpd.Tree, Context) => Unit) = new Compiler {
self =>
override def phases = {
diff --git a/tests/pending/pos/annot.scala b/tests/pending/pos/annot.scala
deleted file mode 100644
index 8e21803b4..000000000
--- a/tests/pending/pos/annot.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-class Test {
-
- @SuppressWarnings("hi") def foo() = ???
-
-}
diff --git a/tests/pos/annot.scala b/tests/pos/annot.scala
index ab80aba27..c3a17ff1d 100644
--- a/tests/pos/annot.scala
+++ b/tests/pos/annot.scala
@@ -2,11 +2,11 @@ import java.beans.Transient
class Test {
- @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deffered as requires implicit resolution(only generic Array$.apply applies here)
+ @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deferred as requires implicit resolution(only generic Array$.apply applies here)
- @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deffered as there is a non-generic method
+ @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deferred as there is a non-generic method
-// @SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck
+ @SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck
@Transient(false) def bar = ???
diff --git a/tests/pos/i0268.scala b/tests/pos/i0268.scala
new file mode 100644
index 000000000..6ac0c5c90
--- /dev/null
+++ b/tests/pos/i0268.scala
@@ -0,0 +1,15 @@
+package typespatmat
+
+sealed trait Box2[T]
+final case class Int2(x: Int) extends Box2[Int]
+final case class Str2(x: String)
+ extends Box2[String]
+final case class Gen[T](x: T) extends Box2[T]
+
+object Box2 {
+ def double2[T](x: Box2[T]): T = x match {
+ case Int2(i) => i * 2
+ case Str2(s) => s + s
+ case Gen(x) => x
+ }
+}