Skip to content
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

Add IsNamedTuple compiletime op #22431

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

bishabosha
Copy link
Member

@bishabosha bishabosha commented Jan 22, 2025

This reuses the NamedTuple type extractor underneath, and is careful not to reduce when the scrutinee of a match type.

The use case is to be able to define a recursive algorithm such as "does this named tuple type have a substructure equivalent to this other named tuple type?"

e.g. the status quo in #22422 is that Int can not be compared to case NamedTuple[ns,vs] and (x: Int, y: Int) can not be compared to case Int. With this compile time op you can have branching logic.

I should probably add an example of the recursive algorithm as a test. - but initial testing in the repl is good result:

scala> type IsNamedTupleForward[X] = NamedTuple.IsNamedTuple[X] match
     |   case true => true
     |   case false => false
     | 
                                                                                                              
scala> summon[IsNamedTupleForward[(x: Int, y: Int)] =:= true]
val res6: true =:= true = generalized constraint

scala> summon[IsNamedTupleForward[Int] =:= false]
val res8: false =:= false = generalized constraint

scala> case class Person(name: String, age: Int)
// defined case class Person

scala> summon[IsNamedTupleForward[Person] =:= false]
val res7: false =:= false = generalized constraint

also for bonus the OptFrom:

scala> type FieldNames[X] <: Tuple = NamedTuple.OptFrom[X] match
     |   case Some[nt] => NamedTuple.Names[nt]
     |   case _ => EmptyTuple
     | 

scala> summon[FieldNames[(x: Int, y: Int)] =:= ("x", "y")]
val res3: ("x", "y") =:= ("x", "y") = generalized constraint

scala> summon[FieldNames[Person] =:= ("name", "age")]
val res4: ("name", "age") =:= ("name", "age") = generalized constraint

scala> summon[FieldNames[Int] =:= EmptyTuple]
val res5: EmptyTuple.type =:= EmptyTuple.type = generalized constraint

fixes #22422

@@ -1384,7 +1385,7 @@ class CheckCaptures extends Recheck, SymTransformer:
if boxErrors != null then boxErrors += msg
if ctx.settings.YccDebug.value then
println(i"cannot box/unbox $actual vs $expected")
return actual
boundary.break(actual)
Copy link
Member Author

@bishabosha bishabosha Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you enable tracing then this return starts to warn, due to the surrounding trace call, so this is here

@bishabosha
Copy link
Member Author

if this were rejected - i believe that the use case of a substructural check could be relegated to an implicit evidence generated via macro (provided the macro api has suitable api for manipulating named tuple types)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No way to differentiate NamedTuple from other types
1 participant