Skip to content

Don't synthesize context functions with embedded wildcards #11527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
*/
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
14 changes: 14 additions & 0 deletions tests/neg/i11350.check
Original file line number Diff line number Diff line change
@@ -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[<?>]
2 changes: 2 additions & 0 deletions tests/neg/i11350.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class A1[T](action: A1[T] ?=> String = "") // error
class A2[T](action: A1[T] ?=> String = summon[A1[T]]) // error
5 changes: 5 additions & 0 deletions tests/pos/i11350.scala
Original file line number Diff line number Diff line change
@@ -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