Skip to content

Commit

Permalink
Simplify ElabGuard
Browse files Browse the repository at this point in the history
Summary: Type returned by `elabTest` is not needed anywhere: deleting it.

Reviewed By: ilya-klyuchnikov

Differential Revision: D60453610

fbshipit-source-id: 82c9d60a5077b7d19bb767444ba6b03b337fed4b
  • Loading branch information
VLanvin authored and facebook-github-bot committed Jul 31, 2024
1 parent a1de906 commit fe2b133
Showing 1 changed file with 41 additions and 82 deletions.
123 changes: 41 additions & 82 deletions eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/ElabGuard.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import com.whatsapp.eqwalizer.ast.Id
import com.whatsapp.eqwalizer.ast.Types._
import com.whatsapp.eqwalizer.tc.TcDiagnostics.{UnboundRecord, UndefinedField, UnhandledOp}

import scala.collection.mutable.ListBuffer

final class ElabGuard(pipelineContext: PipelineContext) {
private lazy val module = pipelineContext.module
private lazy val narrow = pipelineContext.narrow
Expand Down Expand Up @@ -67,7 +65,7 @@ final class ElabGuard(pipelineContext: PipelineContext) {
envAcc
}

private def elabTest(test: Test, env: Env): (Type, Env) = {
private def elabTest(test: Test, env: Env): Env = {
test match {
case TestVar(v) =>
// safe because we assume no unbound vars
Expand All @@ -76,90 +74,59 @@ final class ElabGuard(pipelineContext: PipelineContext) {
AnyType,
)
typeInfo.add(test.pos, ty)
(ty, env)
case TestAtom(lit) =>
(AtomLitType(lit), env)
env
case TestAtom(_) =>
env
case TestNumber(_) =>
(NumberType, env)
env
case TestTuple(elems) =>
var envAcc: Env = env
val elemTys = ListBuffer[Type]()
for (elem <- elems) {
val (elemT, elemEnv) = elabTest(elem, envAcc)
elemTys += elemT
val elemEnv = elabTest(elem, envAcc)
envAcc = elemEnv
}
(TupleType(elemTys.toList), envAcc)
envAcc
case TestString() =>
(stringType, env)
env
case TestNil() =>
(NilType, env)
env
case TestCons(head, tail) =>
val (headTy, env1) = elabTest(head, env)
val (tailTy, env2) = elabTest(tail, env1)
if (!subtype.subType(tailTy, ListType(AnyType))) {
(ListType(headTy), env2)
} else {
val resType = narrow.asListType(tailTy) match {
case Some(ListType(t)) => ListType(subtype.join(headTy, t))
case None => headTy
}
(resType, env2)
}
val env1 = elabTest(head, env)
val env2 = elabTest(tail, env1)
env2
case TestMapCreate(kvs) =>
var envAcc: Env = env
val kvTys = ListBuffer[(Type, Type)]()
for ((k, v) <- kvs) {
val (kTy, kEnv) = elabTest(k, envAcc)
val (vTy, vEnv) = elabTest(k, kEnv)
kvTys += kTy -> vTy
val kEnv = elabTest(k, envAcc)
val vEnv = elabTest(v, kEnv)
envAcc = vEnv
}
val isShape = kvs.forall(_._1.isInstanceOf[TestAtom])
if (isShape) {
val props = kvTys.collect { case (AtomLitType(k), v) => ReqProp(k, v) }.toList
(ShapeMap(props), envAcc)
} else {
val domain = kvTys.map(_._1).reduce(subtype.join)
val codomain = kvTys.map(_._2).reduce(subtype.join)
(DictMap(domain, codomain), envAcc)
}
case TestCall(id, args) =>
envAcc
case TestCall(_, args) =>
var envAcc: Env = env
val argTys = ListBuffer[Type]()
for (arg <- args) {
val (argTy, argEnv) = elabTest(arg, envAcc)
argTys += argTy
val argEnv = elabTest(arg, envAcc)
envAcc = argEnv
}
// approx: opacity checking ignores overloaded functions,
// elabApplyCustom functions, and generic functions
// because those functions currently require `Expr`s, not tests
val resTy = util.getFunType("erlang", id) match {
case Some(ft @ FunType(Nil, _argTys, resTy)) =>
resTy
case _ =>
AnyType
}
(resTy, env)
env
case unOp: TestUnOp =>
elabUnOp(unOp, env)
case binOp: TestBinOp =>
elabBinOp(binOp, env)
case TestBinaryLit() =>
(BinaryType, env)
env
case TestRecordIndex(_, _) =>
(NumberType, env)
env
case TestRecordSelect(rec, recName, _) =>
val ty = RecordType(recName)(module)
(ty, elabTestT(rec, ty, env))
elabTestT(rec, ty, env)
case TestRecordCreate(recName, fields) =>
val recDecl =
util.getRecord(module, recName) match {
case Some(recDecl) => recDecl
case None =>
diagnosticsInfo.add(UnboundRecord(test.pos, recName))
return (DynamicType, env)
return env
}
val namedFields = fields.collect { case f: TestRecordFieldNamed => f }
val optGenField = fields.collectFirst { case f: TestRecordFieldGen => f }
Expand Down Expand Up @@ -188,10 +155,10 @@ final class ElabGuard(pipelineContext: PipelineContext) {
}
case None => ()
}
(RecordType(recName)(module), envAcc)
envAcc
case TestMapUpdate(map, _) =>
val ty = DictMap(AnyType, AnyType)
(ty, elabTestT(map, ty, env))
elabTestT(map, ty, env)
}
}

Expand All @@ -218,36 +185,33 @@ final class ElabGuard(pipelineContext: PipelineContext) {
elabTestT(arg1, elabPredicateType22(pred, arg2), env)
case TestBinOp("and", arg1, arg2) =>
val env1 = elabTestT(arg1, AtomLitType("true"), env)
val env2 = elabTestT(arg2, upper, env1)
env2
elabTestT(arg2, upper, env1)
case TestBinOp("andalso", arg1, arg2) =>
val env1 = elabTestT(arg1, AtomLitType("true"), env)
val env2 = elabTestT(arg2, upper, env1)
env2
elabTestT(arg2, upper, env1)
case TestBinOp("orelse", arg1, arg2) =>
val envTrue = elabTestT(arg1, trueType, env)
val envFalse = elabTestT(arg2, upper, env)
subtype.joinEnvs(List(envTrue, envFalse))
case TestBinOp("or", arg1, arg2) =>
val env1 = elabTestT(arg1, booleanType, env)
// "or" is not short-circuiting
val env2 = elabTestT(arg2, booleanType, env1)
env2
elabTestT(arg2, booleanType, env1)
case _ =>
elabTest(test, env)._2
elabTest(test, env)
}
}

def elabUnOp(unOp: TestUnOp, env: Env): (Type, Env) = {
def elabUnOp(unOp: TestUnOp, env: Env): Env = {
val TestUnOp(op, arg) = unOp
op match {
case "not" =>
arg match {
case TestVar(_) => (booleanType, elabTestT(arg, booleanType, env))
case _ => (booleanType, env)
case TestVar(_) => elabTestT(arg, booleanType, env)
case _ => env
}
case "bnot" | "+" | "-" =>
(NumberType, elabTestT(arg, NumberType, env))
elabTestT(arg, NumberType, env)
case _ =>
throw UnhandledOp(unOp.pos, op)
}
Expand Down Expand Up @@ -334,33 +298,28 @@ final class ElabGuard(pipelineContext: PipelineContext) {
case None =>
env
}
case TestBinOp(op, arg1, arg2) =>
val (arg1Ty, env1) = elabTest(arg1, env)
val (arg2Ty, env2) = elabTest(arg2, env1)
env2
case TestBinOp(_, arg1, arg2) =>
val env1 = elabTest(arg1, env)
elabTest(arg2, env1)
}

private def elabBinOp(binOp: TestBinOp, env: Env): (Type, Env) = {
private def elabBinOp(binOp: TestBinOp, env: Env): Env = {
val TestBinOp(op, arg1, arg2) = binOp
op match {
case "/" | "*" | "-" | "+" | "div" | "rem" | "band" | "bor" | "bxor" | "bsl" | "bsr" =>
val env1 = elabTestT(arg1, NumberType, env)
val env2 = elabTestT(arg2, NumberType, env1)
(NumberType, env2)
elabTestT(arg2, NumberType, env1)
case "or" | "xor" | "and" =>
val env1 = elabTestT(arg1, booleanType, env)
val env2 = elabTestT(arg2, booleanType, env1)
(booleanType, env2)
elabTestT(arg2, booleanType, env1)
case ">=" | ">" | "=<" | "<" | "/=" | "=/=" | "==" | "=:=" =>
(booleanType, elabComparison(binOp, env))
elabComparison(binOp, env)
case "andalso" =>
val env1 = elabTestT(arg1, booleanType, env)
val (t2, env2) = elabTest(arg2, env1)
(subtype.join(List(t2, falseType)), env2)
elabTest(arg2, env1)
case "orelse" =>
val env1 = elabTestT(arg1, booleanType, env)
val (t2, env2) = elabTest(arg2, env1)
(subtype.join(List(t2, trueType)), env2)
elabTest(arg2, env1)
case _ =>
throw new IllegalStateException(s"unexpected $op")
}
Expand Down

0 comments on commit fe2b133

Please sign in to comment.