Skip to content

Widen unions before finding members #12925

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 2 commits into from
Jun 25, 2021
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
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2049,7 +2049,10 @@ object SymDenotations {

override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation =
val raw = if excluded.is(Private) then nonPrivateMembersNamed(name) else membersNamed(name)
raw.filterWithFlags(required, excluded).asSeenFrom(pre).toDenot(pre)
val pre1 = pre match
case pre: OrType => pre.widenUnion
case _ => pre
raw.filterWithFlags(required, excluded).asSeenFrom(pre1).toDenot(pre1)

final def findMemberNoShadowingBasedOnFlags(name: Name, pre: Type,
required: FlagSet = EmptyFlags, excluded: FlagSet = EmptyFlags)(using Context): Denotation =
Expand Down
23 changes: 17 additions & 6 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1282,13 +1282,10 @@ object Types {
case tp =>
tp.widenUnionWithoutNull

/** Overridden in OrType */
def widenUnionWithoutNull(using Context): Type = widen match
case tp @ OrType(lhs, rhs) if tp.isSoft =>
TypeComparer.lub(lhs.widenUnionWithoutNull, rhs.widenUnionWithoutNull, canConstrain = true) match
case union: OrType => union.join
case res => res
case tp: AndOrType =>
tp.derivedAndOrType(tp.tp1.widenUnionWithoutNull, tp.tp2.widenUnionWithoutNull)
case tp: AndType =>
tp.derivedAndType(tp.tp1.widenUnionWithoutNull, tp.tp2.widenUnionWithoutNull)
case tp: RefinedType =>
tp.derivedRefinedType(tp.parent.widenUnion, tp.refinedName, tp.refinedInfo)
case tp: RecType =>
Expand Down Expand Up @@ -3198,6 +3195,20 @@ object Types {
myJoin
}

private var myUnion: Type = _
private var myUnionPeriod: Period = Nowhere

override def widenUnionWithoutNull(using Context): Type =
if myUnionPeriod != ctx.period then
myUnion =
if isSoft then
TypeComparer.lub(tp1.widenUnionWithoutNull, tp2.widenUnionWithoutNull, canConstrain = true) match
case union: OrType => union.join
case res => res
else derivedOrType(tp1.widenUnionWithoutNull, tp2.widenUnionWithoutNull)
if !isProvisional then myUnionPeriod = ctx.period
myUnion

private var atomsRunId: RunId = NoRunId
private var myAtoms: Atoms = _
private var myWidened: Type = _
Expand Down
42 changes: 42 additions & 0 deletions tests/pos/i12909.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package example

final case class Writer[W, A](run: (W, A)) {
def map[B](f: A => B): Writer[W, B] = ???

def flatMap[B](f: A => Writer[W, B]): Writer[W, B] = ???
}

object Main {
implicit class WriterOps[A](a: A) {
def set[W](w: W): Writer[W, A] = ???
}

def x1[A]: Writer[Vector[String], Option[A]] = ???

val failure = for {
a1 <- {
Option(1) match {
case Some(x) =>
x1[Boolean]
case _ =>
Option.empty[Boolean].set(Vector.empty[String])
}
}
a2 <- x1[String]
} yield ()

val success = for {
a1 <- {
val temp = Option(1) match {
case Some(x) =>
x1[Boolean]
case _ =>
Option.empty[Boolean].set(Vector.empty[String])
}
// why ???
temp
}
a2 <- x1[String]
} yield ()

}