Erlang Dialyzer: принимать только определенные целые числа?

Скажи, у меня есть функция,foo/1чья спецификация -spec foo(atom()) -> #r{}., где #r{} это запись, определенная как -record(r, {a :: 1..789}).Однако у меня есть foo(a) -> 800. в моем коде, когда я запускаю против него диализатор, он не предупредил меня об этом, (800 не является допустимым возвращаемым значением для функции foo/1), могу ли я заставить диализатор предупредить меня об этом?

редактировать

Изучаю тебя Какой-то Эрланг говорит:

Dialyzer оставляет за собой право расширить этот диапазон в более широкий.

Но я не мог найти, как это отключить.

1 ответ

Начиная с Erlang 18, обработка целочисленных диапазонов выполняется erl_types:t_from_range/2, Как вы можете видеть, существует много обобщений, чтобы получить "безопасную" избыточную приближение диапазона.

Если вы пытались ?USE_UNSAFE_RANGES (см. код) вполне вероятно, что ваша конкретная ошибка будет обнаружена, но за ужасную цену: нативная компиляция и набор рекурсивных целочисленных функций никогда не завершатся!

Причина в том, что анализ типов для рекурсивных функций использует простой подход с фиксированной точкой, когда начальные типы принимают базовые случаи и многократно расширяются с использованием рекурсивных случаев для включения большего количества значений. В какой-то момент чрезмерное приближение должно произойти, если процесс должен завершиться. Вот конкретный пример:

fact(1) -> 1;
fact(N) -> N * fact(N - 1).

Первоначально fact/1 предполагается, что имеет тип fun(none()) -> none(), Используя это для анализа кода, второе предложение "проваливается", и только первое предложение в порядке. Поэтому после первой итерации новый тип fun(1) -> 1, Используя новый тип, можно успешно выполнить второе предложение, расширив тип до fun(1|2) -> 1|2, затем fun(1|2|3) -> 1|2|6 это продолжается до ?SET_LIMIT достигается в этом случае t_from_range перестает использовать отдельные значения и тип становится fun(1..255) -> pos_integer(), Следующая итерация расширяется 1..255 в pos_integer() а потом fun(pos_integer()) -> pos_integer() это точка фиксации!

Ниже следует неправильный ответ (поясняется первый комментарий ниже):

Вы должны получить предупреждение для этого кода, если вы используете -Woverspecs вариант. Эта опция не включена по умолчанию, так как Dialyzer работает в предположении, что все в порядке, чтобы чрезмерно приблизить возвращаемые значения функции. В вашем конкретном случае, однако, вы действительно хотите, чтобы любые дополнительные значения генерировали предупреждения.

Другие вопросы по тегам