diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 91f5c2258ea7..0baba88d53b9 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1355,12 +1355,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling * for equality would give the wrong result, so we should not use the sets * for comparisons. */ - def canCompare(ts: Set[Type]) = ctx.phase.isTyper || { - val hasSkolems = new ExistsAccumulator(_.isInstanceOf[SkolemType]) { - override def stopAtStatic = true - } - !ts.exists(hasSkolems(false, _)) - } + def canCompare(ts: Set[Type]) = + ctx.phase.isTyper + || !ts.exists(_.existsPart(_.isInstanceOf[SkolemType], stopAtStatic = true)) + def verified(result: Boolean): Boolean = if Config.checkAtomsComparisons then try diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 26ce67614c3e..3390e3063fe9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -422,8 +422,8 @@ object Types { /** Returns true if there is a part of this type that satisfies predicate `p`. */ - final def existsPart(p: Type => Boolean, forceLazy: Boolean = true)(using Context): Boolean = - new ExistsAccumulator(p, forceLazy).apply(false, this) + final def existsPart(p: Type => Boolean, stopAtStatic: Boolean = false, forceLazy: Boolean = true)(using Context): Boolean = + new ExistsAccumulator(p, stopAtStatic, forceLazy).apply(false, this) /** Returns true if all parts of this type satisfy predicate `p`. */ @@ -5686,11 +5686,12 @@ object Types { protected def traverseChildren(tp: Type): Unit = foldOver((), tp) } - class ExistsAccumulator(p: Type => Boolean, forceLazy: Boolean = true)(using Context) extends TypeAccumulator[Boolean] { - override def stopAtStatic: Boolean = false + class ExistsAccumulator( + p: Type => Boolean, + override val stopAtStatic: Boolean, + forceLazy: Boolean)(using Context) extends TypeAccumulator[Boolean]: def apply(x: Boolean, tp: Type): Boolean = x || p(tp) || (forceLazy || !tp.isInstanceOf[LazyRef]) && foldOver(x, tp) - } class ForeachAccumulator(p: Type => Unit, override val stopAtStatic: Boolean)(using Context) extends TypeAccumulator[Unit] { def apply(x: Unit, tp: Type): Unit = foldOver(p(tp), tp) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 8087396e4084..f77dc285ee8e 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -669,12 +669,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } // Cannot use standard `existsPart` method because it calls `lookupRefined` // which can cause CyclicReference errors. - val isBoundAccumulator = new ExistsAccumulator(isBound) { - override def foldOver(x: Boolean, tp: Type): Boolean = tp match { + val isBoundAccumulator = new ExistsAccumulator(isBound, stopAtStatic = true, forceLazy = true): + override def foldOver(x: Boolean, tp: Type): Boolean = tp match case tp: TypeRef => applyToPrefix(x, tp) case _ => super.foldOver(x, tp) - } - } + def removeSingleton(tp: Type): Type = if (tp isRef defn.SingletonClass) defn.AnyType else tp def elim(tp: Type): Type = tp match { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index cdd1076a48c6..7d7296ec7ce4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1203,7 +1203,7 @@ class Typer extends Namer * @post: If result exists, `paramIndex` is defined for the name of * every parameter in `params`. */ - lazy val calleeType: Type = untpd.stripAnnotated(fnBody) match { + lazy val calleeType: Type = untpd.stripAnnotated(untpd.unsplice(fnBody)) match { case ident: untpd.Ident if isContextual => val ident1 = typedIdent(ident, WildcardType) val tp = ident1.tpe.widen @@ -2700,7 +2700,7 @@ class Typer extends Namer // see tests/pos/i7778b.scala val paramTypes = { - val hasWildcard = formals.exists(_.isInstanceOf[WildcardType]) + val hasWildcard = formals.exists(_.existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true)) if hasWildcard then formals.map(_ => untpd.TypeTree()) else formals.map(untpd.TypeTree) } diff --git a/tests/neg/i11350.check b/tests/neg/i11350.check new file mode 100644 index 000000000000..3a43ac6a12b8 --- /dev/null +++ b/tests/neg/i11350.check @@ -0,0 +1,14 @@ +-- [E081] Type Error: tests/neg/i11350.scala:1:39 ---------------------------------------------------------------------- +1 |class A1[T](action: A1[T] ?=> String = "") // error + | ^ + | Missing parameter type + | + | I could not infer the type of the parameter evidence$1. + | What I could infer was: A1[] +-- [E081] Type Error: tests/neg/i11350.scala:2:39 ---------------------------------------------------------------------- +2 |class A2[T](action: A1[T] ?=> String = summon[A1[T]]) // error + | ^ + | Missing parameter type + | + | I could not infer the type of the parameter evidence$2. + | What I could infer was: A1[] diff --git a/tests/neg/i11350.scala b/tests/neg/i11350.scala new file mode 100644 index 000000000000..d754214c79de --- /dev/null +++ b/tests/neg/i11350.scala @@ -0,0 +1,2 @@ +class A1[T](action: A1[T] ?=> String = "") // error +class A2[T](action: A1[T] ?=> String = summon[A1[T]]) // error diff --git a/tests/pos/i11350.scala b/tests/pos/i11350.scala new file mode 100644 index 000000000000..a5bfced67a79 --- /dev/null +++ b/tests/pos/i11350.scala @@ -0,0 +1,5 @@ +case class A[T](action: A[T] ?=> String) // error + +class A1[T](action: A1[T] ?=> String = (_: A1[T]) ?=> "") // works +case class A2[T](action: A2[?] ?=> String) // works +case class A3[T](action: A3[T] => String) // works as well