Skip to content

Commit 26ecda5

Browse files
committed
Drop phase.isTyper use in isLegalPrefix/asf
Note that "asSeenFrom" (aka asf) is used by SymDenotation#findMember, which is used by TypeComparer's "hasMatchingMember", as a part of "compareRefinedSlow". Previously (using the minimisation in i17222.8.scala) `summonOne` is inlined during the "inlining" phase, while "summonInline" is inlined during typing. The result is that during inlining we fail to find `Reader[BC, Int]` because we incorrectly consider `A{type F = Int}` as stable.
1 parent d78516a commit 26ecda5

13 files changed

+240
-24
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
369369
}
370370
compareWild
371371
case tp2: LazyRef =>
372-
isBottom(tp1) || !tp2.evaluating && recur(tp1, tp2.ref)
372+
isBottom(tp1)
373+
|| !tp2.evaluating && recur(tp1, tp2.ref)
373374
case CapturingType(_, _) =>
374375
secondTry
375376
case tp2: AnnotatedType if !tp2.isRefining =>
@@ -489,7 +490,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
489490
// If `tp1` is in train of being evaluated, don't force it
490491
// because that would cause an assertionError. Return false instead.
491492
// See i859.scala for an example where we hit this case.
492-
tp2.isRef(AnyClass, skipRefined = false)
493+
tp2.isAny
493494
|| !tp1.evaluating && recur(tp1.ref, tp2)
494495
case AndType(tp11, tp12) =>
495496
if tp11.stripTypeVar eq tp12.stripTypeVar then recur(tp11, tp2)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ object TypeOps:
124124
}
125125

126126
def isLegalPrefix(pre: Type)(using Context): Boolean =
127-
pre.isStable || !ctx.phase.isTyper
127+
pre.isStable
128128

129129
/** Implementation of Types#simplified */
130130
def simplify(tp: Type, theMap: SimplifyMap | Null)(using Context): Type = {

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

+13-16
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,8 @@ object Types extends TypeUtils {
9999
// ----- Tests -----------------------------------------------------
100100

101101
// // debug only: a unique identifier for a type
102-
// val uniqId = {
103-
// nextId = nextId + 1
104-
// if (nextId == 19555)
105-
// println("foo")
106-
// nextId
107-
// }
102+
// val uniqId = { nextId = nextId + 1; nextId }
103+
// if uniqId == 19555 then trace.dumpStack()
108104

109105
/** A cache indicating whether the type was still provisional, last time we checked */
110106
@sharable private var mightBeProvisional = true
@@ -5577,24 +5573,25 @@ object Types extends TypeUtils {
55775573
}
55785574

55795575
def & (that: TypeBounds)(using Context): TypeBounds =
5576+
val lo1 = this.lo.stripLazyRef
5577+
val lo2 = that.lo.stripLazyRef
5578+
val hi1 = this.hi.stripLazyRef
5579+
val hi2 = that.hi.stripLazyRef
5580+
55805581
// This will try to preserve the FromJavaObjects type in upper bounds.
55815582
// For example, (? <: FromJavaObjects | Null) & (? <: Any),
55825583
// we want to get (? <: FromJavaObjects | Null) intead of (? <: Any),
55835584
// because we may check the result <:< (? <: Object | Null) later.
5584-
if this.hi.containsFromJavaObject
5585-
&& (this.hi frozen_<:< that.hi)
5586-
&& (that.lo frozen_<:< this.lo) then
5585+
if hi1.containsFromJavaObject && (hi1 frozen_<:< hi2) && (lo2 frozen_<:< lo1) then
55875586
// FromJavaObject in tp1.hi guarantees tp2.hi <:< tp1.hi
55885587
// prefer tp1 if FromJavaObject is in its hi
55895588
this
5590-
else if that.hi.containsFromJavaObject
5591-
&& (that.hi frozen_<:< this.hi)
5592-
&& (this.lo frozen_<:< that.lo) then
5589+
else if hi2.containsFromJavaObject && (hi2 frozen_<:< hi1) && (lo1 frozen_<:< lo2) then
55935590
// Similarly, prefer tp2 if FromJavaObject is in its hi
55945591
that
5595-
else if (this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi) then that
5596-
else if (that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi) then this
5597-
else TypeBounds(this.lo | that.lo, this.hi & that.hi)
5592+
else if (lo1 frozen_<:< lo2) && (hi2 frozen_<:< hi1) then that
5593+
else if (lo2 frozen_<:< lo1) && (hi1 frozen_<:< hi2) then this
5594+
else TypeBounds(lo1 | lo2, hi1 & hi2)
55985595

55995596
def | (that: TypeBounds)(using Context): TypeBounds =
56005597
if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) this
@@ -5603,7 +5600,7 @@ object Types extends TypeUtils {
56035600

56045601
override def & (that: Type)(using Context): Type = that match {
56055602
case that: TypeBounds => this & that
5606-
case _ => super.& (that)
5603+
case _ => super.&(that)
56075604
}
56085605

56095606
override def | (that: Type)(using Context): Type = that match {

compiler/src/dotty/tools/dotc/transform/Recheck.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,10 @@ abstract class Recheck extends Phase, SymTransformer:
217217
sharpen: Denotation => Denotation)(using Context): Type =
218218
if name.is(OuterSelectName) then tree.tpe
219219
else
220-
//val pre = ta.maybeSkolemizePrefix(qualType, name)
220+
val pre = ta.maybeSkolemizePrefix(qualType, name)
221221
val mbr =
222222
sharpen(
223-
qualType.findMember(name, qualType,
223+
qualType.findMember(name, pre,
224224
excluded = if tree.symbol.is(Private) then EmptyFlags else Private
225225
)).suchThat(tree.symbol == _)
226226
val newType = tree.tpe match

compiler/test/dotc/pos-test-pickling.blacklist

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ t5031_2.scala
2323
i16997.scala
2424
i7414.scala
2525
i17588.scala
26+
i8300.scala
2627
i9804.scala
2728
i13433.scala
2829
i16649-irrefutable.scala

tests/neg/6314-6.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
|object creation impossible, since def apply(fa: String): Int in trait XX in object Test3 is not defined
55
|(Note that
66
| parameter String in def apply(fa: String): Int in trait XX in object Test3 does not match
7-
| parameter Test3.Bar[X & Object with Test3.YY {...}#Foo] in def apply(fa: Test3.Bar[X & YY.this.Foo]): Test3.Bar[Y & YY.this.Foo] in trait YY in object Test3
7+
| parameter Test3.Bar[X & (X & Y)] in def apply(fa: Test3.Bar[X & YY.this.Foo]): Test3.Bar[Y & YY.this.Foo] in trait YY in object Test3
88
| )
99
-- Error: tests/neg/6314-6.scala:52:3 ----------------------------------------------------------------------------------
1010
52 | (new YY {}).boom // error: object creation impossible
1111
| ^
1212
|object creation impossible, since def apply(fa: String): Int in trait XX in object Test4 is not defined
1313
|(Note that
1414
| parameter String in def apply(fa: String): Int in trait XX in object Test4 does not match
15-
| parameter Test4.Bar[X & Object with Test4.YY {...}#FooAlias] in def apply(fa: Test4.Bar[X & YY.this.FooAlias]): Test4.Bar[Y & YY.this.FooAlias] in trait YY in object Test4
15+
| parameter Test4.Bar[X & (X & Y)] in def apply(fa: Test4.Bar[X & YY.this.FooAlias]): Test4.Bar[Y & YY.this.FooAlias] in trait YY in object Test4
1616
| )

tests/neg/i6225.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
object O1 {
1+
object O1 { // error: cannot be instantiated
22
type A[X] = X
33
opaque type T = A // error: opaque type alias must be fully applied
44
}

tests/pos/i17222.2.scala

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.compiletime.*
2+
3+
trait Reader[-In, Out]
4+
5+
trait A:
6+
type T
7+
type F[X]
8+
type Q = F[T]
9+
10+
object Reader:
11+
12+
given [X]: Reader[A { type Q = X }, X] with {}
13+
14+
object Test:
15+
16+
trait B[X] extends A:
17+
type T = X
18+
19+
trait C extends A:
20+
type F[X] = X
21+
22+
trait D[X] extends B[X] with C
23+
24+
val d = new D[Int] {}
25+
val bc = new B[Int] with C
26+
27+
summonAll[(Reader[d.type, Int], Reader[d.type, Int])] // works
28+
summonAll[(Reader[bc.type, Int], Reader[bc.type, Int])] // error
29+
summonInline[Reader[d.type, Int]] // works
30+
summonInline[Reader[bc.type, Int]] // works??

tests/pos/i17222.3.scala

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import scala.compiletime.*
2+
3+
trait Reader[-In, Out]
4+
5+
trait A:
6+
type T
7+
type F[X]
8+
type Q = F[T]
9+
10+
object Reader:
11+
12+
given [X]: Reader[A { type Q = X }, X] with {}
13+
14+
object Test:
15+
16+
trait B[X] extends A:
17+
type T = X
18+
19+
trait C extends A:
20+
type F[X] = X
21+
22+
trait D[X] extends B[X] with C
23+
24+
val d = new D[Int] {}
25+
val bc = new B[Int] with C
26+
27+
case class Box[T](value: T)
28+
29+
/** compiletime.summonAll, but with one case */
30+
inline def summonOne[T <: Box[?]]: T =
31+
val res =
32+
inline erasedValue[T] match
33+
case _: Box[t] => summonInline[t]
34+
end match
35+
Box(res).asInstanceOf[T]
36+
end summonOne
37+
38+
summonOne[Box[Reader[d.type, Int]]] // works
39+
summonOne[Box[Reader[bc.type, Int]]] // errors

tests/pos/i17222.4.scala

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import scala.compiletime.*
2+
3+
trait Reader[-In, Out]
4+
5+
trait A:
6+
type T
7+
type F[X]
8+
type Q = F[T]
9+
10+
given [X]: Reader[A { type Q = X }, X] with {}
11+
12+
case class Box[T](x: T)
13+
14+
/** compiletime.summonAll, but with one case */
15+
inline def summonOne[T]: T =
16+
val res =
17+
inline erasedValue[T] match
18+
case _: Box[t] => summonInline[t]
19+
end match
20+
Box(res).asInstanceOf[T]
21+
end summonOne
22+
23+
24+
@main def main =
25+
26+
27+
trait B[X] extends A:
28+
type T = X
29+
30+
trait C extends A:
31+
type F[X] = X
32+
33+
34+
val bc = new B[Int] with C
35+
36+
summonOne[Box[Reader[bc.type, Int]]] // errors
37+
38+
39+
val bc2: A { type Q = Int } = new B[Int] with C
40+
41+
summonOne[Box[Reader[bc2.type, Int]]] // works
42+
43+
44+
object BC extends B[Int] with C
45+
46+
summonOne[Box[Reader[BC.type, Int]]] // works
47+
48+
49+
val a = new A:
50+
type T = Int
51+
type F[X] = X
52+
53+
summonOne[Box[Reader[a.type, Int]]] // works
54+
55+
56+
val b = new B[Int]:
57+
type F[X] = X
58+
59+
summonOne[Box[Reader[b.type, Int]]] // works
60+
61+
62+
val ac = new A with C:
63+
type T = Int
64+
65+
summonOne[Box[Reader[ac.type, Int]]] // works
66+
67+
68+
trait D[X] extends B[X] with C
69+
val d = new D[Int] {}
70+
71+
summonOne[Box[Reader[d.type, Int]]] // works

tests/pos/i17222.5.scala

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import scala.compiletime.*
2+
3+
trait Reader[-In, Out]
4+
5+
trait A:
6+
type T
7+
type F[X]
8+
type Q = F[T]
9+
10+
given [X]: Reader[A { type Q = X }, X] with {}
11+
12+
case class Box[T](x: T)
13+
14+
inline def summonOne[T]: T =
15+
summonInline[T]
16+
end summonOne
17+
18+
@main def main =
19+
trait B[X] extends A:
20+
type T = X
21+
trait C extends A:
22+
type F[X] = X
23+
24+
val bc = new B[Int] with C
25+
summonInline[Reader[bc.type, Int]] // (I) Works
26+
summonOne[Reader[bc.type, Int]] // (II) Errors

tests/pos/i17222.8.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.compiletime.*
2+
3+
trait A:
4+
type F
5+
type Q = F
6+
7+
trait Reader[-In, Out]
8+
object Reader:
9+
given [X]: Reader[A { type Q = X }, X] with {}
10+
11+
class Test:
12+
//type BC = A { type F = Int } & A // ok
13+
type BC = A & A { type F = Int } // fail, also ok when manually de-aliased
14+
15+
inline def summonOne: Unit = summonInline[Reader[BC, Int]]
16+
17+
def t1(): Unit = summonInline[Reader[BC, Int]] // ok
18+
def t2(): Unit = summonOne // error

tests/pos/i17222.scala

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import scala.deriving.Mirror
2+
import scala.compiletime.*
3+
4+
trait Reader[-In, Out]
5+
6+
trait A:
7+
type T
8+
type F[X]
9+
type Q = F[T]
10+
11+
object Reader:
12+
13+
given [X]: Reader[A { type Q = X }, X] with {}
14+
15+
type Map2[Tup1 <: Tuple, Tup2 <: Tuple, F[_, _]] <: Tuple = (Tup1, Tup2) match
16+
case (h1 *: t1, h2 *: t2) => F[h1, h2] *: Map2[t1, t2, F]
17+
case (EmptyTuple, EmptyTuple) => EmptyTuple
18+
19+
inline given productReader[In <: Product, Out <: Product](using mi: Mirror.ProductOf[In])(using mo: Mirror.ProductOf[Out]): Reader[In, Out] =
20+
summonAll[Map2[mi.MirroredElemTypes, mo.MirroredElemTypes, Reader]]
21+
???
22+
23+
object Test:
24+
25+
trait B[X] extends A:
26+
type T = X
27+
28+
trait C extends A:
29+
type F[X] = X
30+
31+
val bc = new B[Int] with C
32+
33+
summon[Reader[(bc.type, bc.type), (Int, Int)]] // fails

0 commit comments

Comments
 (0)