Skip to content

Commit d4968e7

Browse files
committed
Fix .toTuple insertion
It previously did not follow aliases or upper bounds when deciding whether something was a named tuple.
1 parent b989790 commit d4968e7

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ class TypeUtils:
145145
case defn.NamedTuple(_, _) => true
146146
case _ => false
147147

148+
def derivesFromNamedTuple(using Context): Boolean = self match
149+
case defn.NamedTuple(_, _) => true
150+
case tp: MatchType =>
151+
tp.bound.derivesFromNamedTuple || tp.reduced.derivesFromNamedTuple
152+
case tp: TypeProxy => tp.superType.derivesFromNamedTuple
153+
case tp: AndType => tp.tp1.derivesFromNamedTuple || tp.tp2.derivesFromNamedTuple
154+
case tp: OrType => tp.tp1.derivesFromNamedTuple && tp.tp2.derivesFromNamedTuple
155+
case _ => false
156+
148157
/** Drop all named elements in tuple type */
149158
def stripNamedTuple(using Context): Type = self.normalized.dealias match
150159
case defn.NamedTuple(_, vals) =>

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4641,7 +4641,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
46414641
case _: SelectionProto =>
46424642
tree // adaptations for selections are handled in typedSelect
46434643
case _ if ctx.mode.is(Mode.ImplicitsEnabled) && tree.tpe.isValueType =>
4644-
if tree.tpe.widen.isNamedTupleType && pt.derivesFrom(defn.TupleClass) then
4644+
if tree.tpe.derivesFromNamedTuple && pt.derivesFrom(defn.TupleClass) then
46454645
readapt(typed(untpd.Select(untpd.TypedSplice(tree), nme.toTuple)))
46464646
else if pt.isRef(defn.AnyValClass, skipRefined = false)
46474647
|| pt.isRef(defn.ObjectClass, skipRefined = false)

tests/pos/named-tuple-downcast.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
type Person = (name: String, age: Int)
2+
3+
val Bob: Person = (name = "Bob", age = 33)
4+
5+
type SI = (String, Int)
6+
7+
def id[X](x: X): X = x
8+
val x: (String, Int) = Bob
9+
val y: SI = id(Bob)
10+
val and: Person & String = ???
11+
val _: SI = and
12+
val or: Person | (name: "Bob", age: 33) = ???
13+
val _: SI = or
14+
15+
class C[P <: Person](p: P):
16+
val x: (String, Int) = p
17+
18+
19+
20+

0 commit comments

Comments
 (0)