Skip to content

Commit 0df5ae2

Browse files
authored
Generate kind-correct wildcards when selecting from a wildcard (#17025)
Co-authored-by: Dale Wijnand <dale.wijnand@gmail.com>
2 parents f445807 + e7e0df0 commit 0df5ae2

File tree

4 files changed

+85
-7
lines changed

4 files changed

+85
-7
lines changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,8 +1573,6 @@ object Types {
15731573
else NoType
15741574
case SkolemType(tp) =>
15751575
loop(tp)
1576-
case pre: WildcardType =>
1577-
WildcardType
15781576
case pre: TypeRef =>
15791577
pre.info match {
15801578
case TypeAlias(alias) => loop(alias)
@@ -2553,10 +2551,7 @@ object Types {
25532551
case _ => true
25542552
}
25552553

2556-
/** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type
2557-
* to an (unbounded) wildcard type.
2558-
*
2559-
* (2) Reduce a type-ref `T { X = U; ... } # X` to `U`
2554+
/** Reduce a type-ref `T { X = U; ... } # X` to `U`
25602555
* provided `U` does not refer with a RecThis to the
25612556
* refinement type `T { X = U; ... }`
25622557
*/
@@ -2678,7 +2673,7 @@ object Types {
26782673
case _ =>
26792674
}
26802675
}
2681-
if (prefix.isInstanceOf[WildcardType]) WildcardType
2676+
if (prefix.isInstanceOf[WildcardType]) WildcardType.sameKindAs(this)
26822677
else withPrefix(prefix)
26832678
}
26842679

@@ -5252,6 +5247,10 @@ object Types {
52525247
else
52535248
result
52545249
def emptyPolyKind(using Context): TypeBounds = apply(defn.NothingType, defn.AnyKindType)
5250+
/** An interval covering all types of the same kind as `tp`. */
5251+
def emptySameKindAs(tp: Type)(using Context): TypeBounds =
5252+
val top = tp.topType
5253+
if top.isExactlyAny then empty else apply(defn.NothingType, top)
52555254
def upper(hi: Type)(using Context): TypeBounds = apply(defn.NothingType, hi)
52565255
def lower(lo: Type)(using Context): TypeBounds = apply(lo, defn.AnyType)
52575256
}
@@ -5427,6 +5426,9 @@ object Types {
54275426
else
54285427
result
54295428
else unique(CachedWildcardType(bounds))
5429+
/** A wildcard matching any type of the same kind as `tp`. */
5430+
def sameKindAs(tp: Type)(using Context): WildcardType =
5431+
apply(TypeBounds.emptySameKindAs(tp))
54305432
}
54315433

54325434
/** An extractor for single abstract method types.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ i13871.scala
2020
i15181.scala
2121
i15922.scala
2222
t5031_2.scala
23+
i16997.scala
2324

2425
# Tree is huge and blows stack for printing Text
2526
i7034.scala

tests/pos/i16997.min.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Fn:
2+
class R[Y]
3+
4+
case class Foo[F[_]](nest: Foo[F]):
5+
case class Bar[G[_], R[_]](value: Foo[G])
6+
7+
def bar[G[_]](using fn: Fn): Bar[G, fn.R] = ???
8+
9+
def part[G[_]](using fn: Fn): Bar[G, fn.R] =
10+
(bar[G], ()) match
11+
case (Bar(value), ()) =>
12+
Bar(Foo(value))

tests/pos/i16997.scala

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class Funs {
2+
sealed trait ->[A, B]
3+
}
4+
5+
/**
6+
* Binary tree with leafs holding values of types `F[X]`, `F[Y]`, ...
7+
* The complete structure of the tree is expressed by the type `A`, using the tags for branches and leafs.
8+
*
9+
* @tparam <*> tag for branches
10+
* @tparam T tag for leafs.
11+
* @tparam F value type of leafs. Each leaf holds a value of type `F[T]`, for some type `T`.
12+
* @tparam A captures the complete structure of the tree
13+
*/
14+
enum Tree[<*>[_, _], T[_], F[_], A] {
15+
case Branch[<*>[_, _], T[_], F[_], A, B](
16+
l: Tree[<*>, T, F, A],
17+
r: Tree[<*>, T, F, B],
18+
) extends Tree[<*>, T, F, A <*> B]
19+
20+
case Leaf[<*>[_, _], T[_], F[_], A](
21+
value: F[A],
22+
) extends Tree[<*>, T, F, T[A]]
23+
24+
def <*>[B](that: Tree[<*>, T, F, B]): Tree[<*>, T, F, A <*> B] =
25+
Branch(this, that)
26+
27+
def partition[G[_], H[_]](
28+
f: [x] => F[x] => Either[G[x], H[x]],
29+
)(using
30+
funs: Funs,
31+
): Partitioned[G, H, funs.->] =
32+
this match {
33+
case Leaf(a) =>
34+
f(a) match
35+
case Left(a) => Partitioned.Left(Leaf(a))
36+
case Right(a) => Partitioned.Right(Leaf(a))
37+
case Branch(l, r) =>
38+
import Partitioned.{Both, Left, Right}
39+
import l.Partitioned.{Both => LBoth, Left => LLeft, Right => LRight}
40+
import r.Partitioned.{Both => RBoth, Left => RLeft, Right => RRight}
41+
42+
(l.partition(f), r.partition(f)) match
43+
case (LLeft(lg), RLeft(rg)) => Left(lg <*> rg)
44+
case (LLeft(lg), RRight(rh)) => Both(lg, rh)
45+
case (LLeft(lg), RBoth(rg, rh)) => Both(lg <*> rg, rh)
46+
case (LRight(lh), RLeft(rg)) => Both(rg, lh)
47+
case (LRight(lh), RRight(rh)) => Right(lh <*> rh)
48+
case (LRight(lh), RBoth(rg, rh)) => Both(rg, lh <*> rh)
49+
case (LBoth(lg, lh), RLeft(rg)) => Both(lg <*> rg, lh)
50+
case (LBoth(lg, lh), RRight(rh)) => Both(lg, lh <*> rh)
51+
case (LBoth(lg, lh), RBoth(rg, rh)) => Both(lg <*> rg, lh <*> rh)
52+
}
53+
54+
// note that `->` is never even used, to keep this reproduction case small
55+
enum Partitioned[G[_], H[_], ->[_, _]] {
56+
case Left(value: Tree[<*>, T, G, A])
57+
case Right(value: Tree[<*>, T, H, A])
58+
case Both[G[_], H[_], X, Y, ->[_, _]](
59+
l: Tree[<*>, T, G, X],
60+
r: Tree[<*>, T, H, Y],
61+
) extends Partitioned[G, H, ->]
62+
}
63+
}

0 commit comments

Comments
 (0)