Skip to content

Commit 825f8de

Browse files
authored
Merge pull request #2402 from dotty-staging/fix-#2397
Fix #2397: Upgrade hasMatchingMember
2 parents a391a58 + be1312a commit 825f8de

File tree

5 files changed

+75
-33
lines changed

5 files changed

+75
-33
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -888,35 +888,44 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
888888
* Normalization is as follows: If `tp2` contains a skolem to its refinement type,
889889
* rebase both itself and the member info of `tp` on a freshly created skolem type.
890890
*/
891-
protected def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean = {
892-
val rinfo2 = tp2.refinedInfo
893-
val mbr = tp1.member(name)
894-
895-
def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
896-
897-
def memberMatches: Boolean = mbr match { // inlined hasAltWith for performance
898-
case mbr: SingleDenotation => qualifies(mbr)
899-
case _ => mbr hasAltWith qualifies
900-
}
901-
902-
// special case for situations like:
903-
// class C { type T }
904-
// val foo: C
905-
// foo.type <: C { type T {= , <: , >:} foo.T }
906-
def selfReferentialMatch = tp1.isInstanceOf[SingletonType] && {
907-
rinfo2 match {
908-
case rinfo2: TypeBounds =>
909-
val mbr1 = tp1.select(name)
910-
!defn.isBottomType(tp1.widen) &&
911-
(mbr1 =:= rinfo2.hi || (rinfo2.hi ne rinfo2.lo) && mbr1 =:= rinfo2.lo)
891+
protected def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean =
892+
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member(name).info}", subtyping) /*<|<*/ {
893+
val rinfo2 = tp2.refinedInfo
894+
895+
// If the member is an abstract type, compare the member itself
896+
// instead of its bounds. This case is needed situations like:
897+
//
898+
// class C { type T }
899+
// val foo: C
900+
// foo.type <: C { type T {= , <: , >:} foo.T }
901+
//
902+
// or like:
903+
//
904+
// class C[T]
905+
// C[_] <: C[TV]
906+
//
907+
// where TV is a type variable. See i2397.scala for an example of the latter.
908+
def matchAbstractTypeMember(info1: Type) = info1 match {
909+
case TypeBounds(lo, hi) if lo ne hi =>
910+
tp2.refinedInfo match {
911+
case rinfo2: TypeBounds =>
912+
val ref1 = tp1.widenExpr.select(name)
913+
(rinfo2.variance > 0 || isSubType(rinfo2.lo, ref1)) &&
914+
(rinfo2.variance < 0 || isSubType(ref1, rinfo2.hi))
915+
case _ =>
916+
false
917+
}
912918
case _ => false
913919
}
914-
}
915920

916-
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}) ${mbr.info.show} $rinfo2", subtyping) /*<|<*/ {
917-
memberMatches || selfReferentialMatch
921+
def qualifies(m: SingleDenotation) =
922+
isSubType(m.info, rinfo2) || matchAbstractTypeMember(m.info)
923+
924+
tp1.member(name) match { // inlined hasAltWith for performance
925+
case mbr: SingleDenotation => qualifies(mbr)
926+
case mbr => mbr hasAltWith qualifies
927+
}
918928
}
919-
}
920929

921930
final def ensureStableSingleton(tp: Type): SingletonType = tp.stripTypeVar match {
922931
case tp: SingletonType if tp.isStable => tp

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,8 +1341,10 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
13411341
tree match {
13421342
case Typed(unapply, _) => apply(unapply, binder)
13431343
case UnApply(unfun, implicits, args) =>
1344-
val castedBinder = ref(binder).ensureConforms(tree.tpe)
1345-
val synth = if (implicits.isEmpty) unfun.appliedTo(castedBinder) else unfun.appliedTo(castedBinder).appliedToArgs(implicits)
1344+
val mt @ MethodType(_) = unfun.tpe.widen
1345+
val castedBinder = ref(binder).ensureConforms(mt.paramInfos.head)
1346+
var synth = unfun.appliedTo(castedBinder)
1347+
if (implicits.nonEmpty) synth = synth.appliedToArgs(implicits)
13461348
new ExtractorCallRegular(alignPatterns(tree, synth.tpe), synth, args, synth.tpe)
13471349
}
13481350
}

tests/neg/t5729.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait T[X]
2+
object Test {
3+
def join(in: Seq[T[_]]): Int = ???
4+
def join[S](in: Seq[T[S]]): String = ???
5+
join(null: Seq[T[_]]) // error: ambiguous
6+
}
7+
8+
object C {
9+
def join(in: Seq[List[_]]): Int = error("TODO")
10+
def join[S](in: Seq[List[S]]): String = error("TODO")
11+
12+
join(Seq[List[Int]]()) // error: ambiguous
13+
//
14+
// ./a.scala:13: error: ambiguous reference to overloaded definition,
15+
// both method join in object C of type [S](in: Seq[List[S]])String
16+
// and method join in object C of type (in: Seq[List[_]])Int
17+
// match argument types (Seq[List[Int]])
18+
// join(Seq[List[Int]]())
19+
// ^
20+
// one error found
21+
}

tests/pos/i2397.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Foo[A]
2+
3+
object Test {
4+
def foo[T](x: Foo[T]) = x
5+
6+
foo((new Foo[Int]: Foo[_]))
7+
}
8+
9+
import java.nio.file._
10+
import java.util.stream.Collectors
11+
12+
object Foo {
13+
Files.walk(Paths.get("")).collect(Collectors.toList[Path])
14+
}
15+
16+

tests/pos/t5729.scala

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)