Skip to content

Commit

Permalink
Do not consider envs from no_return clauses
Browse files Browse the repository at this point in the history
Summary:
When elaborating an expression with multiple clauses, we generate one refined environment per clause and use them to elaborate the clauses. We then join **all** resulting types **and** environments to produce the result of the elaboration.

However, if a clause throws/exit/doesn't return, then its resulting environment can be ignored as it will never appear in the remainder of the code.

Consider this example which currently errors:
```
-spec foo(L :: list() | map()) -> term().
case is_list(L) of
  true -> ok;
  false -> error(not_list)
end,
lists:nth(1, L). % error: L has type list() | map()
```
In clause `true -> ok` we have `L :: list()`, and in the other clause `L :: map()`.

Since the second clause doesn't return, its environment can be ignored, making the `case` expression return the environment `L :: list()`, and making the example accepted.

This diff achieves it by marking all types in the environment as being empty.

Reviewed By: ilya-klyuchnikov

Differential Revision: D68410835

fbshipit-source-id: 8bdd26e949673f0d915620738a50bb888a90dcd3
  • Loading branch information
VLanvin authored and facebook-github-bot committed Jan 20, 2025
1 parent bd21cef commit a4a5219
Showing 1 changed file with 4 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ final class Elab(pipelineContext: PipelineContext) {
val env4 = elabGuard.elabGuards(clause.guards, env3)
val (eType, env5) = elabBody(clause.body, env4)
val env6 = util.exitScope(env0, env5, exportedVars)
(eType, env6)
if (subtype.gradualSubType(eType, NoneType))
(NoneType, env6.map { case (name, _) => (name -> NoneType) })
else
(eType, env6)
}

def elabExprs(exprs: List[Expr], env: Env): (List[Type], Env) = {
Expand Down

0 comments on commit a4a5219

Please sign in to comment.