@@ -1258,6 +1258,18 @@ defmodule Module.Types.Pattern do
12581258 end
12591259 end
12601260
1261+ @ dynamic_fail dynamic ( atom ( [ :fail ] ) )
1262+
1263+ # `x or :fail` is a pattern used in Elixir to make guards fail.
1264+ # For example, `not is_struct(x, Foo)` checks if `Foo` is an atom
1265+ # or fails, but in the negation case `:fail` becomes a possible
1266+ # return type leading to a violation, we don't want. So we mark
1267+ # `:fail` as dynamic as its whole purpose is to cause failures.
1268+ defp of_remote ( :orelse , [ left , :fail ] , _call , expected , stack , context ) do
1269+ { type , context } = of_guard ( left , expected , left , stack , context )
1270+ { union ( type , @ dynamic_fail ) , context }
1271+ end
1272+
12611273 defp of_remote ( fun , _args , call , expected , stack , context )
12621274 when fun in [ :and , :or , :andalso , :orelse ] do
12631275 { both_domain , abort_domain , always_rhs? } =
@@ -1280,38 +1292,43 @@ defmodule Module.Types.Pattern do
12801292 # For example, if the expected type is true for andalso, then it can
12811293 # only be true if both clauses are executed, so we know the first
12821294 # argument has to be true and the second has to be expected.
1283- if subtype? ( expected , both_domain ) do
1284- of_logical_all ( [ left | right ] , true , both_domain , abort_domain , stack , context )
1285- else
1286- cond_context = enable_conditional_mode ( context )
1295+ cond do
1296+ subtype? ( expected , both_domain ) ->
1297+ of_logical_all ( [ left | right ] , true , both_domain , abort_domain , stack , context )
12871298
1288- # Compute the sure types, which are stored directly in the context
1289- { _type , context } = of_guard ( left , boolean ( ) , left , stack , context )
1299+ right == [ ] ->
1300+ of_guard ( left , expected , left , stack , context )
12901301
1291- # andalso/orelse may not execute the rhs, so we cannot get sure types from it
1292- context =
1293- case always_rhs? do
1294- true ->
1295- Enum . reduce ( right , context , fn expr , context ->
1296- { _ , context } = of_guard ( expr , boolean ( ) , expr , stack , context )
1297- context
1298- end )
1302+ true ->
1303+ cond_context = enable_conditional_mode ( context )
12991304
1300- false ->
1301- context
1302- end
1305+ # Compute the sure types, which are stored directly in the context
1306+ { _type , context } = of_guard ( left , boolean ( ) , left , stack , context )
13031307
1304- { type , vars_conds } =
1305- of_logical_cond ( [ left | right ] , none ( ) , [ ] , expected , stack , cond_context )
1308+ # andalso/orelse may not execute the rhs, so we cannot get sure types from it
1309+ context =
1310+ case always_rhs? do
1311+ true ->
1312+ Enum . reduce ( right , context , fn expr , context ->
1313+ { _ , context } = of_guard ( expr , boolean ( ) , expr , stack , context )
1314+ context
1315+ end )
13061316
1307- # We will be precise if all branches changed the same variable
1308- context =
1309- update_in ( context . pattern_info . vars , fn
1310- false -> false
1311- vars -> Of . all_same_conditional_vars? ( vars_conds ) and vars
1312- end )
1317+ false ->
1318+ context
1319+ end
1320+
1321+ { type , vars_conds } =
1322+ of_logical_cond ( [ left | right ] , none ( ) , [ ] , expected , stack , cond_context )
1323+
1324+ # We will be precise if all branches changed the same variable
1325+ context =
1326+ update_in ( context . pattern_info . vars , fn
1327+ false -> false
1328+ vars -> Of . all_same_conditional_vars? ( vars_conds ) and vars
1329+ end )
13131330
1314- { type , Of . reduce_conditional_vars ( vars_conds , call , stack , context ) }
1331+ { type , Of . reduce_conditional_vars ( vars_conds , call , stack , context ) }
13151332 end
13161333 end
13171334
0 commit comments