diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 331a5adc06a9..13900832d3ab 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -17,6 +17,8 @@ import reporting.trace /** Provides methods to compare types. */ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { + import TypeComparer.show + implicit val ctx = initctx val state = ctx.typerState @@ -24,6 +26,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { private[this] var pendingSubTypes: mutable.Set[(Type, Type)] = null private[this] var recCount = 0 + private[this] var monitored = false private[this] var needsGc = false @@ -101,9 +104,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { if (tp2 eq NoType) return false if ((tp2 eq tp1) || (tp2 eq WildcardType)) return true try isSubType(tp1, tp2) - finally + finally { + monitored = false if (Config.checkConstraintsSatisfiable) assert(isSatisfiable, constraint.show) + } } protected def isSubType(tp1: Type, tp2: Type): Boolean = trace(s"isSubType ${traceInfo(tp1, tp2)}", subtyping) { @@ -114,9 +119,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val savedSuccessCount = successCount try { recCount = recCount + 1 - val result = - if (recCount < Config.LogPendingSubTypesThreshold) firstTry(tp1, tp2) - else monitoredIsSubType(tp1, tp2) + if (recCount >= Config.LogPendingSubTypesThreshold) monitored = true + val result = if (monitored) monitoredIsSubType(tp1, tp2) else firstTry(tp1, tp2) recCount = recCount - 1 if (!result) state.resetConstraintTo(saved) else if (recCount == 0 && needsGc) { @@ -284,6 +288,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { if (isSubType(info1.alias, tp2)) return true if (tp1.prefix.isStable) return false case _ => + if (tp1 eq NothingType) return tp1 == tp2.bottomType } thirdTry(tp1, tp2) case tp1: TypeParamRef => @@ -1571,7 +1576,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** Show subtype goal that led to an assertion failure */ def showGoal(tp1: Type, tp2: Type)(implicit ctx: Context) = { - println(i"assertion failure for $tp1 <:< $tp2, frozen = $frozenConstraint") + println(i"assertion failure for ${show(tp1)} <:< ${show(tp2)}, frozen = $frozenConstraint") def explainPoly(tp: Type) = tp match { case tp: TypeParamRef => ctx.echo(s"TypeParamRef ${tp.show} found in ${tp.binder.show}") case tp: TypeRef if tp.symbol.exists => ctx.echo(s"typeref ${tp.show} found in ${tp.symbol.owner.show}") @@ -1603,6 +1608,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { object TypeComparer { + private[core] def show(res: Any)(implicit ctx: Context) = res match { + case res: printing.Showable if !ctx.settings.YexplainLowlevel.value => res.show + case _ => String.valueOf(res) + } + /** Show trace of comparison operations when performing `op` as result string */ def explained[T](op: Context => T)(implicit ctx: Context): String = { val nestedCtx = ctx.fresh.setTypeComparerFn(new ExplainingTypeComparer(_)) @@ -1613,6 +1623,8 @@ object TypeComparer { /** A type comparer that can record traces of subtype operations */ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { + import TypeComparer.show + private[this] var indent = 0 private val b = new StringBuilder @@ -1629,11 +1641,6 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { 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)}${if (Config.verboseExplainSubtype) s" ${tp1.getClass} ${tp2.getClass}" else ""}${if (frozenConstraint) " frozen" else ""}") { super.isSubType(tp1, tp2) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 067b9c1e15df..44fdc89c87df 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -495,9 +495,7 @@ object ProtoTypes { tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen)) case tp @ TypeParamRef(poly, pnum) => def wildApproxBounds(bounds: TypeBounds) = - if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType]) - WildcardType(wildApprox(bounds, theMap, seen).bounds) - else if (seen.contains(tp)) WildcardType + if (seen.contains(tp)) WildcardType else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds) def unconstrainedApprox = wildApproxBounds(poly.paramInfos(pnum)) def approxPoly = @@ -544,7 +542,8 @@ object ProtoTypes { case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed tp case _ => - (if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp) + (if (theMap != null && seen.eq(theMap.seen)) theMap else new WildApproxMap(seen)) + .mapOver(tp) } @sharable object AssignProto extends UncachedGroundType with MatchAlways diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index e79121c7fe6e..53e570095d02 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -171,6 +171,7 @@ class CompilationTests extends ParallelTesting { compileFilesInDir("../tests/neg-tailcall", defaultOptions) + compileFilesInDir("../tests/neg-no-optimise", defaultOptions) + compileFile("../tests/neg-custom-args/i3246.scala", scala2Mode) + + compileFile("../tests/neg-custom-args/i3627.scala", allowDeepSubtypes) + compileFile("../tests/neg-custom-args/typers.scala", allowDoubleBindings) + compileFile("../tests/neg-custom-args/overrideClass.scala", scala2Mode) + compileFile("../tests/neg-custom-args/autoTuplingTest.scala", defaultOptions.and("-language:noAutoTupling")) + diff --git a/tests/neg-custom-args/i3627.scala b/tests/neg-custom-args/i3627.scala new file mode 100644 index 000000000000..f97d6e67d582 --- /dev/null +++ b/tests/neg-custom-args/i3627.scala @@ -0,0 +1,9 @@ +trait Comparinator[T] { + def sort[T](x: Comparinator[_ >: T]) = () + sort((a: Int) => true) // error +} + +trait Comparinator2[T >: U, U] { + def sort[TT](x: Comparinator2[_ >: TT, U]) = () + sort((a: Int) => true) // error +}