aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/TypedTrees.scala10
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala15
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala1
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala6
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala223
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala108
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala15
-rw-r--r--src/dotty/tools/dotc/core/Types.scala8
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala2
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala15
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala11
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala18
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala16
-rw-r--r--tests/pos/inferred.scala15
16 files changed, 287 insertions, 180 deletions
diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala
index a34e015b8..a126108aa 100644
--- a/src/dotty/tools/dotc/ast/TypedTrees.scala
+++ b/src/dotty/tools/dotc/ast/TypedTrees.scala
@@ -32,7 +32,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = {
val owntype =
- if (mix.isEmpty) ctx.glb(qual.tpe.parents)
+ if (mix.isEmpty) ctx.typeComparer.glb(qual.tpe.parents)
else {
val mixParents = qual.tpe.parents filter (_.name == mix)
check(mixParents.length == 1)
@@ -132,7 +132,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
- untpd.Match(selector, cases).withType(ctx.lub(cases.tpes)).checked
+ untpd.Match(selector, cases).withType(ctx.typeComparer.lub(cases.tpes)).checked
def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef =
untpd.CaseDef(pat, guard, body).withType(body.tpe).checked
@@ -148,7 +148,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
untpd.SeqLiteral(elems)
- .withType(defn.SeqClass.typeConstructor.appliedTo(ctx.lub(elems.tpes)))
+ .withType(defn.SeqClass.typeConstructor.appliedTo(ctx.typeComparer.lub(elems.tpes)))
.checked
def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral = {
@@ -160,7 +160,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def JavaSeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
new untpd.JavaSeqLiteral(elems)
- .withType(defn.ArrayClass.typeConstructor.appliedTo(ctx.lub(elems.tpes)))
+ .withType(defn.ArrayClass.typeConstructor.appliedTo(ctx.typeComparer.lub(elems.tpes)))
.checked
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
@@ -204,7 +204,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
untpd.Bind(sym.name, body).withType(refType(sym)).checked
def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative =
- untpd.Alternative(trees).withType(ctx.lub(trees map (_.tpe))).checked
+ untpd.Alternative(trees).withType(ctx.typeComparer.lub(trees map (_.tpe))).checked
def UnApply(fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = {
val owntype = fun.tpe.widen match {
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index 72cfe6d75..68f56d6d9 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -161,6 +161,7 @@ class ScalaSettings extends Settings.SettingGroup {
val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.")
val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.")
+ val Yexplainlowlevel = BooleanSetting("-Yexplainlowlevel", "When explaining type errors, show types at a lower level.")
val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize"
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index c74428be5..af797c09b 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -43,7 +43,7 @@ class Constraint(val map: SimpleMap[PolyType, Array[Type]]) extends AnyVal with
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain.
*/
- def - (param: PolyParam) = {
+ def - (param: PolyParam)(implicit ctx: Context) = {
val pt = param.binder
val pnum = param.paramNum
val entries = map(pt)
@@ -107,11 +107,16 @@ class Constraint(val map: SimpleMap[PolyType, Array[Type]]) extends AnyVal with
if entries(n).exists
} yield PolyParam(poly, n)
- override def toText(printer: Printer): Text = {
- val dom = domainPolys map (_.toText(printer))
+ def constrainedTypesText(printer: Printer): Text =
+ Text(domainPolys map (_.toText(printer)), ", ")
+
+ def constraintText(indent: Int, printer: Printer): Text = {
val assocs =
for (param <- domainParams)
- yield " " ~ param.toText(printer) ~ this(param).toText(printer)
- "Constraint(" ~ Text(dom, ", ") ~ ") {" ~ Text(assocs, "\n") ~ "}"
+ yield (" " * indent) ~ param.toText(printer) ~ this(param).toText(printer)
+ Text(assocs, "\n")
}
+
+ override def toText(printer: Printer): Text =
+ "Constraint(" ~ constrainedTypesText(printer) ~ ") {" ~ constraintText(2, printer) ~ "}"
}
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 476b97ec2..7888d2f8c 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -6,6 +6,7 @@ import Symbols._
import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer
import util.Positions.Position, util.SourcePosition
import collection.mutable.ListBuffer
+import scala.language.implicitConversions
/** This object provides useful implicit decorators for types defined elsewhere */
object Decorators {
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 135dfe148..0d1c9b597 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -739,13 +739,11 @@ object SymDenotations {
myThisType
}
- private def computeThisType(implicit ctx: Context): Type = ThisType(classSymbol)
- /* was:
+ private def computeThisType(implicit ctx: Context): Type = ThisType(classSymbol) /*
if ((this is PackageClass) && !isRoot)
TermRef(owner.thisType, name.toTermName)
else
- ThisType(classSymbol)
- */
+ ThisType(classSymbol) */
private[this] var myTypeConstructor: TypeRef = null
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index b3039c730..cf7b18f88 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -21,23 +21,47 @@ class TypeComparer(initctx: Context) extends DotClass {
private var pendingSubTypes: mutable.Set[(Type, Type)] = null
private var recCount = 0
+ private var frozenConstraint = false
+
+ private var myAnyType: Type = null
+ private var myNothingType: Type = null
+ private var myNullType: Type = null
+ private var myObjectType: Type = null
+ def AnyType = {
+ if (myAnyType == null) myAnyType = defn.AnyType
+ myAnyType
+ }
+ def NothingType = {
+ if (myNothingType == null) myNothingType = defn.NothingType
+ myNothingType
+ }
+ def NullType = {
+ if (myNullType == null) myNullType = defn.NullType
+ myNullType
+ }
+ def ObjectType = {
+ if (myObjectType == null) myObjectType = defn.ObjectType
+ myObjectType
+ }
+
/** Add the constraint `<bounds.lo <: param <: bounds.hi>`
* to `constraint`.
* @pre `param` is in the constraint's domain
*/
- def addConstraint(param: PolyParam, bounds: TypeBounds): Boolean = {
- val pt = param.binder
- val pnum = param.paramNum
- val oldEntries = constraint(pt)
- val oldBounds = oldEntries(pnum).asInstanceOf[TypeBounds]
- val newBounds = oldBounds & bounds
- if (oldBounds ne newBounds) {
- val newEntries = oldEntries.clone
- newEntries(pnum) = newBounds
- constraint = constraint.updated(pt, newEntries)
+ def addConstraint(param: PolyParam, bounds: TypeBounds): Boolean =
+ !frozenConstraint && {
+ val pt = param.binder
+ val pnum = param.paramNum
+ val oldEntries = constraint(pt)
+ val oldBounds = oldEntries(pnum).asInstanceOf[TypeBounds]
+ val newBounds = oldBounds & bounds
+ if (oldBounds ne newBounds) {
+ val newEntries = oldEntries.clone
+ newEntries(pnum) = newBounds
+ constraint = constraint.updated(pt, newEntries)
+ }
+ isSubType(newBounds.lo, newBounds.hi)
}
- isSubType(newBounds.lo, newBounds.hi)
- }
/** Solve constraint for given type parameter `param`.
* If `fromBelow` is true the parameter is approximated by its lower bound,
@@ -66,6 +90,12 @@ class TypeComparer(initctx: Context) extends DotClass {
inst
}
+ def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ frozenConstraint = true
+ try isSubType(tp1, tp2)
+ finally frozenConstraint = false
+ }
+
def isSubType(tp1: Type, tp2: Type): Boolean =
if (tp1 == NoType || tp2 == NoType) false
else if (tp1 eq tp2) true
@@ -120,7 +150,7 @@ class TypeComparer(initctx: Context) extends DotClass {
tp1.name == tp2.name && isSubType(pre1, pre2)
|| sym2.isClass && {
val base = tp1.baseType(sym2)
- (base ne tp1) && isSubType(base, tp2)
+ base.exists && (base ne tp1) && isSubType(base, tp2)
}
|| thirdTryNamed(tp1, tp2))
case _ =>
@@ -189,9 +219,11 @@ class TypeComparer(initctx: Context) extends DotClass {
thirdTryNamed(tp1, tp2)
case tp2: RefinedType =>
isSubType(tp1, tp2.parent) && (
- tp2.refinedName == nme.WILDCARD ||
- tp1.member(tp2.refinedName).hasAltWith(alt =>
- isSubType(alt.info, tp2.refinedInfo)))
+ tp2.refinedName == nme.WILDCARD
+ || (tp1 eq NothingType)
+ || (tp1 eq NullType)
+ || tp1.member(tp2.refinedName).hasAltWith(alt =>
+ isSubType(alt.info, tp2.refinedInfo)))
case AndType(tp21, tp22) =>
isSubType(tp1, tp21) && isSubType(tp1, tp22)
case OrType(tp21, tp22) =>
@@ -226,7 +258,8 @@ class TypeComparer(initctx: Context) extends DotClass {
case TypeBounds(lo2, hi2) =>
tp1 match {
case TypeBounds(lo1, hi1) =>
- isSubType(lo2, lo1) && isSubType(hi1, hi2)
+ ((lo2 eq NothingType) || isSubType(lo2, lo1)) &&
+ ((hi2 eq AnyType) || isSubType(hi1, hi2))
case tp1: ClassInfo =>
val tt = tp1.typeConstructor // was typeTemplate
isSubType(lo2, tt) && isSubType(tt, hi2)
@@ -246,8 +279,8 @@ class TypeComparer(initctx: Context) extends DotClass {
def fourthTry(tp1: Type, tp2: Type): Boolean = tp1 match {
case tp1: TypeRef =>
- ((tp1 eq defn.NothingType)
- || (tp1 eq defn.NullType) && tp2.dealias.typeSymbol.isNonValueClass
+ ((tp1 eq NothingType)
+ || (tp1 eq NullType) && tp2.dealias.typeSymbol.isNonValueClass
|| (tp1.info match {
case TypeBounds(lo1, hi1) =>
isSubType(hi1, tp2) ||
@@ -353,8 +386,8 @@ class TypeComparer(initctx: Context) extends DotClass {
formals2 match {
case formal2 :: rest2 =>
(isSameType(formal1, formal2)
- || isJava1 && formal2 == defn.ObjectType && formal1 == defn.AnyType
- || isJava2 && formal1 == defn.ObjectType && formal2 == defn.AnyType) && matchingParams(rest1, rest2, isJava1, isJava2)
+ || isJava1 && formal2 == ObjectType && formal1 == AnyType
+ || isJava2 && formal1 == ObjectType && formal2 == AnyType) && matchingParams(rest1, rest2, isJava1, isJava2)
case nil =>
false
}
@@ -367,12 +400,156 @@ class TypeComparer(initctx: Context) extends DotClass {
else if (tp1 eq tp2) true
else isSubType(tp1, tp2) && isSubType(tp2, tp1)
+ def glb(tp1: Type, tp2: Type): Type =
+ if (tp1 eq tp2) tp1
+ else if (!tp1.exists || (tp1 eq AnyType) || (tp2 eq NothingType)) tp2
+ else if (!tp2.exists || (tp2 eq AnyType) || (tp1 eq NothingType)) tp1
+ else tp2 match { // normalize to disjunctive normal form if possible.
+ case OrType(tp21, tp22) =>
+ tp1 & tp21 | tp1 & tp22
+ case _ =>
+ tp1 match {
+ case OrType(tp11, tp12) =>
+ tp11 & tp2 | tp12 & tp2
+ case _ =>
+ val t1 = mergeIfSub(tp1, tp2)
+ if (t1.exists) t1
+ else {
+ val t2 = mergeIfSub(tp2, tp1)
+ if (t2.exists) t2
+ else {
+ tp1 match {
+ case tp1: TypeType =>
+ tp2 match {
+ case tp2: TypeType =>
+ val b1 = tp1.bounds
+ val b2 = tp2.bounds
+ return TypeBounds(b1.lo | b2.lo, b1.hi & b2.hi)
+ case _ =>
+ }
+ case _ =>
+ }
+ AndType(tp1, tp2)
+ }
+ }
+ }
+ }
+
+ final def glb(tps: List[Type]): Type =
+ (AnyType /: tps)(glb)
+
+ def lub(tp1: Type, tp2: Type): Type =
+ if (tp1 eq tp2) tp1
+ else if (!tp1.exists || (tp1 eq AnyType) || (tp2 eq NothingType)) tp1
+ else if (!tp2.exists || (tp2 eq AnyType) || (tp1 eq NothingType)) tp2
+ else {
+ val t1 = mergeIfSuper(tp1, tp2)
+ if (t1.exists) t1
+ else {
+ val t2 = mergeIfSuper(tp2, tp1)
+ if (t2.exists) t2
+ else {
+ tp1 match {
+ case tp1: TypeType =>
+ tp2 match {
+ case tp2: TypeType =>
+ val b1 = t1.bounds
+ val b2 = t2.bounds
+ return TypeBounds(b1.lo & b2.lo, b1.hi | b2.hi)
+ case _ =>
+ }
+ case _ =>
+ }
+ OrType(tp1, tp2)
+ }
+ }
+ }
+
+ final def lub(tps: List[Type]): Type =
+ (NothingType /: tps)(lub)
+
+ /** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
+ */
+ private def mergeIfSub(tp1: Type, tp2: Type): Type =
+ if (isSubTypeWhenFrozen(tp1, tp2))
+ if (isSubTypeWhenFrozen(tp2, tp1)) tp2 else tp1 // keep existing type if possible
+ else tp2 match {
+ case tp2 @ AndType(tp21, tp22) =>
+ val lower1 = mergeIfSub(tp1, tp21)
+ if (lower1 eq tp21) tp2
+ else if (lower1.exists) lower1 & tp22
+ else {
+ val lower2 = mergeIfSub(tp1, tp22)
+ if (lower2 eq tp22) tp2
+ else if (lower2.exists) tp21 & lower2
+ else NoType
+ }
+ case _ =>
+ NoType
+ }
+
+ /** Merge `tp1` into `tp2` if tp1 is a supertype of some |-summand of tp2.
+ */
+ private def mergeIfSuper(tp1: Type, tp2: Type): Type =
+ if (isSubTypeWhenFrozen(tp2, tp1))
+ if (isSubTypeWhenFrozen(tp1, tp2)) tp2 else tp1 // keep existing type if possible
+ else tp2 match {
+ case tp2 @ OrType(tp21, tp22) =>
+ val higher1 = mergeIfSuper(tp1, tp21)
+ if (higher1 eq tp21) tp2
+ else if (higher1.exists) higher1 | tp22
+ else {
+ val higher2 = mergeIfSuper(tp1, tp22)
+ if (higher2 eq tp22) tp2
+ else if (higher2.exists) tp21 | higher2
+ else NoType
+ }
+ case _ =>
+ NoType
+ }
+
def copyIn(ctx: Context) = new TypeComparer(ctx)
}
class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
- override def isSubType(tp1: Type, tp2: Type) = {
- ctx.traceIndented(s"${tp1} <:< ${tp2}")(super.isSubType(tp1, tp2))
+ private var indent = 0
+ private val b = new StringBuilder
+
+ def traceIndented[T](str: String)(op: => T): T = {
+ assert(str != "<notype> <:< Int")
+ indent += 2
+ b append "\n" append (" " * indent) append "==> " append str
+ val res = op
+ b append "\n" append (" " * indent) append "<== " append str append " = " append show(res)
+ indent -= 2
+ res
}
+
+ private def show(res: Any) = res match {
+ case res: printing.Showable if !ctx.settings.Yexplainlowlevel.value => res.show
+ case _ => String.valueOf(res)
+ }
+
+ override def isSubType(tp1: Type, tp2: Type) =
+ traceIndented(s"${show(tp1)} <:< ${show(tp2)} ${tp1.getClass} ${defn.NothingType.getClass} ${tp1.normalizedPrefix} ${defn.NothingType.normalizedPrefix} ${tp1 eq defn.NothingType} ${tp1.typeSymbol eq defn.NothingClass}") {
+ super.isSubType(tp1, tp2)
+ }
+
+ override def lub(tp1: Type, tp2: Type) =
+ traceIndented(s"lub(${show(tp1)}, ${show(tp2)})") {
+ super.lub(tp1, tp2)
+ }
+
+ override def glb(tp1: Type, tp2: Type) =
+ traceIndented(s"glb(${show(tp1)}, ${show(tp2)})") {
+ super.glb(tp1, tp2)
+ }
+
override def copyIn(ctx: Context) = new ExplainingTypeComparer(ctx)
+
+ override def toString =
+ "Subtype trace:" + {
+ try b.toString
+ finally b.clear()
+ }
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 0af244054..b4418642d 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -97,114 +97,6 @@ trait TypeOps { this: Context =>
}
}
- final def glb(tp1: Type, tp2: Type): Type =
- if (tp1 eq tp2) tp1
- else if (!tp1.exists) tp2
- else if (!tp2.exists) tp1
- else tp2 match { // normalize to disjunctive normal form if possible.
- case OrType(tp21, tp22) =>
- tp1 & tp21 | tp1 & tp22
- case _ =>
- tp1 match {
- case OrType(tp11, tp12) =>
- tp11 & tp2 | tp12 & tp2
- case _ =>
- val t1 = mergeIfSub(tp1, tp2)
- if (t1.exists) t1
- else {
- val t2 = mergeIfSub(tp2, tp1)
- if (t2.exists) t2
- else {
- tp1 match {
- case tp1: TypeType =>
- tp2 match {
- case tp2: TypeType =>
- val b1 = tp1.bounds
- val b2 = tp2.bounds
- return TypeBounds(b1.lo | b2.lo, b1.hi & b2.hi)
- case _ =>
- }
- case _ =>
- }
- AndType(tp1, tp2)
- }
- }
- }
- }
-
- final def glb(tps: List[Type]): Type =
- (defn.AnyType /: tps)(glb)
-
- def lub(tp1: Type, tp2: Type): Type =
- if (tp1 eq tp2) tp1
- else if (!tp1.exists) tp1
- else if (!tp2.exists) tp2
- else {
- val t1 = mergeIfSuper(tp1, tp2)
- if (t1.exists) t1
- else {
- val t2 = mergeIfSuper(tp2, tp1)
- if (t2.exists) t2
- else {
- tp1 match {
- case tp1: TypeType =>
- tp2 match {
- case tp2: TypeType =>
- val b1 = t1.bounds
- val b2 = t2.bounds
- return TypeBounds(b1.lo & b2.lo, b1.hi | b2.hi)
- case _ =>
- }
- case _ =>
- }
- OrType(tp1, tp2)
- }
- }
- }
-
- final def lub(tps: List[Type]): Type =
- (defn.NothingType /: tps)(lub)
-
- /** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
- */
- private def mergeIfSub(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
- if (tp1 <:< tp2)
- if (tp2 <:< tp1) tp2 else tp1 // keep existing type if possible
- else tp2 match {
- case tp2 @ AndType(tp21, tp22) =>
- val lower1 = mergeIfSub(tp1, tp21)
- if (lower1 eq tp21) tp2
- else if (lower1.exists) lower1 & tp22
- else {
- val lower2 = mergeIfSub(tp1, tp22)
- if (lower2 eq tp22) tp2
- else if (lower2.exists) tp21 & lower2
- else NoType
- }
- case _ =>
- NoType
- }
-
- /** Merge `tp1` into `tp2` if tp1 is a supertype of some |-summand of tp2.
- */
- private def mergeIfSuper(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
- if (tp2 <:< tp1)
- if (tp1 <:< tp2) tp2 else tp1 // keep existing type if possible
- else tp2 match {
- case tp2 @ OrType(tp21, tp22) =>
- val higher1 = mergeIfSuper(tp1, tp21)
- if (higher1 eq tp21) tp2
- else if (higher1.exists) higher1 | tp22
- else {
- val higher2 = mergeIfSuper(tp1, tp22)
- if (higher2 eq tp22) tp2
- else if (higher2.exists) tp21 | higher2
- else NoType
- }
- case _ =>
- NoType
- }
-
/** Normalize a list of parent types of class `cls` that may contain refinements
* to a list of typerefs, by converting all refinements to member
* definitions in scope `decls`. Can add members to `decls` as a side-effect.
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 21dc73579..d14f6c24b 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -96,14 +96,17 @@ extends TyperState(reporter) {
}
override def toText(printer: Printer): Text = {
+ val header: Text = "Typer state:"
val undetVarsText =
- " undetVars = (" ~
- Text(undetVars map (_.toText(printer)), ", ") ~ ")"
+ " undetVars: " ~
+ Text(undetVars map (_.toText(printer)), ", ") ~ "."
+ val constrainedText =
+ " constrained types: " ~ constraint.constrainedTypesText(printer) ~ "."
val constraintText =
- " constraint = " ~ constraint.toText(printer)
+ " constraint: " ~ constraint.constraintText(3, printer)
val instTypeText =
- " instType = (" ~
- Text(instType.map2((k, v) => s"${k.toText(printer)} -> ${v.toText(printer)}"), ", ") ~ ")"
- Text.lines(List(undetVarsText, constraintText, instTypeText))
+ " instType: " ~
+ Text(instType.map2((k, v) => s"${k.toText(printer)} -> ${v.toText(printer)}"), ", ") ~ "."
+ Text.lines(List(header, undetVarsText, constrainedText, constraintText, instTypeText))
}
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 9c0a0ff49..36a4986b4 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -504,10 +504,10 @@ object Types {
}}
def & (that: Type)(implicit ctx: Context): Type =
- ctx.glb(this, that)
+ ctx.typeComparer.glb(this, that)
def | (that: Type)(implicit ctx: Context): Type =
- ctx.lub(this, that)
+ ctx.typeComparer.lub(this, that)
// ----- Unwrapping types -----------------------------------------------
@@ -1284,6 +1284,7 @@ object Types {
false
}
override def computeHash = doHash(fixedSym, prefix)
+ override def toString = super.toString + "(fixed sym)"
}
final class TermRefBySym(prefix: Type, name: TermName, val fixedSym: TermSymbol)
@@ -1762,7 +1763,6 @@ object Types {
/** Instantiate variable with given type */
def instantiateWith(tp: Type)(implicit ctx: Context): Type = {
assert(owningState.undetVars contains this)
- owningState.constraint -= origin
owningState.undetVars -= this
if (ctx.typerState eq creatorState) inst = tp
else ctx.typerState.instType = ctx.typerState.instType.updated(this, tp)
@@ -2010,7 +2010,7 @@ object Types {
object ErrorType extends ErrorType
/** Wildcard type, possibly with bounds */
- abstract case class WildcardType(optBounds: Type) extends CachedGroundType {
+ abstract case class WildcardType(optBounds: Type) extends CachedGroundType with TermType {
def derivedWildcardType(optBounds: Type)(implicit ctx: Context) =
if (optBounds eq this.optBounds) this else WildcardType(optBounds.asInstanceOf[TypeBounds])
override def computeHash = doHash(optBounds)
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index e2f1af5f9..f0dcb7336 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -592,7 +592,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val pre = readTypeRef()
val sym = readDisambiguatedSymbolRef(_.info.isParameterless)
if (isLocal(sym) || (pre == NoPrefix)) TermRef.withSym(pre, sym.asTerm)
- else TermRef.withSig(pre, sym.name.asTermName, NotAMethod)
+ else TermRef.withSig(pre, sym.name.asTermName, NotAMethod) // !!! should become redundant
case SUPERtpe =>
val thistpe = readTypeRef()
val supertpe = readTypeRef()
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 74c14f96d..6e81d5558 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -128,20 +128,19 @@ class PlainPrinter(_ctx: Context) extends Printer {
changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) }
case tp: PolyType =>
def paramText(name: TypeName, bounds: TypeBounds) =
- toText(polyParamName(name)) ~ toText(bounds)
+ toText(polyParamName(name)) ~ polyHash(tp) ~ toText(bounds)
changePrec(GlobalPrec) {
"[" ~
Text((tp.paramNames, tp.paramBounds).zipped map paramText, ", ") ~
"]" ~ toText(tp.resultType)
}
case PolyParam(pt, n) =>
- toText(polyParamName(pt.paramNames(n)))
+ toText(polyParamName(pt.paramNames(n))) ~ polyHash(pt)
case AnnotatedType(annot, tpe) =>
toTextLocal(tpe) ~ " " ~ toText(annot)
case tp: TypeVar =>
- toTextLocal(tp.underlying) ~ "'" // debug for now, so that we can see where the TypeVars are.
- case NoPrefix =>
- "<no-prefix>"
+ val suffix = if (tp.isInstantiated) "'" else "''"
+ toTextLocal(tp.underlying) ~ suffix // debug for now, so that we can see where the TypeVars are.
case _ =>
tp.fallbackToText(this)
}
@@ -154,7 +153,11 @@ class PlainPrinter(_ctx: Context) extends Printer {
*/
protected def simpleNameString(sym: Symbol): String = nameString(sym.name)
- /** The unique id of symbol, after a # */
+ /** If -uniqid is set, the hashcode of the polytype, after a # */
+ protected def polyHash(pt: PolyType): Text =
+ "#" + pt.hashCode provided ctx.settings.uniqid.value
+
+ /** If -uniqid is set, the unique id of symbol, after a # */
protected def idString(sym: Symbol): String =
if (ctx.settings.uniqid.value) "#" + sym.id else ""
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 57ea5ebda..a078476e3 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -68,11 +68,16 @@ object ErrorReporting {
}
def typeMismatchStr(found: Type, expected: Type) = {
- if (ctx.settings.explaintypes.value)
- (found <:< expected)(ctx.fresh.withTypeComparerFn(new ExplainingTypeComparer(_)))
+ val (typerStateStr, explanationStr) =
+ if (ctx.settings.explaintypes.value) {
+ val nestedCtx = ctx.fresh.withTypeComparerFn(new ExplainingTypeComparer(_))
+ (found <:< expected)(nestedCtx)
+ ("\n" + ctx.typerState.show, "\n" + nestedCtx.typeComparer.toString)
+ }
+ else ("", "")
i"""type mismatch:
| found : $found
- | required: $expected""".stripMargin
+ | required: $expected""".stripMargin + typerStateStr + explanationStr
}
}
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index ddac6f3bf..2de8985d9 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -172,7 +172,8 @@ trait ImplicitRunInfo { self: RunInfo =>
val pre = tp.prefix
def joinClass(tp: Type, cls: ClassSymbol) =
AndType(tp, cls.symTypeRef.asSeenFrom(pre, cls.owner))
- (apply(tp.prefix) /: tp.classSymbols)(joinClass)
+ val lead = if (tp.prefix eq NoPrefix) defn.AnyType else apply(tp.prefix)
+ (lead /: tp.classSymbols)(joinClass)
case _ =>
mapOver(tp)
}
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 58e5f73c9..7a8b94571 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -193,15 +193,15 @@ object Inferencing {
(ctx.typerState.undetVars contains tvar) && (pos contains tvar.pos))
for ((tvar, v) <- vs)
if (v == 1) {
- println(i"interpolate covariant $tvar in $tp")
+ println(s"interpolate covariant ${tvar.show} in ${tp.show}")
tvar.instantiate(fromBelow = true)
}
else if (v == -1) {
- println(i"interpolate contrvariant $tvar in $tp")
+ println(s"interpolate contrvariant ${tvar.show} in ${tp.show}")
tvar.instantiate(fromBelow = false)
}
for (tvar <- ctx.typerState.undetVars if (pos contains tvar.pos) && !(vs contains tvar)) {
- println(i"interpolate non-occurring $tvar in $tp")
+ println(s"interpolate non-occurring ${tvar.show} in ${tp.show}")
tvar.instantiate(fromBelow = true)
}
ctx.typerState.checkConsistent
@@ -229,9 +229,15 @@ object Inferencing {
* @param pos The position of the new type variables (relevant for
* interpolateUndetVars
*/
- def newTypeVars(pt: PolyType, pos: Position): List[TypeVar] =
- for (n <- (0 until pt.paramNames.length).toList)
- yield new TypeVar(PolyParam(pt, n), ctx.typerState, pos)
+ def newTypeVars(pt: PolyType, pos: Position): List[TypeVar] = {
+ val state = ctx.typerState
+ val tvars =
+ for (n <- (0 until pt.paramNames.length).toList)
+ yield new TypeVar(PolyParam(pt, n), state, pos)
+ state.constraint = state.constraint.updated(pt,
+ state.constraint(pt) map (_.substParams(pt, tvars)))
+ tvars
+ }
def isSubTypes(actuals: List[Type], formals: List[Type])(implicit ctx: Context): Boolean = formals match {
case formal :: formals1 =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 7519cdd73..a9f90b9ec 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -363,7 +363,13 @@ class Typer extends Namer with Applications with Implicits {
}
def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) =
- tree.withType(if (tree.const.tag == UnitTag) defn.UnitType else ConstantType(tree.const))
+ tree.withType {
+ tree.const.tag match {
+ case UnitTag => defn.UnitType
+ case NullTag => defn.NullType
+ case _ => ConstantType(tree.const)
+ }
+ }
def typedNew(tree: untpd.New, pt: Type)(implicit ctx: Context) = tree.tpt match {
case templ: Template =>
@@ -542,7 +548,7 @@ class Typer extends Namer with Applications with Implicits {
}
val cases1 = tree.cases mapconserve typedCase
- cpy.Match(tree, sel1, cases1).withType(ctx.lub(cases1.tpes))
+ cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes))
}
def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = {
@@ -590,7 +596,7 @@ class Typer extends Namer with Applications with Implicits {
def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = {
val proto1 = pt.elemType orElse WildcardType
val elems1 = tree.elems mapconserve (typed(_, proto1))
- cpy.SeqLiteral(tree, elems1) withType ctx.lub(elems1.tpes)
+ cpy.SeqLiteral(tree, elems1) withType ctx.typeComparer.lub(elems1.tpes)
}
def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = {
@@ -679,7 +685,7 @@ class Typer extends Namer with Applications with Implicits {
def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = {
val trees1 = tree.trees mapconserve (typed(_, pt))
- cpy.Alternative(tree, trees1) withType ctx.lub(trees1.tpes)
+ cpy.Alternative(tree, trees1) withType ctx.typeComparer.lub(trees1.tpes)
}
def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = {
@@ -839,7 +845,7 @@ class Typer extends Namer with Applications with Implicits {
}
}
- def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ctx.traceIndented (i"typing $tree", show = true) {
+ def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ctx.traceIndented (s"typing ${tree.show}", show = true) {
val tree1 = typedUnadapted(tree, pt)
ctx.interpolateUndetVars(tree1.tpe.widen, tree1.pos)
adapt(tree1, pt)
diff --git a/tests/pos/inferred.scala b/tests/pos/inferred.scala
index c138a8e53..03bd7ee6c 100644
--- a/tests/pos/inferred.scala
+++ b/tests/pos/inferred.scala
@@ -1,3 +1,12 @@
+class List[+T] {
+
+ def prepend [U >: T] (x: U): List[U] = null
+
+}
+
+object Nil extends List[Nothing]
+
+
object Inferred {
def foo[T](x: T): T = x
@@ -12,8 +21,8 @@ object Inferred {
val nn = bar(Nil)
- val ints: List[Int] = 1 :: Nil
+ val ints: List[Int] = Nil prepend 1
- val a = if (1 == 0) Nil else ints
+ // val a = if (1 == 0) Nil else ints
-}
+} \ No newline at end of file