From ea1084a3dbc1b155c3168a224648b4d504738dc0 Mon Sep 17 00:00:00 2001 From: Ilya Klyuchnikov Date: Mon, 16 Sep 2024 02:41:15 -0700 Subject: [PATCH] reporting ignored overloaded specs Summary: - when a function literal is used (like `fun foo/1`) and the corresponding function has overloaded specs, we elaborate the type of such expression as `dynamic() -> dynamic()`, since overloaded specs are not the part of "language of types" - adding an option to introspect such approximations Reviewed By: VLanvin Differential Revision: D62641981 fbshipit-source-id: 1d7d3c3452640510a4b49acdc99f5d5768ce7bd8 --- eqwalizer/src/main/resources/application.conf | 2 ++ .../src/main/scala/com/whatsapp/eqwalizer/package.scala | 2 ++ .../src/main/scala/com/whatsapp/eqwalizer/tc/Check.scala | 9 ++++++++- .../src/main/scala/com/whatsapp/eqwalizer/tc/Elab.scala | 9 ++++++++- .../scala/com/whatsapp/eqwalizer/tc/TcDiagnostics.scala | 2 +- .../main/scala/com/whatsapp/eqwalizer/tc/package.scala | 1 + 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/eqwalizer/src/main/resources/application.conf b/eqwalizer/src/main/resources/application.conf index 2ba853c..0ce1c6e 100644 --- a/eqwalizer/src/main/resources/application.conf +++ b/eqwalizer/src/main/resources/application.conf @@ -14,4 +14,6 @@ eqwalizer { overloaded_spec_dynamic_result = ${?EQWALIZER_OVERLOADED_SPEC_DYNAMIC_RESULT} custom_maps_merge = false custom_maps_merge = ${?EQWALIZER_CUSTOM_MAPS_MERGE} + ignored_overloaded_spec = false + ignored_overloaded_spec = ${?EQWALIZER_IGNORED_OVERLOADED_SPEC} } diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/package.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/package.scala index 02c954b..0287794 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/package.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/package.scala @@ -37,6 +37,7 @@ package object eqwalizer { customMapsMerge: Boolean, mode: Mode.Mode, errorDepth: Int, + ignoredOverloadedSpec: Boolean, ) lazy val config: Config = { @@ -52,6 +53,7 @@ package object eqwalizer { customMapsMerge = config.getBoolean("custom_maps_merge"), mode, errorDepth = config.getInt("error_depth"), + ignoredOverloadedSpec = config.getBoolean("ignored_overloaded_spec"), ) } } diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Check.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Check.scala index 95d52c9..9ce316b 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Check.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Check.scala @@ -260,13 +260,20 @@ final class Check(pipelineContext: PipelineContext) { } env2 case LocalFun(id) => - val ft = util.getFunType(module, id) + val fqn = util.globalFunId(module, id) + if (pipelineCtx.ignoredOverloadedSpec && util.getOverloadedSpec(fqn).isDefined) { + diagnosticsInfo.add(IgnoredOverloadedSpec(expr.pos)) + } + val ft = util.getFunType(fqn) val ft1 = freshen(ft) if (!subtype.subType(ft1, resTy)) diagnosticsInfo.add(ExpectedSubtype(expr.pos, expr, expected = resTy, got = ft1)) env case RemoteFun(fqn) => val ft = util.getFunType(fqn) + if (pipelineCtx.ignoredOverloadedSpec && util.getOverloadedSpec(fqn).isDefined) { + diagnosticsInfo.add(IgnoredOverloadedSpec(expr.pos)) + } val ft1 = freshen(ft) if (!subtype.subType(ft1, resTy)) diagnosticsInfo.add(ExpectedSubtype(expr.pos, expr, expected = resTy, got = ft1)) diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Elab.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Elab.scala index 296ca78..de4dd11 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Elab.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Elab.scala @@ -227,10 +227,17 @@ final class Elab(pipelineContext: PipelineContext) { (resTy, env1) } case LocalFun(id) => - val ft = util.getFunType(module, id) + val fqn = util.globalFunId(module, id) + if (pipelineCtx.ignoredOverloadedSpec && util.getOverloadedSpec(fqn).isDefined) { + diagnosticsInfo.add(IgnoredOverloadedSpec(expr.pos)) + } + val ft = util.getFunType(fqn) (check.freshen(ft), env) case RemoteFun(fqn) => val ft = util.getFunType(fqn) + if (pipelineCtx.ignoredOverloadedSpec && util.getOverloadedSpec(fqn).isDefined) { + diagnosticsInfo.add(IgnoredOverloadedSpec(expr.pos)) + } (check.freshen(ft), env) case lambda @ Lambda(clauses) => val arity = clauses.head.pats.length diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/TcDiagnostics.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/TcDiagnostics.scala index 4c6dd3d..8948a6e 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/TcDiagnostics.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/TcDiagnostics.scala @@ -46,7 +46,7 @@ object TcDiagnostics { } case class IgnoredOverloadedSpec(pos: Pos) extends TypeError { override val msg: String = s"dynamic() -> dynamic() is used" - def errorName = "not_enough_info_to_branch" + def errorName = "ignored_overloaded_spec" override def erroneousExpr: Option[Expr] = None } case class LambdaArityMismatch(pos: Pos, expr: Expr, lambdaArity: Int, argsArity: Int) extends TypeError { diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/package.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/package.scala index 821af62..62e899b 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/package.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/package.scala @@ -69,5 +69,6 @@ package object tc { val clauseCoverage: Boolean = config.clauseCoverage val overloadedSpecDynamicResult: Boolean = config.overloadedSpecDynamicResult val customMapsMerge: Boolean = config.customMapsMerge + val ignoredOverloadedSpec: Boolean = config.ignoredOverloadedSpec } }