-
Notifications
You must be signed in to change notification settings - Fork 1.1k
A simple way to check exhaustivity of GADTs #3510
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
Conversation
val typeParamMap = new TypeMap() { | ||
override def apply(tp: Type): Type = tp match { | ||
case tref: TypeRef if tref.symbol.is(TypeParam) => | ||
if (tvarMap.contains(tref.symbol)) tvarMap(tref.symbol) |
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.
This block looks like a tvarMap.getOrElseUpdate(tref.symbol, newTypeVar(tref.underlying.bounds))
ss.zip(tps).flatMap { | ||
case (sp : Prod, tp) => sp.tp -> tp :: genConstraint(sp) | ||
case (Typ(tp1, _), tp2) => tp1 -> tp2 :: Nil | ||
case _ => ??? // impossible |
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.
I feel that we should use something other than ???
for unreachable cases, to me ???
really has the semantic of a TODO: "implementation is missing here, to be added later"
Maybe something like this? Not sure where should that definition could go...
def impossible: Nothing = throw new AssertionError("This expression shouldn't be reachable.")
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.
assert(false, "Unreachable code")
?
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.
@allanrenucci assert returns Unit
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.
My bad...
@@ -775,6 +810,15 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { | |||
res | |||
} | |||
|
|||
def checkGADT(tp: Type): Boolean = { |
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.
I'm not sure what you mean by checkGADT
the implementation looks like it's computing isDeeplyInvariant
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.
Yes, something like shouldCheckGADT
with a comment is more friendly.
@liufengyun Is it possible to use object O {
sealed trait NumExpr[T]
case class IntLit(v: Int) extends NumExpr[Int]
case class DoubleLit(v: Double) extends NumExpr[Double]
case class Mul[T](n1: NumExpr[T], n2: NumExpr[T]) extends NumExpr[T]
def simplify[T](e: NumExpr[T]): NumExpr[T] = e match {
case Mul(IntLit(i), ie) => ie match {
case IntLit(0) => IntLit(0)
case IntLit(1) => IntLit(i)
case IntLit(_) | Mul(_, _) => e
}
case _ => e
}
} where the typechecker already knows that |
@AleksanderBG Good observation. The Edited: Also, I think it's up to the typer to give |
00b94be
to
8613227
Compare
8613227
to
cd5a1d1
Compare
This is an alternative to #3454.
The idea (implemented in OCaml, briefly mentioned in the
space
paper) is simple: just exclude counterexamples that are not satisfiable.The PR passed all GADT tests, and it should have better performance by only enabling the checking for
invariant
GADTs. It doesn't do any changes to the core algorithm.Many thanks to @AleksanderBG for his work on checking GADTs and pushing the limits of exhaustivity check for Scala.
cc/ @AleksanderBG: we're still interested in your algorithm , it would be nice to have detailed evaluation of the two approaches when #3454 is done.