Skip to content

Commit 7be0dd9

Browse files
committed
Better infos for dependent class parameter references
We sometimes create a dependent parameter reference p.X where `p` is a path with a type that has a wildcard argument, e.g. `P[X >: L <: H].` So far the denotation of `p.X` had as info the bounds with which `X` was declared in `P`. Now it gets the actual parameter bounds instead. Fixes #15652 #15652 started failing when tuple unpackings started to use `val`s instead of `def`s in #14816. That caused dependent class parameter references to be created and uncovered the problem.
1 parent 79d9a6f commit 7be0dd9

File tree

4 files changed

+25
-8
lines changed

4 files changed

+25
-8
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ object Denotations {
11181118
if !owner.membersNeedAsSeenFrom(pre) && (!ownerIsPrefix || hasOriginalInfo)
11191119
|| symbol.is(NonMember)
11201120
then this
1121+
else if symbol.isAllOf(ClassTypeParam) then
1122+
val arg = symbol.typeRef.argForParam(pre, widenAbstract = true)
1123+
if arg.exists then derivedSingleDenotation(symbol, arg.bounds, pre)
1124+
else derived(symbol.info)
11211125
else derived(symbol.info)
11221126
}
11231127
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,7 @@ object TypeOps:
432432
override def apply(tp: Type): Type =
433433
try
434434
tp match
435-
case tp: TermRef
436-
if toAvoid(tp) =>
435+
case tp: TermRef if toAvoid(tp) =>
437436
tp.info.widenExpr.dealias match {
438437
case info: SingletonType => apply(info)
439438
case info => range(defn.NothingType, apply(info))

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,10 +2459,12 @@ object Types {
24592459
ctx.base.underlyingRecursions -= 1
24602460

24612461
/** The argument corresponding to class type parameter `tparam` as seen from
2462-
* prefix `pre`. Can produce a TypeBounds type in case prefix is an & or | type
2463-
* and parameter is non-variant.
2462+
* prefix `pre`. Can produce a TypeBounds type if `widenAbstract` is true,
2463+
* or prefix is an & or | type and parameter is non-variant.
2464+
* Otherwise, a typebounds argument is dropped and the original type parameter
2465+
* reference is returned.
24642466
*/
2465-
def argForParam(pre: Type)(using Context): Type = {
2467+
def argForParam(pre: Type, widenAbstract: Boolean = false)(using Context): Type = {
24662468
val tparam = symbol
24672469
val cls = tparam.owner
24682470
val base = pre.baseType(cls)
@@ -2474,7 +2476,7 @@ object Types {
24742476
while (tparams.nonEmpty && args.nonEmpty) {
24752477
if (tparams.head.eq(tparam))
24762478
return args.head match {
2477-
case _: TypeBounds => TypeRef(pre, tparam)
2479+
case _: TypeBounds if !widenAbstract => TypeRef(pre, tparam)
24782480
case arg => arg
24792481
}
24802482
tparams = tparams.tail
@@ -5581,10 +5583,10 @@ object Types {
55815583
// if H#T = U, then for any x in L..H, x.T =:= U,
55825584
// hence we can replace with U under all variances
55835585
reapply(alias.rewrapAnnots(tp1))
5584-
case tp: TypeBounds =>
5586+
case bounds: TypeBounds =>
55855587
// If H#T = ? >: S <: U, then for any x in L..H, S <: x.T <: U,
55865588
// hence we can replace with S..U under all variances
5587-
expandBounds(tp)
5589+
expandBounds(bounds)
55885590
case info: SingletonType =>
55895591
// if H#x: y.type, then for any x in L..H, x.type =:= y.type,
55905592
// hence we can replace with y.type under all variances

tests/pos/i15652.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait Node
2+
type NodeParser[T] = Node => T
3+
4+
def child(key: String): Option[Node] = ???
5+
6+
def optionalOneOf[T](in: Map[String, NodeParser[? <: T]]): Option[T] =
7+
val mappings = in flatMap { (key, parser) =>
8+
child(key) map { node =>
9+
key -> (() => parser(node))
10+
}
11+
}
12+
mappings.headOption map (_._2())

0 commit comments

Comments
 (0)