Skip to content

Commit 053c8f9

Browse files
committed
A tweak to type improvement
When we replace Nothing by a fresh type variable, we should not accidentally instantiate that type variable to Any in case it is still undetermined. We achieve this by giving the type variable a slightly disguised version of Nothing which makes the compiler believe it has a lower bound. Fixes #21275
1 parent 4429d73 commit 053c8f9

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Inferencing.scala

+9-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,15 @@ object Inferencing {
180180
t match
181181
case t: TypeRef =>
182182
if t.symbol == defn.NothingClass then
183-
newTypeVar(TypeBounds.empty, nestingLevel = tvar.nestingLevel)
183+
val notExactlyNothing = LazyRef(_ => defn.NothingType)
184+
val bounds = TypeBounds(notExactlyNothing, defn.AnyType)
185+
// The new type variale has a slightly disguised lower bound Nothing.
186+
// This foils the `isExactlyNothing` test in `hasLowerBound` and
187+
// therefore makes the new type variable have a lower bound. That way,
188+
// we favor in `apply` below instantiating from below to `Nothing` instead
189+
// of from above to `Any`. That avoids a spurious flip of the roginal `Nothing`
190+
// instance to `Any`. See i21275 for a test case.
191+
newTypeVar(bounds, nestingLevel = tvar.nestingLevel)
184192
else if t.symbol.is(ModuleClass) then
185193
tryWidened(t.parents.filter(!_.isTransparent())
186194
.foldLeft(defn.AnyType: Type)(TypeComparer.andType(_, _)))

Diff for: tests/pos/i21725.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Box[+O]:
2+
def ++[O2 >: O](other: Box[O2]): Box[O2] = ???
3+
object Box:
4+
val empty: Box[Nothing] = ???
5+
6+
def test[T]: Box[T] =
7+
List(Box.empty, Box.empty)
8+
// .reduceOption[Box[T]](_ ++ _) // works
9+
.reduceOption(_ ++ _) // fails
10+
.getOrElse(Box.empty)

0 commit comments

Comments
 (0)