-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle TypeProxy of Named Tuples in unapply #22325
Changes from all commits
3d11e5e
5b31eda
be88246
f54f5d3
d42347f
83ae00d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,8 +127,17 @@ class TypeUtils: | |
case Some(types) => TypeOps.nestedPairs(types) | ||
case None => throw new AssertionError("not a tuple") | ||
|
||
def namedTupleElementTypesUpTo(bound: Int, normalize: Boolean = true)(using Context): List[(TermName, Type)] = | ||
def namedTupleElementTypesUpTo(bound: Int, derived: Boolean, normalize: Boolean = true)(using Context): List[(TermName, Type)] = | ||
(if normalize then self.normalized else self).dealias match | ||
// for desugaring and printer, ignore derived types to avoid infinite recursion in NamedTuple.unapply | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we avoid the duplication with the extractor? Maybe have two extractors |
||
case AppliedType(tycon, nmes :: vals :: Nil) if !derived && tycon.typeSymbol == defn.NamedTupleTypeRef.symbol => | ||
val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map: | ||
case ConstantType(Constant(str: String)) => str.toTermName | ||
case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.") | ||
val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil) | ||
names.zip(values) | ||
case t if !derived => Nil | ||
// default cause, used for post-typing | ||
case defn.NamedTuple(nmes, vals) => | ||
val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map: | ||
case ConstantType(Constant(str: String)) => str.toTermName | ||
|
@@ -138,22 +147,13 @@ class TypeUtils: | |
case t => | ||
Nil | ||
|
||
def namedTupleElementTypes(using Context): List[(TermName, Type)] = | ||
namedTupleElementTypesUpTo(Int.MaxValue) | ||
def namedTupleElementTypes(derived: Boolean)(using Context): List[(TermName, Type)] = | ||
namedTupleElementTypesUpTo(Int.MaxValue, derived) | ||
|
||
def isNamedTupleType(using Context): Boolean = self match | ||
case defn.NamedTuple(_, _) => true | ||
case _ => false | ||
|
||
def derivesFromNamedTuple(using Context): Boolean = self match | ||
case defn.NamedTuple(_, _) => true | ||
case tp: MatchType => | ||
tp.bound.derivesFromNamedTuple || tp.reduced.derivesFromNamedTuple | ||
case tp: TypeProxy => tp.superType.derivesFromNamedTuple | ||
case tp: AndType => tp.tp1.derivesFromNamedTuple || tp.tp2.derivesFromNamedTuple | ||
case tp: OrType => tp.tp1.derivesFromNamedTuple && tp.tp2.derivesFromNamedTuple | ||
case _ => false | ||
|
||
/** Drop all named elements in tuple type */ | ||
def stripNamedTuple(using Context): Type = self.normalized.dealias match | ||
case defn.NamedTuple(_, vals) => | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -110,7 +110,7 @@ object Applications { | |||||
} | ||||||
|
||||||
def namedTupleOrProductTypes(tp: Type)(using Context): List[Type] = | ||||||
if tp.isNamedTupleType then tp.namedTupleElementTypes.map(_(1)) | ||||||
if tp.isNamedTupleType then tp.namedTupleElementTypes(true).map(_(1)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And the same for the other boolean arguments. |
||||||
else productSelectorTypes(tp, NoSourcePosition) | ||||||
|
||||||
def productSelectorTypes(tp: Type, errorPos: SrcPos)(using Context): List[Type] = { | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
0 | ||
1 | ||
2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//> using options -experimental -language:experimental.namedTuples | ||
import language.experimental.namedTuples | ||
|
||
val directionsNT = IArray( | ||
(dx = 0, dy = 1), // up | ||
(dx = 1, dy = 0), // right | ||
(dx = 0, dy = -1), // down | ||
(dx = -1, dy = 0), // left | ||
) | ||
val IArray(UpNT @ _, _, _, _) = directionsNT | ||
|
||
object NT: | ||
aherlihy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def foo[T <: (x: Int, y: String)](tup: T): Int = | ||
tup.x | ||
|
||
def union[T](tup: (x: Int, y: String) | (x: Int, y: String)): Int = | ||
tup.x | ||
|
||
def intersect[T](tup: (x: Int, y: String) & T): Int = | ||
tup.x | ||
|
||
|
||
@main def Test = | ||
println(UpNT.dx) | ||
println(NT.union((1, "a"))) | ||
println(NT.intersect((2, "b"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a rule to always pass a booleans as named arguments.