From 50fb72d6a9630cd8feb6ae82a4bafbb42848dfd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muska=C5=82a?= Date: Mon, 27 Jun 2022 18:32:48 +0100 Subject: [PATCH 1/3] Introduce the ?TYPE macro It allows explicitly using PropEr's "native types" feature. This is more powerful than the current automatic parse transform-based inference: * it can be used outside of `?FORALL` to produce PropEr types & combine them with other PropEr or native types. * it allows using the "native types" feature with the proper parse transform disabled * it allows expressing more types directly, without creating additional type aliases, for example: `?TYPE(atom() | float())`. The semantics are identical to automatic inference, if the expression was wrapped in a simple `id` type (when the syntax allows expressing such a type). For example: ```erlang -record(foo, {}). -type id(X) :: X. % semantically equivalent definitions: ?FORALL(X, id(#foo{}), Prop). ?FORALL(X, ?TYPE(#foo{}), Prop). ``` --- include/proper_common.hrl | 1 + src/proper_typeserver.erl | 38 ++++++++++++++++++++++++++--------- test/no_transforms.erl | 42 +++++++++++++++++++++++++++++++++++++++ test/proper_tests.erl | 4 +++- 4 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 test/no_transforms.erl diff --git a/include/proper_common.hrl b/include/proper_common.hrl index f92a7262..054b5fbd 100644 --- a/include/proper_common.hrl +++ b/include/proper_common.hrl @@ -61,6 +61,7 @@ proper_types:add_constraint(RawType,fun(X) -> Condition end,true)). -define(SUCHTHATMAYBE(X,RawType,Condition), proper_types:add_constraint(RawType,fun(X) -> Condition end,false)). +-define(TYPE(X), proper_types:native_type(?MODULE, ??X)). %%------------------------------------------------------------------------------ %% Targeted macros diff --git a/src/proper_typeserver.erl b/src/proper_typeserver.erl index c5ea8112..4abe60e6 100644 --- a/src/proper_typeserver.erl +++ b/src/proper_typeserver.erl @@ -27,16 +27,23 @@ %%% %%% PropEr can parse types expressed in Erlang's type language and convert them %%% to its own type format. Such expressions can be used instead of regular type -%%% constructors in the second argument of `?FORALL's. No extra notation is -%%% required; PropEr will detect which calls correspond to native types by -%%% applying a parse transform during compilation. This parse transform is -%%% automatically applied to any module that includes the `proper.hrl' header -%%% file. You can disable this feature by compiling your modules with -%%% `-DPROPER_NO_TRANS'. Note that this will currently also disable the -%%% automatic exporting of properties. +%%% constructors in the second argument of `?FORALL's. Such types can be expressed +%%% in two ways: +%%% +%%% +%%% You can disable the parse transform (and automatic detection of native types) +%%% by compiling your modules with `-DPROPER_NO_TRANS' flag. Note that this will +%%% currently also disable the automatic exporting of properties. %%% -%%% The use of native types in properties is subject to the following usage -%%% rules: +%%% The use of automatically-detected native types in properties is subject +%%% to the following usage rules: %%% %%% +%%% The `?TYPE` macro for explicitly taking advantage of PropEr's native type +%%% support is subject to the following usage rules: +%%% +%%% %%% You can use these functions to try out the type %%% translation subsystem. %%% diff --git a/test/no_transforms.erl b/test/no_transforms.erl new file mode 100644 index 00000000..3fe2f906 --- /dev/null +++ b/test/no_transforms.erl @@ -0,0 +1,42 @@ +%%% -*- coding: utf-8 -*- +%%% -*- erlang-indent-level: 2 -*- +%%% ------------------------------------------------------------------- +%%% Copyright 2010-2011 Manolis Papadakis , +%%% Eirini Arvaniti +%%% and Kostis Sagonas +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see . + +%%% @copyright 2010-2011 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @doc This module tests whether proper works with parse transforms disabled. + +-module(no_transforms). +-export([prop_1/0, prop_2/0]). + +-define(PROPER_NO_TRANS, true). + +-include_lib("proper/include/proper.hrl"). + +-type local_integer() :: integer(). +-type local_float() :: float(). + +prop_1() -> ?FORALL(X, ?TYPE(local_integer() | local_float()), is_number(X)). + +prop_2() -> ?FORALL(X, native_type(), is_integer(X) orelse is_atom(X)). + +native_type() -> + ?TYPE(local_integer() | atom()). diff --git a/test/proper_tests.erl b/test/proper_tests.erl index 6960872c..49e21582 100644 --- a/test/proper_tests.erl +++ b/test/proper_tests.erl @@ -837,7 +837,9 @@ parse_transform_test_() -> ?_assertError(undef, auto_export_test2:prop_1()), ?_assertError(undef, no_native_parse_test:prop_1()), ?_passes(let_tests:prop_1()), - ?_failsWith([3*42], let_tests:prop_2())]. + ?_failsWith([3*42], let_tests:prop_2()), + ?_passes(no_transforms:prop_1()), + ?_passes(no_transforms:prop_2())]. native_type_props_test_() -> [?_passes(?FORALL({X,Y}, {my_native_type(),my_proper_type()}, From 4814f7ed0e98c4003718673fb2cc4fe2ef47a29c Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Wed, 29 Jun 2022 09:31:56 +0300 Subject: [PATCH 2/3] Update proper_typeserver.erl Fix an error in building the documentation and improve the wording. --- src/proper_typeserver.erl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/proper_typeserver.erl b/src/proper_typeserver.erl index 4abe60e6..cd439f78 100644 --- a/src/proper_typeserver.erl +++ b/src/proper_typeserver.erl @@ -161,17 +161,19 @@ %%% %%% %%% -%%% The `?TYPE` macro for explicitly taking advantage of PropEr's native type +%%% The `?TYPE' macro for explicitly taking advantage of PropEr's native type %%% support is subject to the following usage rules: %%%
    %%%
  • It is allowed in any position to produce a PropEr type, including -%%% outside of `?FORALL`.
  • -%%%
  • The same restriction on allowed recursive native types as in `?FORALL` apply.
  • -%%%
  • There's no risk of confusion between expressions and native types, -%%% inside `?TYPE` everything is interpreted as a native type, and as such -%%% `?TYPE([integer()])` will produce an arbitrary integer list.
  • -%%%
  • It is not checked for correct syntax - using invalid syntax can produce -%%% errors when the property is evaluated, which are hard to understand.
  • +%%% outside of `?FORALL'. +%%%
  • The same restriction on allowed recursive native types as in `?FORALL` +%%% apply.
  • +%%%
  • There is no risk of confusion between expressions and native types. +%%% Inside `?TYPE' everything is interpreted as a native type; for example, +%%% `?TYPE([integer()])' will produce an arbitrary integer list.
  • +%%%
  • Its argument is not checked for correct syntax. Using invalid syntax +%%% can result in errors that are hard to understand when the property is +%%% evaluated.
  • %%%
%%% %%% You can use these functions to try out the type From 352a04283a071ebe82f7bc2f6ddad25a8a9b0420 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Wed, 29 Jun 2022 10:25:07 +0300 Subject: [PATCH 3/3] Update proper_typeserver.erl --- src/proper_typeserver.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proper_typeserver.erl b/src/proper_typeserver.erl index cd439f78..2e09a8af 100644 --- a/src/proper_typeserver.erl +++ b/src/proper_typeserver.erl @@ -166,7 +166,7 @@ %%%
    %%%
  • It is allowed in any position to produce a PropEr type, including %%% outside of `?FORALL'.
  • -%%%
  • The same restriction on allowed recursive native types as in `?FORALL` +%%%
  • The same restriction on allowed recursive native types as in `?FORALL' %%% apply.
  • %%%
  • There is no risk of confusion between expressions and native types. %%% Inside `?TYPE' everything is interpreted as a native type; for example,