Skip to content

Commit 18bc208

Browse files
authored
Merge pull request #548 from scala/backport-lts-3.3-23628
Backport "Generalize "Don't approximate a type using Nothing as prefix"" to 3.3 LTS
2 parents c7efa3a + d4c1a3b commit 18bc208

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,34 @@ class TypeApplications(val self: Type) extends AnyVal {
310310
def ensureLambdaSub(using Context): Type =
311311
if (isLambdaSub) self else EtaExpansion(self)
312312

313+
314+
/** Convert a type constructor `TC` which has type parameters `X1, ..., Xn`
315+
* to `[X1, ..., Xn] -> TC[X1, ..., Xn]`.
316+
*/
317+
def etaExpand(using Context): Type =
318+
val tparams = self.typeParams
319+
val resType = self.appliedTo(tparams.map(_.paramRef))
320+
self.dealias match
321+
case self: TypeRef if tparams.nonEmpty && self.symbol.isClass =>
322+
val owner = self.symbol.owner
323+
// Calling asSeenFrom on the type parameter infos is important
324+
// so that class type references within another prefix have
325+
// their type parameters' info fixed.
326+
// e.g. from pos/i18569:
327+
// trait M1:
328+
// trait A
329+
// trait F[T <: A]
330+
// object M2 extends M1
331+
// Type parameter T in M1.F has an upper bound of M1#A
332+
// But eta-expanding M2.F should have type parameters with an upper-bound of M2.A.
333+
// So we take the prefix M2.type and the F symbol's owner, M1,
334+
// to call asSeenFrom on T's info.
335+
HKTypeLambda(tparams.map(_.paramName))(
336+
tl => tparams.map(p => HKTypeLambda.toPInfo(tl.integrate(tparams, p.paramInfo.asSeenFrom(self.prefix, owner)))),
337+
tl => tl.integrate(tparams, resType))
338+
case _ =>
339+
HKTypeLambda.fromParams(tparams, resType)
340+
313341
/** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
314342
def EtaExpandIfHK(bound: Type)(using Context): Type = {
315343
val hkParams = bound.hkTypeParams

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6073,7 +6073,7 @@ object Types extends TypeUtils {
60736073
protected def range(lo: Type, hi: Type): Type =
60746074
if variance > 0 then hi
60756075
else if variance < 0 then
6076-
if (lo eq defn.NothingType) && hi.hasSimpleKind then
6076+
if (lo eq defn.NothingType) then
60776077
// Approximate by Nothing & hi instead of just Nothing, in case the
60786078
// approximated type is used as the prefix of another type (this would
60796079
// lead to a type with a `NoDenotation` denot and a possible
@@ -6084,8 +6084,14 @@ object Types extends TypeUtils {
60846084
// example if Nothing is the type of a parameter being depended on in
60856085
// a MethodType)
60866086
//
6087-
// Test case in tests/pos/i23530.scala
6088-
AndType(lo, hi)
6087+
// Test case in tests/pos/i23530.scala (and tests/pos/i23627.scala for
6088+
// the higher-kinded case which requires eta-expansion)
6089+
hi.etaExpand match
6090+
case expandedHi: HKTypeLambda =>
6091+
expandedHi.derivedLambdaType(resType = AndType(lo, expandedHi.resType))
6092+
case _ =>
6093+
// simple-kinded case
6094+
AndType(lo, hi)
60896095
else
60906096
lo
60916097
else if lo `eq` hi then lo

tests/pos/i23627.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait TestContainer:
2+
trait TestPath[T]:
3+
type AbsMember
4+
5+
extension (path: TestPath[?])
6+
infix def ext(color: path.AbsMember): Unit = ???
7+
infix def ext(other: Int): Unit = ???
8+
9+
object Repro:
10+
val dc2: TestContainer = ???
11+
import dc2.TestPath
12+
13+
def transition(path: TestPath[?])(using DummyImplicit): TestPath[?] = ???
14+
15+
def test: Unit =
16+
val di: TestPath[?] = ???
17+
// error
18+
val z1 = transition(di).ext(1)

0 commit comments

Comments
 (0)