Skip to content

Commit 3d5bf8d

Browse files
committed
Fix ambiguity problem
With the previous change a companion module could be entered twice, under `Foo.type` and `Foo.package.type`. This led to ambiguous implicits in squants.
1 parent be7d231 commit 3d5bf8d

File tree

1 file changed

+119
-30
lines changed

1 file changed

+119
-30
lines changed

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

Lines changed: 119 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -483,12 +483,47 @@ trait ImplicitRunInfo { self: Run =>
483483
val seen: mutable.Set[Type] = mutable.Set()
484484
val incomplete: mutable.Set[Type] = mutable.Set()
485485

486-
/** Replace every typeref that does not refer to a class by a conjunction of class types
486+
/** Is `sym` an anchor type for which givens may exist? Anchor types are classes,
487+
* opaque type aliases, and abstract types, but not type parameters
488+
*/
489+
def isAnchor(sym: Symbol) = sym.isClass && !sym.is(Package) || sym.isOpaqueAlias
490+
491+
def anchors(tp: Type): List[Type] = tp match {
492+
case tp: NamedType if isAnchor(tp.symbol) => tp :: Nil
493+
case tp: TypeProxy => anchors(tp.superType)
494+
case tp: AndOrType => anchors(tp.tp1) ++ anchors(tp.tp2)
495+
case _ => Nil
496+
}
497+
498+
/** Replace every typeref that does not refer to a class by a conjunction of anchor types
487499
* that has the same implicit scope as the original typeref. The motivation for applying
488500
* this map is that it reduces the total number of types for which we need to
489501
* compute and cache the implicit scope; all variations wrt type parameters or
490502
* abstract types are eliminated.
491503
*/
504+
object liftToAnchors extends TypeMap {
505+
override implicit protected val ctx: Context = liftingCtx
506+
override def stopAtStatic = true
507+
508+
def apply(tp: Type) = tp match {
509+
case tp: TypeRef =>
510+
((defn.AnyType: Type) /: anchors(tp))(AndType.make(_, _))
511+
case tp: TypeVar =>
512+
apply(tp.underlying)
513+
case tp: AppliedType if !tp.tycon.typeSymbol.isClass =>
514+
def applyArg(arg: Type) = arg match {
515+
case TypeBounds(lo, hi) => AndType.make(lo, hi)
516+
case WildcardType(TypeBounds(lo, hi)) => AndType.make(lo, hi)
517+
case _ => arg
518+
}
519+
(apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg)))
520+
case tp: TypeLambda =>
521+
apply(tp.resType)
522+
case _ =>
523+
mapOver(tp)
524+
}
525+
}
526+
492527
object liftToClasses extends TypeMap {
493528
override implicit protected val ctx: Context = liftingCtx
494529
override def stopAtStatic = true
@@ -521,7 +556,6 @@ trait ImplicitRunInfo { self: Run =>
521556
}
522557
}
523558

524-
// todo: compute implicits directly, without going via companionRefs?
525559
def collectCompanions(tp: Type): TermRefSet = track("computeImplicitScope") {
526560
trace(i"collectCompanions($tp)", implicitsDetailed) {
527561

@@ -540,47 +574,102 @@ trait ImplicitRunInfo { self: Run =>
540574
}
541575
}
542576

543-
val comps = new TermRefSet
544-
tp match {
545-
case tp: NamedType =>
546-
if (!tp.symbol.is(Package) || ctx.scala2Mode) {
547-
// Don't consider implicits in package prefixes unless under -language:Scala2
548-
val pre = tp.prefix
549-
comps ++= iscopeRefs(pre)
550-
def addRef(companion: TermRef): Unit = {
551-
val compSym = companion.symbol
552-
if (compSym is Package) {
553-
assert(ctx.scala2Mode)
554-
addRef(companion.select(nme.PACKAGE))
577+
def was = {
578+
val comps = new TermRefSet
579+
tp match {
580+
case tp: NamedType =>
581+
if (!tp.symbol.is(Package) || ctx.scala2Mode) {
582+
// Don't consider implicits in package prefixes unless under -language:Scala2
583+
val pre = tp.prefix
584+
comps ++= iscopeRefs(pre)
585+
def addRef(companion: TermRef): Unit = {
586+
val compSym = companion.symbol
587+
if (compSym is Package) {
588+
assert(ctx.scala2Mode)
589+
addRef(companion.select(nme.PACKAGE))
590+
}
591+
else if (compSym.exists)
592+
comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef]
593+
}
594+
def addCompanionOf(sym: Symbol) = {
595+
val companion = sym.companionModule
596+
if (companion.exists) addRef(companion.termRef)
597+
}
598+
def addClassScope(cls: ClassSymbol): Unit = {
599+
addCompanionOf(cls)
600+
for (parent <- cls.classParents; ref <- iscopeRefs(tp.baseType(parent.classSymbol)))
601+
addRef(ref)
602+
}
603+
tp.classSymbols(liftingCtx).foreach(addClassScope)
604+
}
605+
case _ =>
606+
for (part <- tp.namedPartsWith(_.isType)) comps ++= iscopeRefs(part)
607+
}
608+
comps
609+
}
610+
611+
def now = {
612+
val comps = new TermRefSet
613+
def addCompanion(pre: Type, companion: Symbol) =
614+
if (companion.exists && !companion.isAbsent) comps += TermRef(pre, companion)
615+
def addCompanionNamed(pre: Type, name: TermName) =
616+
addCompanion(pre, pre.member(name).suchThat(_.is(Module)).symbol)
617+
618+
def addPath(pre: Type): Unit = pre.dealias match {
619+
case pre: ThisType if pre.cls.is(Module) && pre.cls.isStaticOwner =>
620+
addPath(pre.cls.sourceModule.termRef)
621+
case pre: TermRef =>
622+
if (pre.symbol.is(Package)) {
623+
if (ctx.scala2Mode) {
624+
addCompanionNamed(pre, nme.PACKAGE)
625+
addPath(pre.prefix)
555626
}
556-
else if (compSym.exists)
557-
comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef]
558627
}
559-
def addCompanionOf(sym: Symbol) = {
560-
val companion = sym.companionModule
561-
if (companion.exists) addRef(companion.termRef)
628+
else {
629+
comps += pre
630+
addPath(pre.prefix)
562631
}
563-
def addClassScope(cls: ClassSymbol): Unit = {
564-
addCompanionOf(cls)
565-
for (parent <- cls.classParents; ref <- iscopeRefs(tp.baseType(parent.classSymbol)))
566-
addRef(ref)
632+
case _ =>
633+
}
634+
tp match {
635+
case tp: TermRef =>
636+
addPath(tp.prefix)
637+
case tp: TypeRef =>
638+
val sym = tp.symbol
639+
if (isAnchor(sym)) {
640+
val pre = tp.prefix
641+
addPath(pre)
642+
if (sym.is(Module)) addCompanion(pre, sym.sourceModule)
643+
else if (sym.isClass) addCompanion(pre, sym.companionModule)
644+
else addCompanionNamed(pre, sym.name.stripModuleClassSuffix.toTermName)
567645
}
568-
tp.classSymbols(liftingCtx).foreach(addClassScope)
569-
}
570-
case _ =>
571-
for (part <- tp.namedPartsWith(_.isType)) comps ++= iscopeRefs(part)
646+
val superAnchors = if (sym.isClass) tp.parents else anchors(tp.superType)
647+
for (anchor <- superAnchors) comps ++= iscopeRefs(anchor)
648+
case _ =>
649+
for (part <- tp.namedPartsWith(_.isType)) comps ++= iscopeRefs(part)
650+
}
651+
comps
572652
}
573-
comps
653+
/*
654+
val wasSet = was.toList.toSet
655+
val nowSet = now.toList.toSet
656+
if (wasSet != nowSet)
657+
println(i"""Diff for $tp
658+
|all: ${(wasSet ++ nowSet).toList}%, %
659+
|was: ${(wasSet -- nowSet).toList}%, %
660+
|now: ${(nowSet -- wasSet).toList}%, %""")
661+
*/
662+
now
574663
}
575664
}
576665

577666
/** The implicit scope of type `tp`
578-
* @param isLifted Type `tp` is the result of a `liftToClasses` application
667+
* @param isLifted Type `tp` is the result of a `liftToAnchors` application
579668
*/
580669
def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits = {
581670
val canCache = Config.cacheImplicitScopes && tp.hash != NotCached && !tp.isProvisional
582671
def computeIScope() = {
583-
val liftedTp = if (isLifted) tp else liftToClasses(tp)
672+
val liftedTp = if (isLifted) tp else liftToAnchors(tp)
584673
val refs =
585674
if (liftedTp ne tp) {
586675
implicitsDetailed.println(i"lifted of $tp = $liftedTp")

0 commit comments

Comments
 (0)