diff options
author | Martin Odersky <odersky@gmail.com> | 2013-09-16 17:56:17 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-09-16 17:56:17 +0200 |
commit | dba4f1ec3dc5f489056284aab63c771cdd32561c (patch) | |
tree | ab6af09b871c2a01741fd5bbe874a1e19a3fddea /src/dotty/tools/dotc | |
parent | 682cf32cbe5cebeccf9ea10caf43e74c9cecc7c0 (diff) | |
download | dotty-dba4f1ec3dc5f489056284aab63c771cdd32561c.tar.gz dotty-dba4f1ec3dc5f489056284aab63c771cdd32561c.tar.bz2 dotty-dba4f1ec3dc5f489056284aab63c771cdd32561c.zip |
Bug fixes and improvements in error diagnostics.
Main refactoring: lub/glb moves to type comparers.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/ast/TypedTrees.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Constraint.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Decorators.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 223 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeOps.scala | 108 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TyperState.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/PlainPrinter.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ErrorReporting.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 18 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 16 |
15 files changed, 275 insertions, 177 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) |