diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 06765608430e..ee9ace2c7355 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -440,24 +440,29 @@ object Types { NoSymbol } - /** The least (wrt <:<) set of class symbols of which this type is a subtype + /** The least (wrt <:<) set of symbols satisfying the `include` predicate of which this type is a subtype */ - final def classSymbols(implicit ctx: Context): List[ClassSymbol] = this match { + final def parentSymbols(include: Symbol => Boolean)(implicit ctx: Context): List[Symbol] = this match { case tp: ClassInfo => tp.cls :: Nil case tp: TypeRef => val sym = tp.symbol - if (sym.isClass) sym.asClass :: Nil else tp.superType.classSymbols + if (include(sym)) sym :: Nil else tp.superType.parentSymbols(include) case tp: TypeProxy => - tp.underlying.classSymbols + tp.underlying.parentSymbols(include) case AndType(l, r) => - l.classSymbols | r.classSymbols + l.parentSymbols(include) | r.parentSymbols(include) case OrType(l, r) => - l.classSymbols intersect r.classSymbols // TODO does not conform to spec + l.parentSymbols(include) intersect r.parentSymbols(include) // TODO does not conform to spec case _ => Nil } + /** The least (wrt <:<) set of class symbols of which this type is a subtype + */ + final def classSymbols(implicit ctx: Context): List[ClassSymbol] = + parentSymbols(_.isClass).asInstanceOf + /** The term symbol associated with the type */ @tailrec final def termSymbol(implicit ctx: Context): Symbol = this match { case tp: TermRef => tp.symbol diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 310c93befda9..a2a529d9b05c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -232,6 +232,7 @@ object Implicits { */ class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) { assert(initctx.typer != null) + implicits.println(i"implicits of type $tp = ${companionRefs.toList}%, %") @threadUnsafe lazy val refs: List[ImplicitRef] = { val buf = new mutable.ListBuffer[TermRef] for (companion <- companionRefs) buf ++= companion.implicitMembers(ImplicitOrImpliedOrGiven) @@ -491,13 +492,19 @@ trait ImplicitRunInfo { self: Run => object liftToClasses extends TypeMap { override implicit protected val ctx: Context = liftingCtx override def stopAtStatic = true + def apply(tp: Type) = tp match { - case tp: TypeRef if !tp.symbol.isClass => - val pre = tp.prefix - def joinClass(tp: Type, cls: ClassSymbol) = - AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner)) - val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre) - (lead /: tp.classSymbols)(joinClass) + case tp: TypeRef => + val sym = tp.symbol + if (sym.isClass || sym.isOpaqueAlias) tp + else { + val pre = tp.prefix + def joinClass(tp: Type, cls: Symbol) = + AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner)) + val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre) + def isLiftTarget(sym: Symbol) = sym.isClass || sym.isOpaqueAlias + (lead /: tp.parentSymbols(isLiftTarget))(joinClass) + } case tp: TypeVar => apply(tp.underlying) case tp: AppliedType if !tp.tycon.typeSymbol.isClass => @@ -516,7 +523,7 @@ trait ImplicitRunInfo { self: Run => // todo: compute implicits directly, without going via companionRefs? def collectCompanions(tp: Type): TermRefSet = track("computeImplicitScope") { - trace(i"collectCompanions($tp)", implicits) { + trace(i"collectCompanions($tp)", implicitsDetailed) { def iscopeRefs(t: Type): TermRefSet = implicitScopeCache.get(t) match { case Some(is) => @@ -575,8 +582,10 @@ trait ImplicitRunInfo { self: Run => def computeIScope() = { val liftedTp = if (isLifted) tp else liftToClasses(tp) val refs = - if (liftedTp ne tp) + if (liftedTp ne tp) { + implicitsDetailed.println(i"lifted of $tp = $liftedTp") iscope(liftedTp, isLifted = true).companionRefs + } else collectCompanions(tp) val result = new OfTypeImplicits(tp, refs)(ctx) @@ -673,7 +682,7 @@ trait Implicits { self: Typer => } /** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`. - * `T` is deeply dealiassed to avoid references to local type aliases. + * `T` is deeply dealiased to avoid references to local type aliases. */ lazy val synthesizedTypeTag: SpecialHandler = (formal, span) => implicit ctx => { diff --git a/tests/pos/implicit-scope.scala b/tests/pos/implicit-scope.scala new file mode 100644 index 000000000000..62636b09adbc --- /dev/null +++ b/tests/pos/implicit-scope.scala @@ -0,0 +1,25 @@ +object A { + + object opaques { + opaque type FlagSet = Long + def FlagSet(bits: Long): FlagSet = bits.asInstanceOf // !!! + def toBits(fs: FlagSet): Long = fs + } + val someFlag = FlagSet(1) + type FlagSet = opaques.FlagSet + def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits) + + delegate FlagOps { + def (xs: FlagSet) bits: Long = opaques.toBits(xs) + } +} + +object B { + type Variance = A.FlagSet + + val f: A.FlagSet = A.someFlag + f.bits // OK + + val v: Variance = A.someFlag + v.bits // OK, used to fail with: value bits is not a member of B.Variance +} \ No newline at end of file