Skip to content

The atom of a module class is its module val #10106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 38 additions & 28 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1217,34 +1217,44 @@ object Types {
/** The singleton types that must or may be in this type. @see Atoms.
* Overridden and cached in OrType.
*/
def atoms(using Context): Atoms = dealias match
case tp: SingletonType =>
def normalize(tp: Type): Type = tp match
case tp: SingletonType =>
tp.underlying.dealias match
case tp1: SingletonType => normalize(tp1)
case _ =>
tp match
case tp: TermRef => tp.derivedSelect(normalize(tp.prefix))
case _ => tp
case _ => tp
tp.underlying.atoms match
case as @ Atoms.Range(lo, hi) =>
if hi.size == 1 then as // if there's just one atom, there's no uncertainty which one it is
else Atoms.Range(Set.empty, hi)
case Atoms.Unknown =>
if tp.isStable then
val single = Set.empty + normalize(tp)
Atoms.Range(single, single)
else Atoms.Unknown
case tp: ExprType => tp.resType.atoms
case tp: OrType => tp.atoms // `atoms` overridden in OrType
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
case tp: TypeProxy =>
tp.underlying.atoms match
case Atoms.Range(_, hi) => Atoms.Range(Set.empty, hi)
case Atoms.Unknown => Atoms.Unknown
case _ => Atoms.Unknown
def atoms(using Context): Atoms =
def normalize(tp: Type): Type = tp match
case tp: SingletonType =>
tp.underlying.dealias match
case tp1: SingletonType => normalize(tp1)
case _ =>
tp match
case tp: TermRef => tp.derivedSelect(normalize(tp.prefix))
case _ => tp
case _ => tp

def single(tp: Type): Atoms =
if tp.isStable then
val set = Set.empty + normalize(tp)
Atoms.Range(set, set)
else Atoms.Unknown

dealias match
case tp: SingletonType =>
tp.underlying.atoms match
case as @ Atoms.Range(lo, hi) =>
if hi.size == 1 then as // if there's just one atom, there's no uncertainty which one it is
else Atoms.Range(Set.empty, hi)
case Atoms.Unknown =>
single(tp)
case tp: ExprType => tp.resType.atoms
case tp: OrType => tp.atoms // `atoms` overridden in OrType
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
case tp: TypeRef if tp.symbol.is(ModuleClass) =>
// The atom of a module class is the module itself,
// this corresponds to the special case in TypeComparer
// which ensures that `X$ <:< X.type` returns true.
single(tp.symbol.companionModule.termRef.asSeenFrom(tp.prefix, tp.symbol.owner))
case tp: TypeProxy =>
tp.underlying.atoms match
case Atoms.Range(_, hi) => Atoms.Range(Set.empty, hi)
case Atoms.Unknown => Atoms.Unknown
case _ => Atoms.Unknown

private def dealias1(keep: AnnotatedType => Context ?=> Boolean)(using Context): Type = this match {
case tp: TypeRef =>
Expand Down
1 change: 0 additions & 1 deletion tests/patmat/outer-ref-checks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class Outer {

def belongsOtherOuter(a: Outer#Inner): Unit = a match {
case Inner(s) => // unchecked warning
case O.Inner(s) => // unchecked warning
case _ =>
}
}
Expand Down
19 changes: 19 additions & 0 deletions tests/pos/object-union-inf.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class A
object ObjA extends A
class B
object ObjB extends B

object Test {
def foo[T <: A | B](t: T): List[T] = List(t)
val x: ObjA.type | ObjB.type = ObjA

// infers `T = ObjA$ | ObjB$` instead of `ObjA.type | ObjB.type` due to the
// use of `widenSingleton` in TypeComparer#secondTry when the lhs is a union
// type.
val y = foo(ObjA : ObjA.type | ObjB.type)

// This only compiles if `ObjA$ <:< ObjA.type`, there is a special-case in
// `firstTry` for that but we also need a special case in `atoms` since unions
// are involved.
val z: List[ObjA.type | ObjB.type] = y
}