Skip to content

Commit e7e0df0

Browse files
smarterdwijnand
andcommitted
Generate kind-correct wildcards when selecting from a wildcard
Previously, derivedSelect would incorrectly approximate `fn.R` by `? >: Nothing <: Any` in `i16997.min.scala`, which subsequently lead to a kind-incorrect type application `Any[Y]` that broke type inference. #16999 proposed to fix this by changing type inference, but it seems like we don't need to do that if we make sure our wildcards are always kind-correct. Note that the wildcard logic in lookupRefined could be removed: it seems like it was supposed to be used by `reduceProjection` according to its documentation, but the constructor of `NamedType` disallows wildcards as prefixes so it didn't actually do anything there. Co-Authored-By: Dale Wijnand <dale.wijnand@gmail.com>
1 parent 57b172e commit e7e0df0

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
@@ -1574,8 +1574,6 @@ object Types {
15741574
else NoType
15751575
case SkolemType(tp) =>
15761576
loop(tp)
1577-
case pre: WildcardType =>
1578-
WildcardType
15791577
case pre: TypeRef =>
15801578
pre.info match {
15811579
case TypeAlias(alias) => loop(alias)
@@ -2554,10 +2552,7 @@ object Types {
25542552
case _ => true
25552553
}
25562554

2557-
/** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type
2558-
* to an (unbounded) wildcard type.
2559-
*
2560-
* (2) Reduce a type-ref `T { X = U; ... } # X` to `U`
2555+
/** Reduce a type-ref `T { X = U; ... } # X` to `U`
25612556
* provided `U` does not refer with a RecThis to the
25622557
* refinement type `T { X = U; ... }`
25632558
*/
@@ -2679,7 +2674,7 @@ object Types {
26792674
case _ =>
26802675
}
26812676
}
2682-
if (prefix.isInstanceOf[WildcardType]) WildcardType
2677+
if (prefix.isInstanceOf[WildcardType]) WildcardType.sameKindAs(this)
26832678
else withPrefix(prefix)
26842679
}
26852680

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

54335435
/** 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)