Skip to content

Commit d495bf4

Browse files
authored
Merge pull request scala#6122 from milessabin/topic/si-10545
When testing for presence of a Symbol in a Type don't skip aliases.
2 parents 9334c20 + 16ad098 commit d495bf4

File tree

5 files changed

+120
-1
lines changed

5 files changed

+120
-1
lines changed

src/reflect/scala/reflect/internal/tpe/TypeMaps.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,11 +964,13 @@ private[internal] trait TypeMaps {
964964
// We can just map over the components and wait until we see the underlying type before we call
965965
// normalize.
966966
tp.mapOver(this)
967+
case TypeRef(_, sym1, _) if (sym == sym1) => result = true // catch aliases before normalization
967968
case _ =>
968969
tp.normalize match {
969970
case TypeRef(_, sym1, _) if (sym == sym1) => result = true
970971
case refined: RefinedType =>
971-
tp.prefix.mapOver(this)
972+
tp.prefix.mapOver(this) // Assumption is that tp was a TypeRef prior to normalization so we should
973+
// mapOver its prefix
972974
refined.mapOver(this)
973975
case SingleType(_, sym1) if (sym == sym1) => result = true
974976
case _ => tp.mapOver(this)

test/files/neg/t10545.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
t10545.scala:32: error: ambiguous implicit values:
2+
both method barF0 in object Bar of type [F[_]](implicit fooF: Foo[F])Bar[F]
3+
and method barF1 in object Bar of type [F[_]](implicit fooF: Foo[F])Bar[F]
4+
match expected type Bar[Option]
5+
implicitly[Bar[Option]]
6+
^
7+
one error found

test/files/neg/t10545.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Foo[F[_]]
2+
object Foo {
3+
// Prior to this fix these two are ambiguous
4+
implicit def fooF0[F[_]]: Foo[F] = new Foo[F]
5+
implicit def fooF1: Foo[Option] = new Foo[Option]
6+
}
7+
8+
class Bar[F[_]]
9+
object Bar extends Bar0 {
10+
// Prior to this fix these two aren't selected because there is no
11+
// Foo[F] due to the ambiguity above
12+
// After this fix these two are ambiguous
13+
implicit def barF0[F[_]](implicit fooF: Foo[F]): Bar[F] = new Bar[F]
14+
implicit def barF1[F[_]](implicit fooF: Foo[F]): Bar[F] = new Bar[F]
15+
}
16+
17+
trait Bar0 {
18+
// Prior to this fix we fall back to here
19+
implicit def barF2[F[_]]: Bar[F] = new Bar[F]
20+
}
21+
22+
object Test {
23+
// Prior to this fix Bar.barF1[Option]
24+
// After this fix,
25+
// error: ambiguous implicit values:
26+
// both method barF0 in object Bar of type [F[_]](implicit fooF: Foo[F])Bar[F]
27+
// and method barF1 in object Bar of type [F[_]](implicit fooF: Foo[F])Bar[F]
28+
// match expected type Bar[Option]
29+
// implicitly[Bar[Option]]
30+
// ^
31+
// one error found
32+
implicitly[Bar[Option]]
33+
}

test/files/run/t10545.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.language.higherKinds
2+
3+
class D[T]
4+
5+
class C[F[_]](val i: Int)
6+
object C {
7+
def apply[F[_]](implicit cf: C[F]): Int = cf.i
8+
9+
implicit def c0[F[_]]: C[F] = new C[F](0)
10+
implicit def c1: C[D] = new C[D](1)
11+
}
12+
13+
object Test extends App {
14+
assert(C[D] == 1) // Works in Dotty ...
15+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package scala.reflect.internal
2+
3+
import org.junit.Assert._
4+
import org.junit.{After, Assert, Before, Test}
5+
import org.junit.runner.RunWith
6+
import org.junit.runners.JUnit4
7+
import scala.collection.mutable
8+
import scala.tools.nsc.settings.ScalaVersion
9+
import scala.tools.nsc.symtab.SymbolTableForUnitTesting
10+
11+
import scala.tools.testing.BytecodeTesting
12+
13+
@RunWith(classOf[JUnit4])
14+
class InferTest extends BytecodeTesting {
15+
import compiler.global._, definitions._, analyzer._, typer.infer._
16+
17+
class D[T]
18+
class A
19+
20+
type DA = D[A]
21+
22+
class C[F[_]](val i: Int)
23+
24+
object Foo {
25+
implicit def foo0[F[_]]: C[F] = ???
26+
implicit def foo1: C[D] = ???
27+
}
28+
29+
@Test
30+
def testContains(): Unit = {
31+
val run = new global.Run
32+
33+
enteringPhase(run.typerPhase) {
34+
val asym = symbolOf[A]
35+
val dsym = symbolOf[D[_]]
36+
37+
val tp0 = typeOf[D[A]]
38+
assert(tp0.contains(asym))
39+
40+
val tp2 = typeOf[C[D]]
41+
assert(tp2.contains(dsym))
42+
43+
val foo0Sym = typeOf[Foo.type].member(TermName("foo0"))
44+
val foo0Tpe = foo0Sym.info
45+
46+
val PolyType(List(fSym), NullaryMethodType(restpe0)) = foo0Tpe
47+
assert(restpe0.contains(fSym))
48+
49+
// existentialAbstraction uses contains
50+
val abstracted = existentialAbstraction(List(fSym), restpe0)
51+
val expected = ExistentialType(List(fSym), restpe0)
52+
assert(abstracted == expected)
53+
54+
val foo1Sym = typeOf[Foo.type].member(TermName("foo1"))
55+
val foo1Tpe = foo1Sym.info
56+
57+
// isStrictlyMoreSpecific uses existentialAbstraction
58+
assert(!isStrictlyMoreSpecific(foo0Tpe, foo1Tpe, foo0Sym, foo1Sym))
59+
assert(isStrictlyMoreSpecific(foo1Tpe, foo0Tpe, foo1Sym, foo0Sym))
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)