@@ -48,67 +48,133 @@ open Ast
4848open Ast_defs
4949open Ast_util
5050
51- let scan_exp_in_pexp f (Pat_aux (aux , _ )) =
52- match aux with
53- | Pat_exp (_ , exp ) -> f exp
54- | Pat_when (_ , guard , exp ) ->
55- f guard;
56- f exp
51+ module Scan (F : sig
52+ type t
53+ val do_exp : t exp -> unit
54+ val do_funcl_pexp : (t pat -> t exp option -> t exp -> unit ) option
55+ end ) : sig
56+ val in_def : (F .t , 'b ) def -> unit
57+ end = struct
58+ let in_pexp (Pat_aux (aux , _ )) =
59+ match aux with
60+ | Pat_exp (_ , exp ) -> F. do_exp exp
61+ | Pat_when (_ , guard , exp ) ->
62+ F. do_exp guard;
63+ F. do_exp exp
5764
58- let scan_exp_in_funcl f (FCL_aux (FCL_funcl (_ , pexp ), _ )) = scan_exp_in_pexp f pexp
65+ let in_funcl (FCL_aux (FCL_funcl (_ , pexp ), _ )) =
66+ match F. do_funcl_pexp with
67+ | Some g -> (
68+ match pexp with
69+ | Pat_aux (Pat_exp (pat , exp ), _ ) -> g pat None exp
70+ | Pat_aux (Pat_when (pat , guard , exp ), _ ) -> g pat (Some guard) exp
71+ )
72+ | None -> in_pexp pexp
5973
60- let scan_exp_in_mpexp f (MPat_aux (aux , _ )) = match aux with MPat_when (_ , exp ) -> f exp | MPat_pat _ -> ()
74+ let in_mpexp (MPat_aux (aux , _ )) = match aux with MPat_when (_ , exp ) -> F. do_exp exp | MPat_pat _ -> ()
6175
62- let scan_exp_in_mapcl f (MCL_aux (aux , _ )) =
63- match aux with
64- | MCL_forwards pexp | MCL_backwards pexp -> scan_exp_in_pexp f pexp
65- | MCL_bidir (left , right ) ->
66- scan_exp_in_mpexp f left;
67- scan_exp_in_mpexp f right
76+ let in_mapcl (MCL_aux (aux , _ )) =
77+ match aux with
78+ | MCL_forwards pexp | MCL_backwards pexp -> in_pexp pexp
79+ | MCL_bidir (left , right ) ->
80+ in_mpexp left;
81+ in_mpexp right
6882
69- let scan_exp_in_scattered_def f (SD_aux (aux , _ )) =
70- match aux with
71- | SD_function _ | SD_unioncl _ | SD_variant _ | SD_internal_unioncl_record _ | SD_enumcl _ | SD_enum _ | SD_mapping _
72- | SD_end _ ->
73- ()
74- | SD_funcl funcl -> scan_exp_in_funcl f funcl
75- | SD_mapcl (_ , mapcl ) -> scan_exp_in_mapcl f mapcl
83+ let in_scattered_def (SD_aux (aux , _ )) =
84+ match aux with
85+ | SD_function _ | SD_unioncl _ | SD_variant _ | SD_internal_unioncl_record _ | SD_enumcl _ | SD_enum _
86+ | SD_mapping _ | SD_end _ ->
87+ ()
88+ | SD_funcl funcl -> in_funcl funcl
89+ | SD_mapcl (_ , mapcl ) -> in_mapcl mapcl
7690
77- let scan_exp_in_fundef f (FD_aux (FD_function (_ , _ , funcls ), _ )) = List. iter (scan_exp_in_funcl f) funcls
91+ let in_fundef (FD_aux (FD_function (_ , _ , funcls ), _ )) = List. iter in_funcl funcls
7892
79- let rec scan_exp_in_def f (DEF_aux (aux , _ )) =
80- match aux with
81- | DEF_fundef fdef -> scan_exp_in_fundef f fdef
82- | DEF_mapdef (MD_aux (MD_mapping (_ , _ , mapcls ), _ )) -> List. iter (scan_exp_in_mapcl f) mapcls
83- | DEF_register (DEC_aux (DEC_reg (_ , _ , exp_opt ), _ )) -> Option. iter f exp_opt
84- | DEF_outcome (_ , defs ) -> List. iter (scan_exp_in_def f) defs
85- | DEF_impl funcl -> scan_exp_in_funcl f funcl
86- | DEF_let (LB_aux (LB_val (_ , exp ), _ )) -> f exp
87- | DEF_scattered sdef -> scan_exp_in_scattered_def f sdef
88- | DEF_internal_mutrec fdefs -> List. iter (scan_exp_in_fundef f) fdefs
89- | DEF_loop_measures _ -> ()
90- | DEF_measure (_ , _ , exp ) -> f exp
91- | DEF_type _ | DEF_constraint _ | DEF_val _ | DEF_fixity _ | DEF_overload _ | DEF_default _ | DEF_pragma _
92- | DEF_instantiation _ ->
93- ()
93+ let rec in_def (DEF_aux (aux , _ )) =
94+ match aux with
95+ | DEF_fundef fdef -> in_fundef fdef
96+ | DEF_mapdef (MD_aux (MD_mapping (_ , _ , mapcls ), _ )) -> List. iter in_mapcl mapcls
97+ | DEF_register (DEC_aux (DEC_reg (_ , _ , exp_opt ), _ )) -> Option. iter F. do_exp exp_opt
98+ | DEF_outcome (_ , defs ) -> List. iter in_def defs
99+ | DEF_impl funcl -> in_funcl funcl
100+ | DEF_let (LB_aux (LB_val (_ , exp ), _ )) -> F. do_exp exp
101+ | DEF_scattered sdef -> in_scattered_def sdef
102+ | DEF_internal_mutrec fdefs -> List. iter in_fundef fdefs
103+ | DEF_loop_measures _ -> ()
104+ | DEF_measure (_ , _ , exp ) -> F. do_exp exp
105+ | DEF_type _ | DEF_constraint _ | DEF_val _ | DEF_fixity _ | DEF_overload _ | DEF_default _ | DEF_pragma _
106+ | DEF_instantiation _ ->
107+ ()
108+ end
94109
95- let warn_unmodified_variables ast =
96- let warn_unused (lexp , bind , exp ) =
97- let unused = IdSet. diff lexp exp in
110+ let warn_unmodified_variables ( type a ) ( ast : (a, 'b) ast ) : unit =
111+ let warn_unmodified (lexp , bind , exp ) =
112+ let unmodified = IdSet. diff lexp exp in
98113 IdSet. iter
99114 (fun id ->
100115 Reporting. warn " Unnecessary mutability" (id_loc id)
101116 " This variable is mutable, but it is never modified. It could be declared as immutable using 'let'."
102117 )
103- unused ;
118+ unmodified ;
104119 IdSet. union (IdSet. diff exp lexp) bind
105120 in
106121 let alg =
107122 {
108123 (Rewriter. pure_exp_alg IdSet. empty IdSet. union) with
109124 le_id = IdSet. singleton;
110125 le_typ = (fun (_ , id ) -> IdSet. singleton id);
111- e_var = warn_unused;
126+ e_var = warn_unmodified;
127+ }
128+ in
129+ let module S = Scan (struct
130+ type t = a
131+ let do_exp exp = ignore (Rewriter. fold_exp alg exp)
132+ let do_funcl_pexp = None
133+ end ) in
134+ List. iter S. in_def ast.defs
135+
136+ let warn_unused_variables (ast : Type_check.typed_ast ) : unit =
137+ let ignore_variable id = (string_of_id id).[0 ] = '_' || is_gen_loc (id_loc id) in
138+ let pexp_unused pat guard_opt exp =
139+ let used = IdSet. union exp (Option. value ~default: IdSet. empty guard_opt) in
140+ let unused = IdSet. diff pat used in
141+ IdSet. iter
142+ (fun id ->
143+ if not (ignore_variable id) then
144+ Reporting. warn " Unused variable" (id_loc id) " This variable is defined but never used."
145+ )
146+ unused;
147+ IdSet. diff used pat
148+ in
149+ (* Gather all the variables defined by a pattern *)
150+ let pat_alg env =
151+ {
152+ (Rewriter. pure_pat_alg IdSet. empty IdSet. union) with
153+ p_id = (fun id -> if Type_check. is_enum_member id env then IdSet. empty else IdSet. singleton id);
154+ p_vector_subrange = (fun (id , _ , _ ) -> IdSet. singleton id);
155+ p_as = (fun (_ , id ) -> IdSet. singleton id);
156+ }
157+ in
158+ let alg env =
159+ {
160+ (Rewriter. pure_exp_alg IdSet. empty IdSet. union) with
161+ e_id = IdSet. singleton;
162+ pat_exp = (fun (pat , exp ) -> pexp_unused pat None exp);
163+ pat_when = (fun (pat , guard , exp ) -> pexp_unused pat (Some guard) exp);
164+ pat_alg = pat_alg env;
112165 }
113166 in
114- List. iter (scan_exp_in_def (fun exp -> ignore (Rewriter. fold_exp alg exp))) ast.defs
167+ let module S = Scan (struct
168+ type t = Type_check .tannot
169+ let do_exp exp = ignore (Rewriter. fold_exp (alg (Type_check. env_of exp)) exp)
170+ let do_funcl_pexp =
171+ Some
172+ (fun pat guard_opt exp ->
173+ let env = Type_check. env_of_pat pat in
174+ let pat = Rewriter. fold_pat (pat_alg env) pat in
175+ let guard_opt = Option. map (Rewriter. fold_exp (alg env)) guard_opt in
176+ let exp = Rewriter. fold_exp (alg env) exp in
177+ ignore (pexp_unused pat guard_opt exp)
178+ )
179+ end ) in
180+ List. iter S. in_def ast.defs
0 commit comments