@@ -417,10 +417,6 @@ compat_ty({type, Anno1, record, [{atom, _, Name} | Fields1]},
417
417
{type , Anno2 , record , [{atom , _ , Name } | Fields2 ]}, Seen , Env ) ->
418
418
AllFields1 = case Fields1 of [] -> get_record_fields_types (Name , Anno1 , Env ); _ -> Fields1 end ,
419
419
AllFields2 = case Fields2 of [] -> get_record_fields_types (Name , Anno2 , Env ); _ -> Fields2 end ,
420
- % % We can assert because we explicitly match {atom, _, Name}
421
- % % out of the field list in both cases above.
422
- AllFields1 = ? assert_type (AllFields1 , [record_field_type ()]),
423
- AllFields2 = ? assert_type (AllFields2 , [record_field_type ()]),
424
420
compat_record_tys (AllFields1 , AllFields2 , Seen , Env );
425
421
compat_ty ({type , _ , record , _ }, {type , _ , tuple , any }, Seen , _Env ) ->
426
422
ret (Seen );
@@ -440,20 +436,15 @@ compat_ty(Ty1, Ty2, Seen, Env) when ?is_list_type(Ty1), ?is_list_type(Ty2) ->
440
436
compat_ty ({type , _ , tuple , any }, {type , _ , tuple , any }, Seen , _Env ) ->
441
437
ret (Seen );
442
438
compat_ty ({type , _ , tuple , any }, {type , _ , tuple , Args2 }, Seen , Env ) ->
443
- % % We can assert because we match out `any' in previous clauses.
444
- % % TODO: it would be perfect if Gradualizer could refine this type automatically in such a case
445
- Args2 = ? assert_type (Args2 , [type ()]),
446
439
Args1 = lists :duplicate (length (Args2 ), type (any )),
447
440
% We check the argument types because Args2 may contain type variables
448
441
% and in that case, we want to constrain them
449
442
compat_tys (Args1 , Args2 , Seen , Env );
450
443
compat_ty ({type , _ , tuple , Args1 }, {type , _ , tuple , any }, Seen , Env ) ->
451
- Args1 = ? assert_type (Args1 , [type ()]),
452
444
Args2 = lists :duplicate (length (Args1 ), type (any )),
453
445
compat_tys (Args1 , Args2 , Seen , Env );
454
446
compat_ty ({type , _ , tuple , Args1 }, {type , _ , tuple , Args2 }, Seen , Env ) ->
455
- compat_tys (? assert_type (Args1 , [type ()]),
456
- ? assert_type (Args2 , [type ()]), Seen , Env );
447
+ compat_tys (Args1 , Args2 , Seen , Env );
457
448
458
449
% % Maps
459
450
compat_ty ({type , _ , map , [? any_assoc ]}, {type , _ , map , _Assocs }, Seen , _Env ) ->
@@ -469,10 +460,6 @@ compat_ty({type, _, map, Assocs1}, {type, _, map, Assocs2}, Seen, Env) ->
469
460
({type , _ , map_field_exact , _ }) -> true ;
470
461
(_ ) -> false
471
462
end ,
472
- % % We can assert because {type, _, map, any} is normalized away by normalize/2,
473
- % % whereas ?any_assoc associations are matched out explicitly in the previous clauses.
474
- Assocs1 = ? assert_type (Assocs1 , [gradualizer_type :af_assoc_type ()]),
475
- Assocs2 = ? assert_type (Assocs2 , [gradualizer_type :af_assoc_type ()]),
476
463
MandatoryAssocs1 = lists :filter (IsMandatory , Assocs1 ),
477
464
MandatoryAssocs2 = lists :filter (IsMandatory , Assocs2 ),
478
465
{Seen3 , Cs3 } = lists :foldl (fun ({type , _ , map_field_exact , _ } = Assoc2 , {Seen2 , Cs2 }) ->
@@ -507,10 +494,6 @@ compat_ty({type, _, AssocTag1, [Key1, Val1]},
507
494
AssocTag1 == map_field_exact , AssocTag2 == map_field_exact ;
508
495
AssocTag1 == map_field_exact , AssocTag2 == map_field_assoc ->
509
496
% % For M1 <: M2, mandatory fields in M2 must be mandatory fields in M1
510
- Key1 = ? assert_type (Key1 , type ()),
511
- Key2 = ? assert_type (Key2 , type ()),
512
- Val1 = ? assert_type (Val1 , type ()),
513
- Val2 = ? assert_type (Val2 , type ()),
514
497
{Seen1 , Cs1 } = compat (Key1 , Key2 , Seen , Env ),
515
498
{Seen2 , Cs2 } = compat (Val1 , Val2 , Seen1 , Env ),
516
499
{Seen2 , constraints :combine (Cs1 , Cs2 , Env )};
@@ -4015,7 +3998,6 @@ disable_exhaustiveness_check(#env{} = Env) ->
4015
3998
check_arg_exhaustiveness (Env , ArgTys , Clauses , RefinedArgTys ) ->
4016
3999
case exhaustiveness_checking (Env ) andalso
4017
4000
all_refinable (ArgTys , Env ) andalso
4018
- no_clause_has_guards (Clauses ) andalso
4019
4001
some_type_not_none (RefinedArgTys )
4020
4002
of
4021
4003
true ->
@@ -4036,10 +4018,6 @@ exhaustiveness_checking(#env{} = Env) ->
4036
4018
all_refinable (any , _Env ) -> false ;
4037
4019
all_refinable (Types , Env ) -> lists :all (fun (Ty ) -> refinable (Ty , Env ) end , Types ).
4038
4020
4039
- - spec no_clause_has_guards (_ ) -> boolean ().
4040
- no_clause_has_guards (Clauses ) ->
4041
- lists :all (fun no_guards /1 , Clauses ).
4042
-
4043
4021
- spec some_type_not_none ([type ()]) -> boolean ().
4044
4022
some_type_not_none (Types ) when is_list (Types ) ->
4045
4023
lists :any (fun (T ) -> T =/= type (none ) end , Types ).
@@ -4106,6 +4084,8 @@ refine_mismatch_using_guards(PatTys,
4106
4084
do_refine_mismatch_using_guards (Guards , PatTys , Pats , VEnv , Env );
4107
4085
[_ |_ ] ->
4108
4086
% % we don't know yet how to do this in guard sequences
4087
+ Env # env .no_skip_complex_guards orelse throw ({skip , too_complex_guards }),
4088
+ % % TODO: Invalid lack of pattern refinement
4109
4089
PatTys
4110
4090
end .
4111
4091
@@ -4579,16 +4559,15 @@ mta({user_type, Anno, Name, Args}, Env) ->
4579
4559
mta (Type , _Env ) ->
4580
4560
Type .
4581
4561
4582
- - spec no_guards (_ ) -> boolean ().
4583
- no_guards ({clause , _ , _ , Guards , _ }) ->
4584
- Guards == [].
4585
-
4586
4562
% % Refines the types of bound variables using the assumption that a clause has
4587
4563
% % mismatched.
4588
4564
- spec refine_vars_by_mismatching_clause (gradualizer_type :af_clause (), venv (), env ()) -> venv ().
4589
4565
refine_vars_by_mismatching_clause ({clause , _ , Pats , Guards , _Block }, VEnv , Env ) ->
4590
4566
PatternCantFail = are_patterns_matching_all_input (Pats , VEnv ),
4591
4567
case Guards of
4568
+ [] ->
4569
+ % % No guards, so no refinement
4570
+ VEnv ;
4592
4571
[[{call , _ , {atom , _ , Fun }, Args = [{var , _ , Var }]}]] when PatternCantFail ->
4593
4572
% % Simple case: A single guard on the form `when is_TYPE(Var)'.
4594
4573
% % If Var was bound before the clause, which failed because of a
@@ -4602,7 +4581,8 @@ refine_vars_by_mismatching_clause({clause, _, Pats, Guards, _Block}, VEnv, Env)
4602
4581
VEnv
4603
4582
end ;
4604
4583
_OtherGuards ->
4605
- % % No refinement
4584
+ Env # env .no_skip_complex_guards orelse throw ({skip , too_complex_guards }),
4585
+ % % TODO: Invalid lack of refinement
4606
4586
VEnv
4607
4587
end .
4608
4588
@@ -4746,17 +4726,23 @@ type_check_function(Env, {function, _Anno, Name, NArgs, Clauses}) ->
4746
4726
? verbose (Env , " Checking function ~p /~p~n " , [Name , NArgs ]),
4747
4727
case maps :find ({Name , NArgs }, Env # env .fenv ) of
4748
4728
{ok , FunTy } ->
4749
- NewEnv = Env # env {current_spec = FunTy },
4750
- FunTyNoPos = [ typelib :remove_pos (? assert_type (Ty , type ())) || Ty <- FunTy ],
4751
- Arity = clause_arity (hd (Clauses )),
4752
- case expect_fun_type (NewEnv , FunTyNoPos , Arity ) of
4753
- {type_error , NotFunTy } ->
4754
- % % This can only happen if `create_fenv/2' creates garbage.
4755
- erlang :error ({invalid_function_type , NotFunTy });
4756
- FTy ->
4757
- FTy1 = make_rigid_type_vars (FTy ),
4758
- _Vars = check_clauses_fun (NewEnv , FTy1 , Clauses ),
4759
- NewEnv
4729
+ try
4730
+ NewEnv = Env # env {current_spec = FunTy },
4731
+ FunTyNoPos = [ typelib :remove_pos (? assert_type (Ty , type ())) || Ty <- FunTy ],
4732
+ Arity = clause_arity (hd (Clauses )),
4733
+ case expect_fun_type (NewEnv , FunTyNoPos , Arity ) of
4734
+ {type_error , NotFunTy } ->
4735
+ % % This can only happen if `create_fenv/2' creates garbage.
4736
+ erlang :error ({invalid_function_type , NotFunTy });
4737
+ FTy ->
4738
+ FTy1 = make_rigid_type_vars (FTy ),
4739
+ _Vars = check_clauses_fun (NewEnv , FTy1 , Clauses ),
4740
+ NewEnv
4741
+ end
4742
+ catch
4743
+ throw :{skip , Reason } ->
4744
+ ? verbose (Env , " Skipping function ~p /~p due to ~s~n " , [Name , NArgs , Reason ]),
4745
+ Env
4760
4746
end ;
4761
4747
error ->
4762
4748
throw (internal_error (missing_type_spec , Name , NArgs ))
@@ -4771,18 +4757,17 @@ arity(I) ->
4771
4757
? assert (I < 256 , arity_overflow ),
4772
4758
? assert_type (I , arity ()).
4773
4759
4774
- - spec position_info_from_spec (form () | forms () | none ) -> erl_anno :anno ().
4760
+ - spec position_info_from_spec (none | form () | forms ()) -> erl_anno :anno ().
4775
4761
position_info_from_spec (none ) ->
4776
4762
% % This simplifies testing internal functions.
4777
4763
% % In these cases we don't go through type_check_function,
4778
4764
% % but call deeper into the typechecker directly.
4779
4765
erl_anno :new (0 );
4766
+ position_info_from_spec (Form ) when is_tuple (Form ) ->
4767
+ element (2 , Form );
4780
4768
position_info_from_spec ([_ |_ ] = Forms ) ->
4781
4769
% % TODO: https://github.com/josefs/Gradualizer/issues/388
4782
- position_info_from_spec (hd (Forms ));
4783
- position_info_from_spec (Form ) ->
4784
- Form = ? assert_type (Form , form ()),
4785
- element (2 , Form ).
4770
+ position_info_from_spec (hd (Forms )).
4786
4771
4787
4772
% % Type check patterns against types (P1 :: T1, P2 :: T2, ...)
4788
4773
% % and add variable bindings for the patterns.
@@ -5835,7 +5820,8 @@ create_env(#parsedata{module = Module
5835
5820
verbose = proplists :get_bool (verbose , Opts ),
5836
5821
union_size_limit = proplists :get_value (union_size_limit , Opts ,
5837
5822
default_union_size_limit ()),
5838
- solve_constraints = proplists :get_bool (solve_constraints , Opts )}.
5823
+ solve_constraints = proplists :get_bool (solve_constraints , Opts ),
5824
+ no_skip_complex_guards = proplists :get_bool (no_skip_complex_guards , Opts )}.
5839
5825
5840
5826
- spec default_union_size_limit () -> non_neg_integer ().
5841
5827
default_union_size_limit () -> 30 .
0 commit comments