Skip to content

Commit 674c3ba

Browse files
committed
Always exclude package objects from the implicit scope
Unlike Scala 2, in Dotty when constructing the implicit scope for a type `pkgA.Foo`, we do not include the main package object (`pkgA.package`). We don't include the package objects we define for top-level definitions either. However, when constructing the implicit scope for a type defined in a package object (e.g. `pkgA.foo$package.Foo`), we did including the implicits defined in the enclosing package object. This is problematic because at the source-level it's hard to distinguish which definitions will be included in the package object. For example, in the testcase included in this commit, `summon[ToString[A.AB]]` used to succeed because both the type `AB` and the given alias for `ToString[AB]` ended up wrapped in a package object, but the other summon calls failed because classes and given instances are not wrapped in a package object. To fix this inconsistency, we now always exclude package objects from the implicit scope, even for types defined in the implicit scope itself. The companion object of classes and opaque types stays the preferred place to put implicit definitions and is not affected by this change.
1 parent 91e5f35 commit 674c3ba

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,10 +507,10 @@ trait ImplicitRunInfo {
507507
val incomplete: mutable.Set[Type] = mutable.Set()
508508

509509
/** Is `sym` an anchor type for which givens may exist? Anchor types are classes,
510-
* opaque type aliases, and abstract types, but not type parameters
510+
* opaque type aliases, and abstract types, but not type parameters or package objects.
511511
*/
512512
def isAnchor(sym: Symbol) =
513-
sym.isClass && !sym.is(Package)
513+
sym.isClass && !sym.is(Package) && (!sym.isPackageObject || ctx.scala2CompatMode)
514514
|| sym.isOpaqueAlias
515515
|| sym.is(Deferred, butNot = Param)
516516

@@ -584,7 +584,7 @@ trait ImplicitRunInfo {
584584
addPath(pre.prefix)
585585
}
586586
}
587-
else {
587+
else if (!pre.symbol.isPackageObject || ctx.scala2CompatMode) {
588588
comps += pre
589589
addPath(pre.prefix)
590590
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
trait ToString[A] {
2+
def print(a: A): Unit
3+
}
4+
5+
package A {
6+
case class AA(text: String)
7+
given ToString[AA] = aa => println(aa.text)
8+
9+
opaque type AB = String
10+
given ToString[AB] = ab => println(ab)
11+
12+
opaque type AC = String
13+
given ToString[AC] {
14+
def print(ac: AC): Unit = println(ac)
15+
}
16+
}
17+
18+
package B {
19+
case class BA(text: String)
20+
object BA {
21+
given ToString[BA] = ba => println(ba.text)
22+
}
23+
24+
opaque type BB = String
25+
object BB {
26+
given ToString[BB] = bb => println(bb)
27+
}
28+
29+
opaque type BC = String
30+
object BC {
31+
given ToString[BC] {
32+
def print(bc: BC): Unit = println(bc)
33+
}
34+
}
35+
}
36+
37+
object Test {
38+
val AA = summon[ToString[A.AA]] // error
39+
val AB = summon[ToString[A.AB]] // error, used to compile
40+
val AC = summon[ToString[A.AC]] // error
41+
42+
val BA = summon[ToString[B.BA]]
43+
val BB = summon[ToString[B.BB]]
44+
val BC = summon[ToString[B.BC]]
45+
}

0 commit comments

Comments
 (0)