diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d403aa1dd183..3bb56a77e7da 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4966,34 +4966,51 @@ object Types { } class TypeSizeAccumulator(implicit ctx: Context) extends TypeAccumulator[Int] { - def apply(n: Int, tp: Type): Int = tp match { - case tp: AppliedType => - foldOver(n + 1, tp) - case tp: RefinedType => - foldOver(n + 1, tp) - case tp: TypeRef if tp.info.isTypeAlias => - apply(n, tp.superType) - case _ => - foldOver(n, tp) + val seen = new java.util.IdentityHashMap[Type, Type] + def apply(n: Int, tp: Type): Int = + if (seen.get(tp) != null) n + else { + seen.put(tp, tp) + tp match { + case tp: AppliedType => + foldOver(n + 1, tp) + case tp: RefinedType => + foldOver(n + 1, tp) + case tp: TypeRef if tp.info.isTypeAlias => + apply(n, tp.superType) + case tp: TypeParamRef => + apply(n, ctx.typeComparer.bounds(tp)) + case _ => + foldOver(n, tp) + } } } class CoveringSetAccumulator(implicit ctx: Context) extends TypeAccumulator[Set[Symbol]] { + val seen = new java.util.IdentityHashMap[Type, Type] def apply(cs: Set[Symbol], tp: Type): Set[Symbol] = { - val sym = tp.typeSymbol - tp match { - case tp if tp.isTopType || tp.isBottomType => - cs - case tp: AppliedType => - foldOver(cs + sym, tp) - case tp: RefinedType => - foldOver(cs + sym, tp) - case tp: TypeRef if tp.info.isTypeAlias => - apply(cs, tp.superType) - case tp: TypeBounds => - foldOver(cs, tp) - case other => - foldOver(cs + sym, tp) + if (seen.get(tp) != null) cs + else { + seen.put(tp, tp) + tp match { + case tp if tp.isTopType || tp.isBottomType => + cs + case tp: AppliedType => + foldOver(cs + tp.typeSymbol, tp) + case tp: RefinedType => + foldOver(cs + tp.typeSymbol, tp) + case tp: TypeRef if tp.info.isTypeAlias => + apply(cs, tp.superType) + case tp: TypeRef if tp.typeSymbol.isClass => + foldOver(cs + tp.typeSymbol, tp) + case tp: TermRef => + val tsym = if (tp.termSymbol.is(Param)) tp.underlying.typeSymbol else tp.termSymbol + foldOver(cs + tsym, tp) + case tp: TypeParamRef => + apply(cs, ctx.typeComparer.bounds(tp)) + case other => + foldOver(cs, tp) + } } } } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index c488f915013b..3eb8becb2d41 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1413,9 +1413,10 @@ abstract class SearchHistory { outer => if (cand1.ref == cand.ref) { val wideTp = tp.widenExpr lazy val wildTp = wildApprox(wideTp) + lazy val tpSize = wideTp.typeSize if (belowByname && (wildTp <:< wildPt)) false - else if ((wideTp.typeSize < ptSize && wideTp.coveringSet == ptCoveringSet) || (wildTp =:= wildPt)) true - else loop(tl, isByname(tp) || belowByname) + else if (tpSize > ptSize || wideTp.coveringSet != ptCoveringSet) loop(tl, isByname(tp) || belowByname) + else tpSize < ptSize || wildTp =:= wildPt || loop(tl, isByname(tp) || belowByname) } else loop(tl, isByname(tp) || belowByname) } diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index ce81eabc4f0c..b275459485c4 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -171,7 +171,8 @@ class CompilationTests extends ParallelTesting { compileList("duplicate source", List( "tests/neg-custom-args/toplevel-samesource/S.scala", "tests/neg-custom-args/toplevel-samesource/nested/S.scala"), - defaultOptions) + defaultOptions) + + compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes) }.checkExpectedErrors() @Test def fuzzyAll: Unit = { diff --git a/tests/neg-custom-args/i6300.scala b/tests/neg-custom-args/i6300.scala new file mode 100644 index 000000000000..f69766b06b01 --- /dev/null +++ b/tests/neg-custom-args/i6300.scala @@ -0,0 +1,8 @@ +object Test { + class Foo[T <: Foo[T]] + class Bar extends Foo[Bar] + + implicit def i[T <: Foo[T]](implicit t: Foo[Foo[T]]): Foo[T] = ??? + + implicitly[Foo[Bar]] // error +}