Skip to content

Commit da7d04c

Browse files
dwijnandtgodzik
authored andcommitted
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 64e2fae commit da7d04c

File tree

13 files changed

+254
-22
lines changed

13 files changed

+254
-22
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
346346
}
347347
compareWild
348348
case tp2: LazyRef =>
349-
isBottom(tp1) || !tp2.evaluating && recur(tp1, tp2.ref)
349+
isBottom(tp1)
350+
|| !tp2.evaluating && recur(tp1, tp2.ref)
350351
case CapturingType(_, _) =>
351352
secondTry
352353
case tp2: AnnotatedType if !tp2.isRefining =>
@@ -466,7 +467,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
466467
// If `tp1` is in train of being evaluated, don't force it
467468
// because that would cause an assertionError. Return false instead.
468469
// See i859.scala for an example where we hit this case.
469-
tp2.isRef(AnyClass, skipRefined = false)
470+
tp2.isAny
470471
|| !tp1.evaluating && recur(tp1.ref, tp2)
471472
case AndType(tp11, tp12) =>
472473
if (tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ object TypeOps:
123123
}
124124

125125
def isLegalPrefix(pre: Type)(using Context): Boolean =
126-
pre.isStable || !ctx.phase.isTyper
126+
pre.isStable
127127

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

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,8 @@ object Types extends TypeUtils {
9595
// ----- Tests -----------------------------------------------------
9696

9797
// // debug only: a unique identifier for a type
98-
// val uniqId = {
99-
// nextId = nextId + 1
100-
// if (nextId == 19555)
101-
// println("foo")
102-
// nextId
103-
// }
98+
// val uniqId = { nextId = nextId + 1; nextId }
99+
// if uniqId == 19555 then trace.dumpStack()
104100

105101
/** A cache indicating whether the type was still provisional, last time we checked */
106102
@sharable private var mightBeProvisional = true
@@ -5249,24 +5245,25 @@ object Types extends TypeUtils {
52495245
}
52505246

52515247
def & (that: TypeBounds)(using Context): TypeBounds =
5248+
val lo1 = this.lo.stripLazyRef
5249+
val lo2 = that.lo.stripLazyRef
5250+
val hi1 = this.hi.stripLazyRef
5251+
val hi2 = that.hi.stripLazyRef
5252+
52525253
// This will try to preserve the FromJavaObjects type in upper bounds.
52535254
// For example, (? <: FromJavaObjects | Null) & (? <: Any),
52545255
// we want to get (? <: FromJavaObjects | Null) intead of (? <: Any),
52555256
// because we may check the result <:< (? <: Object | Null) later.
5256-
if this.hi.containsFromJavaObject
5257-
&& (this.hi frozen_<:< that.hi)
5258-
&& (that.lo frozen_<:< this.lo) then
5257+
if hi1.containsFromJavaObject && (hi1 frozen_<:< hi2) && (lo2 frozen_<:< lo1) then
52595258
// FromJavaObject in tp1.hi guarantees tp2.hi <:< tp1.hi
52605259
// prefer tp1 if FromJavaObject is in its hi
52615260
this
5262-
else if that.hi.containsFromJavaObject
5263-
&& (that.hi frozen_<:< this.hi)
5264-
&& (this.lo frozen_<:< that.lo) then
5261+
else if hi2.containsFromJavaObject && (hi2 frozen_<:< hi1) && (lo1 frozen_<:< lo2) then
52655262
// Similarly, prefer tp2 if FromJavaObject is in its hi
52665263
that
5267-
else if (this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi) then that
5268-
else if (that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi) then this
5269-
else TypeBounds(this.lo | that.lo, this.hi & that.hi)
5264+
else if (lo1 frozen_<:< lo2) && (hi2 frozen_<:< hi1) then that
5265+
else if (lo2 frozen_<:< lo1) && (hi1 frozen_<:< hi2) then this
5266+
else TypeBounds(lo1 | lo2, hi1 & hi2)
52705267

52715268
def | (that: TypeBounds)(using Context): TypeBounds =
52725269
if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) this
@@ -5275,7 +5272,7 @@ object Types extends TypeUtils {
52755272

52765273
override def & (that: Type)(using Context): Type = that match {
52775274
case that: TypeBounds => this & that
5278-
case _ => super.& (that)
5275+
case _ => super.&(that)
52795276
}
52805277

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

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,10 @@ abstract class Recheck extends Phase, SymTransformer:
194194
sharpen: Denotation => Denotation)(using Context): Type =
195195
if name.is(OuterSelectName) then tree.tpe
196196
else
197-
//val pre = ta.maybeSkolemizePrefix(qualType, name)
197+
val pre = ta.maybeSkolemizePrefix(qualType, name)
198198
val mbr = normalizeByName(
199199
sharpen(
200-
qualType.findMember(name, qualType,
200+
qualType.findMember(name, pre,
201201
excluded = if tree.symbol.is(Private) then EmptyFlags else Private
202202
)).suchThat(tree.symbol == _))
203203
val newType = tree.tpe match

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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- Error: tests/neg/6314-6.scala:26:3 ----------------------------------------------------------------------------------
2+
26 | (new YY {}).boom // error: object creation impossible
3+
| ^
4+
|object creation impossible, since def apply(fa: String): Int in trait XX in object Test3 is not defined
5+
|(Note that
6+
| parameter String in def apply(fa: String): Int in trait XX in object Test3 does not match
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
8+
| )
9+
-- Error: tests/neg/6314-6.scala:52:3 ----------------------------------------------------------------------------------
10+
52 | (new YY {}).boom // error: object creation impossible
11+
| ^
12+
|object creation impossible, since def apply(fa: String): Int in trait XX in object Test4 is not defined
13+
|(Note that
14+
| parameter String in def apply(fa: String): Int in trait XX in object Test4 does not match
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
16+
| )

tests/neg/i6225.scala

Lines changed: 1 addition & 1 deletion
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

Lines changed: 30 additions & 0 deletions
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

Lines changed: 39 additions & 0 deletions
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

Lines changed: 71 additions & 0 deletions
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

0 commit comments

Comments
 (0)