Skip to content

Commit ff844b5

Browse files
committed
Fix liftToClasses for opaque types
liftToClasses used to drop an opaque types from the set of types whose companion modules are included. Opaque types do not have companion modules, but their prefixes might, so it is incorrect to drop them.
1 parent a1b6bb6 commit ff844b5

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

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

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ object Implicits {
232232
*/
233233
class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
234234
assert(initctx.typer != null)
235+
implicits.println(i"implicits of type $tp = ${companionRefs.toList}%, %")
235236
@threadUnsafe lazy val refs: List[ImplicitRef] = {
236237
val buf = new mutable.ListBuffer[TermRef]
237238
for (companion <- companionRefs) buf ++= companion.implicitMembers(ImplicitOrImpliedOrGiven)
@@ -492,12 +493,21 @@ trait ImplicitRunInfo { self: Run =>
492493
override implicit protected val ctx: Context = liftingCtx
493494
override def stopAtStatic = true
494495
def apply(tp: Type) = tp match {
495-
case tp: TypeRef if !tp.symbol.isClass =>
496-
val pre = tp.prefix
497-
def joinClass(tp: Type, cls: ClassSymbol) =
498-
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner))
499-
val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre)
500-
(lead /: tp.classSymbols)(joinClass)
496+
case tp: NamedType =>
497+
tp.info match {
498+
case TypeAlias(alias) =>
499+
apply(alias)
500+
case TypeBounds(_, hi) =>
501+
if (tp.symbol.isOpaqueAlias) tp
502+
else {
503+
val pre = tp.prefix
504+
def joinClass(tp: Type, cls: ClassSymbol) =
505+
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner))
506+
val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre)
507+
(lead /: hi.classSymbols)(joinClass)
508+
}
509+
case _ => tp
510+
}
501511
case tp: TypeVar =>
502512
apply(tp.underlying)
503513
case tp: AppliedType if !tp.tycon.typeSymbol.isClass =>
@@ -516,7 +526,7 @@ trait ImplicitRunInfo { self: Run =>
516526

517527
// todo: compute implicits directly, without going via companionRefs?
518528
def collectCompanions(tp: Type): TermRefSet = track("computeImplicitScope") {
519-
trace(i"collectCompanions($tp)", implicits) {
529+
trace(i"collectCompanions($tp)", implicitsDetailed) {
520530

521531
def iscopeRefs(t: Type): TermRefSet = implicitScopeCache.get(t) match {
522532
case Some(is) =>
@@ -575,8 +585,10 @@ trait ImplicitRunInfo { self: Run =>
575585
def computeIScope() = {
576586
val liftedTp = if (isLifted) tp else liftToClasses(tp)
577587
val refs =
578-
if (liftedTp ne tp)
588+
if (liftedTp ne tp) {
589+
implicitsDetailed.println(i"lifted of $tp = $liftedTp")
579590
iscope(liftedTp, isLifted = true).companionRefs
591+
}
580592
else
581593
collectCompanions(tp)
582594
val result = new OfTypeImplicits(tp, refs)(ctx)
@@ -673,7 +685,7 @@ trait Implicits { self: Typer =>
673685
}
674686

675687
/** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
676-
* `T` is deeply dealiassed to avoid references to local type aliases.
688+
* `T` is deeply dealiased to avoid references to local type aliases.
677689
*/
678690
lazy val synthesizedTypeTag: SpecialHandler =
679691
(formal, span) => implicit ctx => {

tests/pos/implicit-scope.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
object A {
2+
3+
object opaques {
4+
opaque type FlagSet = Long
5+
def FlagSet(bits: Long): FlagSet = bits.asInstanceOf // !!!
6+
def toBits(fs: FlagSet): Long = fs
7+
}
8+
val someFlag = FlagSet(1)
9+
type FlagSet = opaques.FlagSet
10+
def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits)
11+
12+
delegate FlagOps {
13+
def (xs: FlagSet) bits: Long = opaques.toBits(xs)
14+
}
15+
}
16+
17+
object B {
18+
type Variance = A.FlagSet
19+
20+
val f: A.FlagSet = A.someFlag
21+
f.bits // OK
22+
23+
val v: Variance = A.someFlag
24+
v.bits // OK, used to fail with: value bits is not a member of B.Variance
25+
}

0 commit comments

Comments
 (0)