Tricking dialyzer with an opaque type

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Tricking dialyzer with an opaque type

Paul Guyot
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Dániel Szoboszlay

Why don't you simply run Dialyzer on a build made without your parse transform? It could even verify the internals of f().

Daniel


On Sun, 25 Jun 2017, 18:56 Paul Guyot, <[hidden email]> wrote:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Tobias Lindahl-4
In reply to this post by Paul Guyot
It seems to me that the gb_sets:from_list/1 should give the correct type for your function even if the spec is not taken into account.

In that case, the value you are getting warnings for comes from somewhere else. Could it be that you are deconstructing the opaque type somewhere?


2017-06-25 18:56 GMT+02:00 Paul Guyot <[hidden email]>:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Alex S.
he is constructing it, after parse transform takes place.
30 июня 2017 г., в 14:27, Tobias Lindahl <[hidden email]> написал(а):

It seems to me that the gb_sets:from_list/1 should give the correct type for your function even if the spec is not taken into account.

In that case, the value you are getting warnings for comes from somewhere else. Could it be that you are deconstructing the opaque type somewhere?


2017-06-25 18:56 GMT+02:00 Paul Guyot <[hidden email]>:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Paul Guyot
In reply to this post by Dániel Szoboszlay
Dániel,

Thank you for your reply. Indeed, the drawback of my approach is that the internals of f() are not checked, although this could be done by keeping (and exporting) the function under another name.
dialyzer is ran as part of the integration process and the code is only meant to be executed at compile time.

Paul

On 28 Jun 2017, at 14:54, Dániel Szoboszlay <[hidden email]> wrote:

Why don't you simply run Dialyzer on a build made without your parse transform? It could even verify the internals of f().

Daniel


On Sun, 25 Jun 2017, 18:56 Paul Guyot, <[hidden email]> wrote:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Paul Guyot
In reply to this post by Alex S.
Alex, Tobias,

Indeed, the function constructs the set using gb_sets API and then the result is embedded in the module with erl_parse:abstract/1.
The current solution consists in adding a call to an identity/1 function in the generated replacement code. This function is exported from the parse transform module of type fun(any()) -> any(). Since the parse transform is in another application, dialyzer seems to take its specification for granted (?). It's a cheaper equivalent of binary_to_term(term_to_binary(V)), although not free (it's still a remote call).

Paul

On 30 Jun 2017, at 15:29, Alex S. <[hidden email]> wrote:

he is constructing it, after parse transform takes place.
30 июня 2017 г., в 14:27, Tobias Lindahl <[hidden email]> написал(а):

It seems to me that the gb_sets:from_list/1 should give the correct type for your function even if the spec is not taken into account.

In that case, the value you are getting warnings for comes from somewhere else. Could it be that you are deconstructing the opaque type somewhere?


2017-06-25 18:56 GMT+02:00 Paul Guyot <[hidden email]>:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Tricking dialyzer with an opaque type

Tobias Lindahl-4


2017-06-30 15:50 GMT+02:00 Paul Guyot <[hidden email]>:
Alex, Tobias,

Indeed, the function constructs the set using gb_sets API and then the result is embedded in the module with erl_parse:abstract/1.
The current solution consists in adding a call to an identity/1 function in the generated replacement code. This function is exported from the parse transform module of type fun(any()) -> any(). Since the parse transform is in another application, dialyzer seems to take its specification for granted (?). It's a cheaper equivalent of binary_to_term(term_to_binary(V)), although not free (it's still a remote call).

Sorry, I misunderstood.

If you are worried about the remote call, you can probably achieve the same thing by having a local call and exporting the function. You need the export to confuse Dialyzer enough to label it as any().
 

Paul

On 30 Jun 2017, at 15:29, Alex S. <[hidden email]> wrote:

he is constructing it, after parse transform takes place.
30 июня 2017 г., в 14:27, Tobias Lindahl <[hidden email]> написал(а):

It seems to me that the gb_sets:from_list/1 should give the correct type for your function even if the spec is not taken into account.

In that case, the value you are getting warnings for comes from somewhere else. Could it be that you are deconstructing the opaque type somewhere?


2017-06-25 18:56 GMT+02:00 Paul Guyot <[hidden email]>:
Hello,

I do have a parse transform that replaces the body of a 0-arity function with its result, as evaluated at compile time.
I am looking for a way to avoid an opaque violation warning from dialyzer when this function returns, say, a gb_sets:set(). The spec is properly copied into the parsed tree, but dialyzer just ignores it.

Typically, such a function would load data from a file and create a gb_sets:set() from this data.

-spec f() -> gb_sets:set(unicode:unicode_binary()).
f() ->
        {ok, Content} = file:read_file(?FILENAME),
        List0 = binary:split(Content, <<"\n">>, [global]),
        List1 = lists:filter(fun(W) -> W =/= <<>> end, List0),
        gb_sets:from_list(List1).

With the parse_transform, dialyzer complains on usage, e.g. :

[warning] some_module.erl:123 the call gb_sets:add(<VALUE>,Var::{1..1114111,{_,_,_}}) does not have an opaque term of type gb_sets:set(_) as 2nd argument

Yet, of course, some_module.erl does not violate the opacity of gb_sets:set() itself.
I can trick dialyzer with an expensive identity function:

        gb_sets:add(Value, binary_to_term(term_to_binary(Var)))

Any better idea?

Paul
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Loading...