Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error messages for incomplete probability calls #1021

Merged
28 changes: 28 additions & 0 deletions src/frontend/Semantic_error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ module TypeError = struct
| ReturningFnExpectedNonReturningFound of string
| ReturningFnExpectedNonFnFound of string
| ReturningFnExpectedUndeclaredIdentFound of string
| ReturningFnExpectedUndeclaredDistSuffixFound of string * string
| ReturningFnExpectedWrongDistSuffixFound of string * string
| NonReturningFnExpectedReturningFound of string
| NonReturningFnExpectedNonFnFound of string
| NonReturningFnExpectedUndeclaredIdentFound of string
Expand Down Expand Up @@ -163,6 +165,22 @@ module TypeError = struct
"A returning function was expected but an undeclared identifier \
'%s' was supplied."
fn_name
| ReturningFnExpectedUndeclaredDistSuffixFound (prefix, suffix) ->
Fmt.pf ppf "Function '%s_%s' is not implemented for distribution '%s'."
prefix suffix prefix
| ReturningFnExpectedWrongDistSuffixFound (prefix, suffix) ->
let newsuffix =
match suffix with
| "lpdf" -> "lpmf"
| "lupdf" -> "lupmf"
| "lpmf" -> "lpdf"
| "lupmf" -> "lupdf"
| _ -> raise_s [%message "This should never happen."]
in
Fmt.pf ppf
"Function '%s_%s' is not implemented for distribution '%s', use \
'%s_%s' instead."
prefix suffix prefix prefix newsuffix
| NonReturningFnExpectedUndeclaredIdentFound fn_name ->
Fmt.pf ppf
"A non-returning function was expected but an undeclared identifier \
Expand Down Expand Up @@ -487,6 +505,16 @@ let returning_fn_expected_nonfn_found loc name =
let returning_fn_expected_undeclaredident_found loc name =
TypeError (loc, TypeError.ReturningFnExpectedUndeclaredIdentFound name)

let returning_fn_expected_undeclared_dist_suffix_found loc (prefix, suffix) =
TypeError
( loc
, TypeError.ReturningFnExpectedUndeclaredDistSuffixFound (prefix, suffix)
)

let returning_fn_expected_wrong_dist_suffix_found loc (prefix, suffix) =
TypeError
(loc, TypeError.ReturningFnExpectedWrongDistSuffixFound (prefix, suffix))

let nonreturning_fn_expected_returning_found loc name =
TypeError (loc, TypeError.NonReturningFnExpectedReturningFound name)

Expand Down
6 changes: 6 additions & 0 deletions src/frontend/Semantic_error.mli
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ val returning_fn_expected_nonfn_found : Location_span.t -> string -> t
val returning_fn_expected_undeclaredident_found :
Location_span.t -> string -> t

val returning_fn_expected_undeclared_dist_suffix_found :
Location_span.t -> string * string -> t

val returning_fn_expected_wrong_dist_suffix_found :
Location_span.t -> string * string -> t

val illtyped_reduce_sum :
Location_span.t
-> string
Expand Down
33 changes: 32 additions & 1 deletion src/frontend/Typechecker.ml
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,38 @@ let check_fn ~is_cond_dist loc tenv id es =
(Utils.normalized_name id.name)) ->
Semantic_error.returning_fn_expected_nonfn_found loc id.name |> error
| [] ->
Semantic_error.returning_fn_expected_undeclaredident_found loc id.name
( match Utils.split_distribution_suffix id.name with
| Some (prefix, suffix) -> (
let known_families =
List.map
~f:(fun (_, y, _, _) -> y)
Stan_math_signatures.distributions
in
let is_known_family s =
List.mem known_families s ~equal:String.equal
in
match suffix with
| ("lpmf" | "lumpf") when Env.mem tenv (prefix ^ "_lpdf") ->
Semantic_error.returning_fn_expected_wrong_dist_suffix_found loc
(prefix, suffix)
| ("lpdf" | "lumdf") when Env.mem tenv (prefix ^ "_lpmf") ->
Semantic_error.returning_fn_expected_wrong_dist_suffix_found loc
(prefix, suffix)
| _ ->
if
is_known_family prefix
&& List.mem ~equal:String.equal
Utils.cumulative_distribution_suffices_w_rng suffix
then
Semantic_error
.returning_fn_expected_undeclared_dist_suffix_found loc
(prefix, suffix)
else
Semantic_error.returning_fn_expected_undeclaredident_found loc
id.name )
| None ->
Semantic_error.returning_fn_expected_undeclaredident_found loc
id.name )
|> error
| _ (* a function *) -> (
match SignatureMismatch.returntype tenv id.name (get_arg_types es) with
Expand Down
7 changes: 7 additions & 0 deletions src/middle/Utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ let conditioning_suffices =
["_lpdf"; "_lupdf"; "_lupmf"; "_lpmf"; "_cdf"; "_lcdf"; "_lccdf"]

let conditioning_suffices_w_log = conditioning_suffices @ ["_log"]

let cumulative_distribution_suffices =
["cdf"; "lcdf"; "lccdf"; "cdf_log"; "ccdf_log"]

let cumulative_distribution_suffices_w_rng =
cumulative_distribution_suffices @ ["rng"]

let is_user_ident = Fn.non (String.is_suffix ~suffix:"__")

let unnormalized_suffix = function
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
model {
target += foo_lpdf(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
data {
int foo_lpmf;
}
model {
target += foo_lpdf(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data {
}
model {
target += von_mises_ccdf_log(1, 0,1);
}
1 change: 1 addition & 0 deletions test/integration/bad/missing_dist_suffix/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(include ../dune)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
data {
}
model {
// known family, known suffix, not implemented
target += binomial_lpdf(1|0,1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
data {
}
model {
// known family, known suffix, not implemented
target += normal_lpmf(1|0,1);
}
3 changes: 3 additions & 0 deletions test/integration/bad/missing_dist_suffix/no_rng_suffix.stan
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
generated quantities {
real x = multi_gp_cholesky_rng([[0,0],[0,0]], [1,0]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data {
}
model {
target += von_mises_cdf(1|0,1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data {
}
model {
target += von_mises_lcdf(1|0,1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data {
}
model {
target += von_mises_lccdf(1|0,1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data {
}
model {
target += von_mises_notasuffix(1,0,1);
}
141 changes: 141 additions & 0 deletions test/integration/bad/missing_dist_suffix/stanc.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
$ ../../../../../install/default/bin/stanc completely_undefined1.stan
Semantic error in 'completely_undefined1.stan', line 2, column 12 to column 23:
-------------------------------------------------
1: model {
2: target += foo_lpdf(1);
^
3: }
-------------------------------------------------

A returning function was expected but an undeclared identifier 'foo_lpdf' was supplied.
$ ../../../../../install/default/bin/stanc completely_undefined2.stan
Semantic error in 'completely_undefined2.stan', line 5, column 12 to column 23:
-------------------------------------------------
3: }
4: model {
5: target += foo_lpdf(1);
^
6: }
-------------------------------------------------

Function 'foo_lpdf' is not implemented for distribution 'foo', use 'foo_lpmf' instead.
$ ../../../../../install/default/bin/stanc deprecated_suffix.stan
Semantic error in 'deprecated_suffix.stan', line 4, column 14 to column 40:
-------------------------------------------------
2: }
3: model {
4: target += von_mises_ccdf_log(1, 0,1);
^
5: }
-------------------------------------------------

Function 'von_mises_ccdf_log' is not implemented for distribution 'von_mises'.
$ ../../../../../install/default/bin/stanc lpmf_lpdf_replacement1.stan
Semantic error in 'lpmf_lpdf_replacement1.stan', line 5, column 14 to column 34:
-------------------------------------------------
3: model {
4: // known family, known suffix, not implemented
5: target += binomial_lpdf(1|0,1);
^
6: }
-------------------------------------------------

Function 'binomial_lpdf' is not implemented for distribution 'binomial', use 'binomial_lpmf' instead.
$ ../../../../../install/default/bin/stanc lpmf_lpdf_replacement2.stan
Semantic error in 'lpmf_lpdf_replacement2.stan', line 5, column 14 to column 32:
-------------------------------------------------
3: model {
4: // known family, known suffix, not implemented
5: target += normal_lpmf(1|0,1);
^
6: }
-------------------------------------------------

Function 'normal_lpmf' is not implemented for distribution 'normal', use 'normal_lpdf' instead.
$ ../../../../../install/default/bin/stanc no_rng_suffix.stan
Semantic error in 'no_rng_suffix.stan', line 2, column 12 to column 55:
-------------------------------------------------
1: generated quantities {
2: real x = multi_gp_cholesky_rng([[0,0],[0,0]], [1,0]);
^
3: }
-------------------------------------------------

Function 'multi_gp_cholesky_rng' is not implemented for distribution 'multi_gp_cholesky'.
$ ../../../../../install/default/bin/stanc non_existing_distribution_suffix1.stan
Semantic error in 'non_existing_distribution_suffix1.stan', line 4, column 14 to column 34:
-------------------------------------------------
2: }
3: model {
4: target += von_mises_cdf(1|0,1);
^
5: }
-------------------------------------------------

Function 'von_mises_cdf' is not implemented for distribution 'von_mises'.
$ ../../../../../install/default/bin/stanc non_existing_distribution_suffix2.stan
Semantic error in 'non_existing_distribution_suffix2.stan', line 4, column 14 to column 35:
-------------------------------------------------
2: }
3: model {
4: target += von_mises_lcdf(1|0,1);
^
5: }
-------------------------------------------------

Function 'von_mises_lcdf' is not implemented for distribution 'von_mises'.
$ ../../../../../install/default/bin/stanc non_existing_distribution_suffix3.stan
Semantic error in 'non_existing_distribution_suffix3.stan', line 4, column 14 to column 36:
-------------------------------------------------
2: }
3: model {
4: target += von_mises_lccdf(1|0,1);
^
5: }
-------------------------------------------------

Function 'von_mises_lccdf' is not implemented for distribution 'von_mises'.
$ ../../../../../install/default/bin/stanc non_existing_distribution_suffix4.stan
Semantic error in 'non_existing_distribution_suffix4.stan', line 4, column 14 to column 41:
-------------------------------------------------
2: }
3: model {
4: target += von_mises_notasuffix(1,0,1);
^
5: }
-------------------------------------------------

A returning function was expected but an undeclared identifier 'von_mises_notasuffix' was supplied.
$ ../../../../../install/default/bin/stanc user_defined.stan
Semantic error in 'user_defined.stan', line 7, column 13 to column 27:
-------------------------------------------------
5: }
6: model {
7: target += bar_lpmf(19.2);
^
8: }
-------------------------------------------------

Function 'bar_lpmf' is not implemented for distribution 'bar', use 'bar_lpdf' instead.
$ ../../../../../install/default/bin/stanc user_defined_no_cdf.stan
Semantic error in 'user_defined_no_cdf.stan', line 7, column 14 to column 29:
-------------------------------------------------
5: }
6: model {
7: target += bar_lcdf(1|0,1);
^
8: }
-------------------------------------------------

A returning function was expected but an undeclared identifier 'bar_lcdf' was supplied.
$ ../../../../../install/default/bin/stanc user_defined_no_rng.stan
Semantic error in 'user_defined_no_rng.stan', line 7, column 12 to column 23:
-------------------------------------------------
5: }
6: generated quantities {
7: real x = bar_rng(10);
^
8: }
-------------------------------------------------

A returning function was expected but an undeclared identifier 'bar_rng' was supplied.
8 changes: 8 additions & 0 deletions test/integration/bad/missing_dist_suffix/user_defined.stan
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
functions {
real bar_lpdf(real x){
return 1.0;
}
}
model {
target += bar_lpmf(19.2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
functions {
real bar_lpdf(real x){
return 1.0;
}
}
model {
target += bar_lcdf(1|0,1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
functions {
real bar_lpdf(real x){
return 1.0;
}
}
generated quantities {
real x = bar_rng(10);
}
9 changes: 9 additions & 0 deletions test/integration/tfp/stan_models/test_mat_corr.stan
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data {
int K;
}
parameters {
cholesky_factor_corr[K] L;
}
model {
target += lkj_corr_cholesky_lpdf(L|2.5);
}