Skip to content

Commit 84a0848

Browse files
Merge pull request #13384 from dotty-staging/add-isTupleType
Add TypeRepr.isTupleN to reflection API
2 parents 216b76c + 7829e30 commit 84a0848

File tree

14 files changed

+70
-18
lines changed

14 files changed

+70
-18
lines changed

compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ object CheckTrees {
217217
optionArg.argTypesHi match {
218218
case Nil =>
219219
optionArg :: Nil
220-
case tupleArgs if defn.isTupleType(optionArg) =>
220+
case tupleArgs if defn.isTupleNType(optionArg) =>
221221
tupleArgs
222222
}
223223
case _ =>

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,11 @@ class Definitions {
14621462
def isPolymorphicAfterErasure(sym: Symbol): Boolean =
14631463
(sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) || (sym eq Object_synchronized)
14641464

1465-
def isTupleType(tp: Type)(using Context): Boolean = {
1465+
/** Is this type a `TupleN` type?
1466+
*
1467+
* @return true if the dealiased type of `tp` is `TupleN[T1, T2, ..., Tn]`
1468+
*/
1469+
def isTupleNType(tp: Type)(using Context): Boolean = {
14661470
val arity = tp.dealias.argInfos.length
14671471
arity <= MaxTupleArity && TupleType(arity) != null && tp.isRef(TupleType(arity).symbol)
14681472
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
11801180
compareLower(info2, tyconIsTypeRef = true)
11811181
case info2: ClassInfo =>
11821182
tycon2.name.startsWith("Tuple") &&
1183-
defn.isTupleType(tp2) && recur(tp1, tp2.toNestedPairs) ||
1183+
defn.isTupleNType(tp2) && recur(tp1, tp2.toNestedPairs) ||
11841184
tryBaseType(info2.cls)
11851185
case _ =>
11861186
fourthTry
@@ -2620,9 +2620,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
26202620
fullyInstantiated(tp2) && !tp1.classSymbols.exists(_.derivesFrom(tp2.symbol))
26212621
case (tp1: TypeRef, tp2: TermRef) if isEnumValue(tp2) =>
26222622
fullyInstantiated(tp1) && !tp2.classSymbols.exists(_.derivesFrom(tp1.symbol))
2623-
case (tp1: Type, tp2: Type) if defn.isTupleType(tp1) =>
2623+
case (tp1: Type, tp2: Type) if defn.isTupleNType(tp1) =>
26242624
provablyDisjoint(tp1.toNestedPairs, tp2)
2625-
case (tp1: Type, tp2: Type) if defn.isTupleType(tp2) =>
2625+
case (tp1: Type, tp2: Type) if defn.isTupleNType(tp2) =>
26262626
provablyDisjoint(tp1, tp2.toNestedPairs)
26272627
case (tp1: TypeProxy, tp2: TypeProxy) =>
26282628
provablyDisjoint(tp1.superType, tp2) || provablyDisjoint(tp1, tp2.superType)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
147147
changePrec(GlobalPrec) {
148148
val argStr: Text =
149149
if args.length == 2
150-
&& !defn.isTupleType(args.head)
150+
&& !defn.isTupleNType(args.head)
151151
&& !isGiven && !isErased
152152
then
153153
atPrec(InfixPrec) { argText(args.head) }

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
768768

769769
val sym = tp.classSymbol
770770

771-
if (ctx.definitions.isTupleType(tp))
771+
if (ctx.definitions.isTupleNType(tp))
772772
params(tp).map(_ => "_").mkString("(", ", ", ")")
773773
else if (scalaListType.isRef(sym))
774774
if (flattenList) "_*" else "_: List"
@@ -782,7 +782,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
782782
else if (decomposed) "_: " + showType(tp, showTypeArgs = true)
783783
else "_"
784784
case Prod(tp, fun, params) =>
785-
if (ctx.definitions.isTupleType(tp))
785+
if (ctx.definitions.isTupleNType(tp))
786786
"(" + params.map(doShow(_)).mkString(", ") + ")"
787787
else if (tp.isRef(scalaConsType.symbol))
788788
if (flattenList) params.map(doShow(_, flattenList)).filter(_.nonEmpty).mkString(", ")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,7 @@ trait Applications extends Compatibility {
13631363
for (argType <- argTypes) assert(!isBounds(argType), unapplyApp.tpe.show)
13641364
val bunchedArgs = argTypes match {
13651365
case argType :: Nil =>
1366-
if (args.lengthCompare(1) > 0 && Feature.autoTuplingEnabled && defn.isTupleType(argType)) untpd.Tuple(args) :: Nil
1366+
if (args.lengthCompare(1) > 0 && Feature.autoTuplingEnabled && defn.isTupleNType(argType)) untpd.Tuple(args) :: Nil
13671367
else args
13681368
case _ => args
13691369
}

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
17381738
val tpNoRefinement = self.dropDependentRefinement
17391739
tpNoRefinement != self
17401740
&& dotc.core.Symbols.defn.isNonRefinedFunction(tpNoRefinement)
1741+
def isTupleN: Boolean =
1742+
dotc.core.Symbols.defn.isTupleNType(self)
17411743
def select(sym: Symbol): TypeRepr = self.select(sym)
17421744
def appliedTo(targ: TypeRepr): TypeRepr =
17431745
dotc.core.Types.decorateTypeApplications(self).appliedTo(targ)

library/src/scala/quoted/Quotes.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,6 +2526,12 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
25262526
*/
25272527
def isDependentFunctionType: Boolean
25282528

2529+
/** Is this type a `TupleN` type?
2530+
*
2531+
* @return true if the dealiased type of `self` is `TupleN[T1, T2, ..., Tn]`
2532+
*/
2533+
def isTupleN: Boolean
2534+
25292535
/** The type <this . sym>, reduced if possible */
25302536
def select(sym: Symbol): TypeRepr
25312537

project/MiMaFilters.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ object MiMaFilters {
1818
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTestTypeTest"),
1919
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTest"),
2020
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTestMethods"),
21+
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.isTupleN"),
2122
)
2223
}

scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ trait InkuireSupport:
150150
params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)),
151151
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
152152
)
153-
else if t.isTupleType then
153+
else if t.isTupleN then
154154
val name = s"Tuple${typeList.size}"
155155
Inkuire.Type(
156156
name = Inkuire.TypeName(name),

scaladoc/src/dotty/tools/scaladoc/tasty/SyntheticSupport.scala

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,9 @@ import scala.quoted._
66
object SyntheticsSupport:
77

88
extension (using Quotes)(t: reflect.TypeRepr)
9-
def isTupleType: Boolean = t.hackIsTupleType(t)
109

1110
def isCompiletimeAppliedType: Boolean = t.hackIsCompiletimeAppliedType(t)
1211

13-
private def hackIsTupleType(rtpe: reflect.TypeRepr): Boolean =
14-
import dotty.tools.dotc
15-
given ctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
16-
val tpe = rtpe.asInstanceOf[dotc.core.Types.Type]
17-
ctx.definitions.isTupleType(tpe)
18-
1912
private def hackIsCompiletimeAppliedType(rtpe: reflect.TypeRepr): Boolean =
2013
import dotty.tools.dotc
2114
given ctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx

scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ trait TypesSupport:
187187
partOfSignature ++ texts(" => ") ++ inner(rtpe)
188188
case args =>
189189
texts("(") ++ commas(args.init.map(inner)) ++ texts(") => ") ++ inner(args.last)
190-
else if t.isTupleType then
190+
else if t.isTupleN then
191191
typeList match
192192
case Nil =>
193193
Nil
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted.*
2+
3+
inline def isTupleN[T]: Boolean = ${ isTupleNImpl[T] }
4+
5+
private def isTupleNImpl[T: Type](using Quotes): Expr[Boolean] = {
6+
import quotes.reflect.*
7+
Expr(TypeRepr.of[T].isTupleN)
8+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@main def Test = {
2+
assert(isTupleN[Tuple1[Int]])
3+
assert(isTupleN[(Int, Int)])
4+
assert(isTupleN[(Int, Int, Int)])
5+
assert(isTupleN[(Int, Int, Int, Int)])
6+
assert(isTupleN[(Int, Int, Int, Int, Int)])
7+
assert(isTupleN[(Int, Int, Int, Int, Int, Int)])
8+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int)])
9+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int)])
10+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int)])
11+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
12+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
13+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
14+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
15+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
16+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
17+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
18+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
19+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
20+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
21+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
22+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
23+
assert(isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)])
24+
25+
type Tup = (Int, Int)
26+
assert(isTupleN[Tup])
27+
28+
assert(!isTupleN[(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)]) // No tuple 23
29+
assert(!isTupleN[Tuple])
30+
assert(!isTupleN[EmptyTuple])
31+
assert(!isTupleN[NonEmptyTuple])
32+
assert(!isTupleN[Int *: Tuple])
33+
34+
assert(!isTupleN[Any])
35+
assert(!isTupleN[Int])
36+
assert(!isTupleN[Object])
37+
assert(!isTupleN[Nothing])
38+
}

0 commit comments

Comments
 (0)