Skip to content

Commit

Permalink
Merge pull request #11527 from dotty-staging/fix-11350
Browse files Browse the repository at this point in the history
Don't synthesize context functions with embedded wildcards
  • Loading branch information
liufengyun committed Feb 24, 2021
2 parents 5953af1 + 6285661 commit 0b697d5
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 17 deletions.
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 @@ -1217,7 +1217,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 @@ -2714,7 +2714,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

0 comments on commit 0b697d5

Please sign in to comment.