@@ -41,6 +41,76 @@ let lkj_cov_message =
41
41
independent lognormal distribution on the scales, see: \
42
42
https://mc-stan.org/docs/reference-manual/deprecations.html#lkj_cov-distribution"
43
43
44
+ let functions_block_contains_jac_pe (stmts : untyped_statement list ) =
45
+ (* tracking if 'jacobian' is a variable in scope *)
46
+ let jacobian_scope_id = ref 0 in
47
+ let is_jacobian_in_scope () = ! jacobian_scope_id > 0 in
48
+ let current_scope_id = ref 1 in
49
+ let found_jacobian () =
50
+ if not (is_jacobian_in_scope () ) then jacobian_scope_id := ! current_scope_id
51
+ in
52
+ let push_scope () = current_scope_id := ! current_scope_id + 1 in
53
+ let pop_scope () =
54
+ current_scope_id := ! current_scope_id - 1 ;
55
+ (* if the scope we just left was the one defining jacobian, reset it *)
56
+ if ! jacobian_scope_id > ! current_scope_id then jacobian_scope_id := 0 in
57
+ (* walk over the tree, looking for usages of jacobian+= where
58
+ there is no variable called jacobian already in scope *)
59
+ let rec f (s : untyped_statement ) =
60
+ match s.stmt with
61
+ | FunDef {body; funname; _}
62
+ when String. is_suffix funname.name ~suffix: " _jacobian" ->
63
+ push_scope () ;
64
+ let res = f body in
65
+ pop_scope () ;
66
+ res
67
+ | Block stmts | Profile (_ , stmts ) ->
68
+ push_scope () ;
69
+ let res = List. exists ~f stmts in
70
+ pop_scope () ;
71
+ res
72
+ | For {loop_body; _} | While (_ , loop_body ) | ForEach (_ , _ , loop_body ) ->
73
+ push_scope () ;
74
+ let res = f loop_body in
75
+ pop_scope () ;
76
+ res
77
+ | IfThenElse (_ , s1 , s2_opt ) ->
78
+ push_scope () ;
79
+ let res1 = f s1 in
80
+ pop_scope () ;
81
+ push_scope () ;
82
+ let res2 = match s2_opt with Some s2 -> f s2 | None -> false in
83
+ pop_scope () ;
84
+ res1 || res2
85
+ | JacobianPE _ -> true
86
+ | Assignment
87
+ { assign_lhs= LValue {lval= LVariable {name; _}; _}
88
+ ; assign_op= OperatorAssign Plus
89
+ ; _ }
90
+ when String. equal name " jacobian" ->
91
+ not (is_jacobian_in_scope () )
92
+ | VarDecl {variables; _} ->
93
+ if
94
+ List. exists
95
+ ~f: (fun {identifier; _} -> String. equal identifier.name " jacobian" )
96
+ variables
97
+ then found_jacobian () ;
98
+ false
99
+ | _ -> false in
100
+ let res = List. exists ~f stmts in
101
+ (* sanity check that pushes and pops are balanced *)
102
+ if ! current_scope_id <> 1 then
103
+ Common.ICE. internal_compiler_error
104
+ [% message
105
+ " functions_block_contains_jac_pe: scope tracking failed"
106
+ (! current_scope_id : int )
107
+ (! jacobian_scope_id : int )
108
+ (stmts : untyped_statement list )];
109
+ res
110
+
111
+ let set_jacobian_compatibility_mode stmts =
112
+ Fun_kind. jacobian_compat_mode := not (functions_block_contains_jac_pe stmts)
113
+
44
114
let rec collect_deprecated_expr (acc : (Location_span.t * string) list )
45
115
({expr; emeta} : (typed_expr_meta, fun_kind) expr_with ) :
46
116
(Location_span. t * string ) list =
@@ -89,6 +159,22 @@ let rec collect_deprecated_stmt fundefs (acc : (Location_span.t * string) list)
89
159
, " Functions do not need to be declared before definition; all user \
90
160
defined function names are always in scope regardless of \
91
161
definition order." ) ]
162
+ | FunDef {funname; body; _}
163
+ when ! Fun_kind. jacobian_compat_mode
164
+ && String. is_suffix funname.name ~suffix: " _jacobian" ->
165
+ let acc =
166
+ ( funname.id_loc
167
+ , " Functions that end in _jacobian will change meaning in Stan 2.39. \
168
+ They will be used for the encapsulating usages of 'jacobian +=', \
169
+ and therefore not available to be called in all the same places as \
170
+ this function is now. To avoid any issues, please rename this \
171
+ function to not end in _jacobian." )
172
+ :: acc in
173
+ fold_statement collect_deprecated_expr
174
+ (collect_deprecated_stmt fundefs)
175
+ collect_deprecated_lval
176
+ (fun l _ -> l)
177
+ acc body.stmt
92
178
| Tilde {distribution; _} when String. equal distribution.name " lkj_cov" ->
93
179
let acc = (distribution.id_loc, lkj_cov_message) :: acc in
94
180
fold_statement collect_deprecated_expr
0 commit comments