{"action":"created","comment":{"url":"https://api.github.com/repos/josefs/Gradualizer/pulls/comments/232693021","pull_request_review_id":173944394,"id":232693021,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzMjY5MzAyMQ==","diff_hunk":"@@ -1968,44 +2013,151 @@ do_type_check_expr_in(Env, ResTy, {'try', _, Block, CaseCs, CatchCs, AfterBlock}\n \n \n type_check_arith_op_in(Env, ResTy, Op, P, Arg1, Arg2) ->\n-    case subtype(ResTy, {type, erl_anno:new(0), 'number', []}, Env#env.tenv) of\n-\t{true, Cs} ->\n-\t  {VarBinds1, Cs1} = type_check_expr_in(Env, ResTy, Arg1),\n-\t  {VarBinds2, Cs2} = type_check_expr_in(Env, ResTy, Arg2),\n-\t  {union_var_binds([VarBinds1, VarBinds2])\n-\t  ,constraints:combine([Cs, Cs1, Cs2])};\n-\tfalse ->\n-\t  throw({type_error, arith_error, Op, P, ResTy})\n-    end.\n+    type_check_arith_op_in(Env, number, ResTy, Op, P, Arg1, Arg2).\n+\n type_check_int_op_in(Env, ResTy, Op, P, Arg1, Arg2) ->\n-    case subtype(ResTy, {type, erl_anno:new(0), 'integer', []}, Env#env.tenv) of\n-\t{true, Cs} ->\n-\t  {VarBinds1, Cs1} = type_check_expr_in(Env, ResTy, Arg1),\n-\t  {VarBinds2, Cs2} = type_check_expr_in(Env, ResTy, Arg2),\n-\t  {union_var_binds([VarBinds1, VarBinds2])\n-\t  ,constraints:combine([Cs, Cs1, Cs2])};\n-\tfalse ->\n-\t  throw({type_error, int_error, Op, P, ResTy})\n+    type_check_arith_op_in(Env, integer, ResTy, Op, P, Arg1, Arg2).\n+\n+type_check_arith_op_in(Env, Kind, ResTy, Op, P, Arg1, Arg2) ->\n+    ResTy1 = glb(type(Kind), ResTy, Env#env.tenv),\n+    IsNone =\n+        case ResTy1 of\n+            %% TODO: allow none() if checking against none()? Not clear that\n+            %% this is sensible, since in that case you'd like to only require\n+            %% *one* of the arguments to be none(), not both.\n+            {type, _, none, []} -> true;\n+            _ -> false\n+        end,\n+    case IsNone of\n+        false ->\n+            case arith_op_arg_types(Op, ResTy1) of\n+                {ArgTy1, ArgTy2} ->\n+                    {VarBinds1, Cs1} = type_check_expr_in(Env, ArgTy1, Arg1),\n+                    {VarBinds2, Cs2} = type_check_expr_in(Env, ArgTy2, Arg2),\n+                    {union_var_binds([VarBinds1, VarBinds2]),\n+                     constraints:combine([Cs1, Cs2])};\n+                false ->\n+                    throw({type_error, arith_type_too_precise, Op, P, ResTy1})\n+            end;\n+        true ->\n+            Tag = if Kind == integer -> int_error;\n+                     true            -> arith_error end,\n+            throw({type_error, Tag, Op, P, ResTy})\n     end.\n+\n+%% What types should be pushed into the arguments if checking an operator\n+%% application against a given type.\n+\n+%% any() is always fine\n+arith_op_arg_types(_Op, Ty = {type, _, any, []}) ->\n+    {Ty, Ty};\n+\n+%% '/' can't produce an integer type\n+arith_op_arg_types('/', Ty) when ?is_int_type(Ty) ->\n+    false;\n+\n+%% integer() is closed under all operators except '/'\n+arith_op_arg_types(_, Ty = {type, _, integer, []}) ->\n+    {Ty, Ty};\n+\n+%% float() is closed under non-integer-exclusive operations and accepts\n+%% any number() for '/'.\n+%% Some precision lost: if at least one argument is a float() the other can\n+%% be integer().\n+arith_op_arg_types(Op, Ty = {type, _, float, []}) ->\n+    case Op of\n+        _ when Op == '+'; Op == '*'; Op == '-' ->\n+            {Ty, Ty};\n+        '/' -> {type(number), type(number)};\n+        _   -> false\n+    end;\n+\n+%% Singleton types are not closed under any operations\n+arith_op_arg_types(_, {T, _, _}) when T == integer; T == float ->\n+    false;\n+\n+%% pos_integer() is closed under '+',  '*', and 'bor'\n+arith_op_arg_types(Op, Ty = {type, _, pos_integer, []}) ->\n+    case lists:member(Op, ['+', '*', 'bor']) of\n+        true -> {Ty, Ty};","path":"src/typechecker.erl","position":225,"original_position":225,"commit_id":"08165923349fcce84b5489595d863ffbda109f61","original_commit_id":"08165923349fcce84b5489595d863ffbda109f61","user":{"login":"UlfNorell","id":447950,"node_id":"MDQ6VXNlcjQ0Nzk1MA==","avatar_url":"https://avatars0.githubusercontent.com/u/447950?v=4","gravatar_id":"","url":"https://api.github.com/users/UlfNorell","html_url":"https://github.com/UlfNorell","followers_url":"https://api.github.com/users/UlfNorell/followers","following_url":"https://api.github.com/users/UlfNorell/following{/other_user}","gists_url":"https://api.github.com/users/UlfNorell/gists{/gist_id}","starred_url":"https://api.github.com/users/UlfNorell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UlfNorell/subscriptions","organizations_url":"https://api.github.com/users/UlfNorell/orgs","repos_url":"https://api.github.com/users/UlfNorell/repos","events_url":"https://api.github.com/users/UlfNorell/events{/privacy}","received_events_url":"https://api.github.com/users/UlfNorell/received_events","type":"User","site_admin":false},"body":"This would require the same machinery as `integer() * float() :: float()`.","created_at":"2018-11-12T15:08:21Z","updated_at":"2018-11-12T15:08:22Z","html_url":"https://github.com/josefs/Gradualizer/pull/83#discussion_r232693021","pull_request_url":"https://api.github.com/repos/josefs/Gradualizer/pulls/83","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/comments/232693021"},"html":{"href":"https://github.com/josefs/Gradualizer/pull/83#discussion_r232693021"},"pull_request":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/83"}},"in_reply_to_id":232669999},"pull_request":{"url":"https://api.github.com/repos/josefs/Gradualizer/pulls/83","id":230124178,"node_id":"MDExOlB1bGxSZXF1ZXN0MjMwMTI0MTc4","html_url":"https://github.com/josefs/Gradualizer/pull/83","diff_url":"https://github.com/josefs/Gradualizer/pull/83.diff","patch_url":"https://github.com/josefs/Gradualizer/pull/83.patch","issue_url":"https://api.github.com/repos/josefs/Gradualizer/issues/83","number":83,"state":"open","locked":false,"title":"Issue 72","user":{"login":"UlfNorell","id":447950,"node_id":"MDQ6VXNlcjQ0Nzk1MA==","avatar_url":"https://avatars0.githubusercontent.com/u/447950?v=4","gravatar_id":"","url":"https://api.github.com/users/UlfNorell","html_url":"https://github.com/UlfNorell","followers_url":"https://api.github.com/users/UlfNorell/followers","following_url":"https://api.github.com/users/UlfNorell/following{/other_user}","gists_url":"https://api.github.com/users/UlfNorell/gists{/gist_id}","starred_url":"https://api.github.com/users/UlfNorell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UlfNorell/subscriptions","organizations_url":"https://api.github.com/users/UlfNorell/orgs","repos_url":"https://api.github.com/users/UlfNorell/repos","events_url":"https://api.github.com/users/UlfNorell/events{/privacy}","received_events_url":"https://api.github.com/users/UlfNorell/received_events","type":"User","site_admin":false},"body":"Work in progress on #72. Do not merge, but please offer feedback.\r\n\r\nStill to do:\r\n- [ ] List operations (`++` and `--`)\r\n- [ ] Inference mode (`type_check_expr`)\r\n- [ ] Finish `glb` (at the very least, needs to handle lists for list operations)\r\n- [ ] Tests\r\n- [ ] Memoisation in `glb` (currently loops on untagged recursive types)\r\n\r\nSome food for discussion\r\n- I changed the rule for `andalso` (and `orelse`) to\r\n  ```\r\n  subtype(boolean(), R)\r\n  A :: boolean()\r\n  B :: R\r\n  ---\r\n  A andalso B :: R\r\n  ```\r\n  allowing an arbitrary type in the second argument. This may or may not be a good idea, but it's safe.\r\n- I implemented some cleverness for arithmetic on ranged types:\r\n  ```\r\n  op in {band, bor, bxor, bsr}\r\n  A :: 0..2^(N-1)\r\n  B :: 0..2^(N-1)\r\n  ---\r\n  A op B :: 0..2^(N-1)\r\n  ```\r\n  and\r\n  ```\r\n  A :: non_neg_integer()\r\n  B :: 0..N+1\r\n  ---\r\n  A rem B :: 0..N\r\n  ```\r\n  This lets you work with fixed-width word types in a typed manned, which I think is nice. More could be added, but I'm not sure there's a nice non-ad hoc amount of cleverness to add that won't just make the type system unpredictable.\r\n- I haven't looked into how type variables work (are they rigid or flexible?) and consequently ignore them in `glb`.\r\n\r\n","created_at":"2018-11-12T12:52:21Z","updated_at":"2018-11-12T15:08:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"693252298a899232e520edb84466b346d5eceb50","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/josefs/Gradualizer/pulls/83/commits","review_comments_url":"https://api.github.com/repos/josefs/Gradualizer/pulls/83/comments","review_comment_url":"https://api.github.com/repos/josefs/Gradualizer/pulls/comments{/number}","comments_url":"https://api.github.com/repos/josefs/Gradualizer/issues/83/comments","statuses_url":"https://api.github.com/repos/josefs/Gradualizer/statuses/08165923349fcce84b5489595d863ffbda109f61","head":{"label":"UlfNorell:issue72","ref":"issue72","sha":"08165923349fcce84b5489595d863ffbda109f61","user":{"login":"UlfNorell","id":447950,"node_id":"MDQ6VXNlcjQ0Nzk1MA==","avatar_url":"https://avatars0.githubusercontent.com/u/447950?v=4","gravatar_id":"","url":"https://api.github.com/users/UlfNorell","html_url":"https://github.com/UlfNorell","followers_url":"https://api.github.com/users/UlfNorell/followers","following_url":"https://api.github.com/users/UlfNorell/following{/other_user}","gists_url":"https://api.github.com/users/UlfNorell/gists{/gist_id}","starred_url":"https://api.github.com/users/UlfNorell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UlfNorell/subscriptions","organizations_url":"https://api.github.com/users/UlfNorell/orgs","repos_url":"https://api.github.com/users/UlfNorell/repos","events_url":"https://api.github.com/users/UlfNorell/events{/privacy}","received_events_url":"https://api.github.com/users/UlfNorell/received_events","type":"User","site_admin":false},"repo":{"id":156221694,"node_id":"MDEwOlJlcG9zaXRvcnkxNTYyMjE2OTQ=","name":"Gradualizer","full_name":"UlfNorell/Gradualizer","private":false,"owner":{"login":"UlfNorell","id":447950,"node_id":"MDQ6VXNlcjQ0Nzk1MA==","avatar_url":"https://avatars0.githubusercontent.com/u/447950?v=4","gravatar_id":"","url":"https://api.github.com/users/UlfNorell","html_url":"https://github.com/UlfNorell","followers_url":"https://api.github.com/users/UlfNorell/followers","following_url":"https://api.github.com/users/UlfNorell/following{/other_user}","gists_url":"https://api.github.com/users/UlfNorell/gists{/gist_id}","starred_url":"https://api.github.com/users/UlfNorell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UlfNorell/subscriptions","organizations_url":"https://api.github.com/users/UlfNorell/orgs","repos_url":"https://api.github.com/users/UlfNorell/repos","events_url":"https://api.github.com/users/UlfNorell/events{/privacy}","received_events_url":"https://api.github.com/users/UlfNorell/received_events","type":"User","site_admin":false},"html_url":"https://github.com/UlfNorell/Gradualizer","description":null,"fork":true,"url":"https://api.github.com/repos/UlfNorell/Gradualizer","forks_url":"https://api.github.com/repos/UlfNorell/Gradualizer/forks","keys_url":"https://api.github.com/repos/UlfNorell/Gradualizer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/UlfNorell/Gradualizer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/UlfNorell/Gradualizer/teams","hooks_url":"https://api.github.com/repos/UlfNorell/Gradualizer/hooks","issue_events_url":"https://api.github.com/repos/UlfNorell/Gradualizer/issues/events{/number}","events_url":"https://api.github.com/repos/UlfNorell/Gradualizer/events","assignees_url":"https://api.github.com/repos/UlfNorell/Gradualizer/assignees{/user}","branches_url":"https://api.github.com/repos/UlfNorell/Gradualizer/branches{/branch}","tags_url":"https://api.github.com/repos/UlfNorell/Gradualizer/tags","blobs_url":"https://api.github.com/repos/UlfNorell/Gradualizer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/UlfNorell/Gradualizer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/UlfNorell/Gradualizer/git/refs{/sha}","trees_url":"https://api.github.com/repos/UlfNorell/Gradualizer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/UlfNorell/Gradualizer/statuses/{sha}","languages_url":"https://api.github.com/repos/UlfNorell/Gradualizer/languages","stargazers_url":"https://api.github.com/repos/UlfNorell/Gradualizer/stargazers","contributors_url":"https://api.github.com/repos/UlfNorell/Gradualizer/contributors","subscribers_url":"https://api.github.com/repos/UlfNorell/Gradualizer/subscribers","subscription_url":"https://api.github.com/repos/UlfNorell/Gradualizer/subscription","commits_url":"https://api.github.com/repos/UlfNorell/Gradualizer/commits{/sha}","git_commits_url":"https://api.github.com/repos/UlfNorell/Gradualizer/git/commits{/sha}","comments_url":"https://api.github.com/repos/UlfNorell/Gradualizer/comments{/number}","issue_comment_url":"https://api.github.com/repos/UlfNorell/Gradualizer/issues/comments{/number}","contents_url":"https://api.github.com/repos/UlfNorell/Gradualizer/contents/{+path}","compare_url":"https://api.github.com/repos/UlfNorell/Gradualizer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/UlfNorell/Gradualizer/merges","archive_url":"https://api.github.com/repos/UlfNorell/Gradualizer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/UlfNorell/Gradualizer/downloads","issues_url":"https://api.github.com/repos/UlfNorell/Gradualizer/issues{/number}","pulls_url":"https://api.github.com/repos/UlfNorell/Gradualizer/pulls{/number}","milestones_url":"https://api.github.com/repos/UlfNorell/Gradualizer/milestones{/number}","notifications_url":"https://api.github.com/repos/UlfNorell/Gradualizer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/UlfNorell/Gradualizer/labels{/name}","releases_url":"https://api.github.com/repos/UlfNorell/Gradualizer/releases{/id}","deployments_url":"https://api.github.com/repos/UlfNorell/Gradualizer/deployments","created_at":"2018-11-05T13:24:25Z","updated_at":"2018-11-05T13:24:27Z","pushed_at":"2018-11-12T12:29:56Z","git_url":"git://github.com/UlfNorell/Gradualizer.git","ssh_url":"git@github.com:UlfNorell/Gradualizer.git","clone_url":"https://github.com/UlfNorell/Gradualizer.git","svn_url":"https://github.com/UlfNorell/Gradualizer","homepage":null,"size":443,"stargazers_count":0,"watchers_count":0,"language":"Erlang","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"josefs:master","ref":"master","sha":"b27e39fd9e5c1e2cb86c6a135c631dee5c410b8f","user":{"login":"josefs","id":152020,"node_id":"MDQ6VXNlcjE1MjAyMA==","avatar_url":"https://avatars0.githubusercontent.com/u/152020?v=4","gravatar_id":"","url":"https://api.github.com/users/josefs","html_url":"https://github.com/josefs","followers_url":"https://api.github.com/users/josefs/followers","following_url":"https://api.github.com/users/josefs/following{/other_user}","gists_url":"https://api.github.com/users/josefs/gists{/gist_id}","starred_url":"https://api.github.com/users/josefs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/josefs/subscriptions","organizations_url":"https://api.github.com/users/josefs/orgs","repos_url":"https://api.github.com/users/josefs/repos","events_url":"https://api.github.com/users/josefs/events{/privacy}","received_events_url":"https://api.github.com/users/josefs/received_events","type":"User","site_admin":false},"repo":{"id":108764455,"node_id":"MDEwOlJlcG9zaXRvcnkxMDg3NjQ0NTU=","name":"Gradualizer","full_name":"josefs/Gradualizer","private":false,"owner":{"login":"josefs","id":152020,"node_id":"MDQ6VXNlcjE1MjAyMA==","avatar_url":"https://avatars0.githubusercontent.com/u/152020?v=4","gravatar_id":"","url":"https://api.github.com/users/josefs","html_url":"https://github.com/josefs","followers_url":"https://api.github.com/users/josefs/followers","following_url":"https://api.github.com/users/josefs/following{/other_user}","gists_url":"https://api.github.com/users/josefs/gists{/gist_id}","starred_url":"https://api.github.com/users/josefs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/josefs/subscriptions","organizations_url":"https://api.github.com/users/josefs/orgs","repos_url":"https://api.github.com/users/josefs/repos","events_url":"https://api.github.com/users/josefs/events{/privacy}","received_events_url":"https://api.github.com/users/josefs/received_events","type":"User","site_admin":false},"html_url":"https://github.com/josefs/Gradualizer","description":null,"fork":false,"url":"https://api.github.com/repos/josefs/Gradualizer","forks_url":"https://api.github.com/repos/josefs/Gradualizer/forks","keys_url":"https://api.github.com/repos/josefs/Gradualizer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/josefs/Gradualizer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/josefs/Gradualizer/teams","hooks_url":"https://api.github.com/repos/josefs/Gradualizer/hooks","issue_events_url":"https://api.github.com/repos/josefs/Gradualizer/issues/events{/number}","events_url":"https://api.github.com/repos/josefs/Gradualizer/events","assignees_url":"https://api.github.com/repos/josefs/Gradualizer/assignees{/user}","branches_url":"https://api.github.com/repos/josefs/Gradualizer/branches{/branch}","tags_url":"https://api.github.com/repos/josefs/Gradualizer/tags","blobs_url":"https://api.github.com/repos/josefs/Gradualizer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/josefs/Gradualizer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/josefs/Gradualizer/git/refs{/sha}","trees_url":"https://api.github.com/repos/josefs/Gradualizer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/josefs/Gradualizer/statuses/{sha}","languages_url":"https://api.github.com/repos/josefs/Gradualizer/languages","stargazers_url":"https://api.github.com/repos/josefs/Gradualizer/stargazers","contributors_url":"https://api.github.com/repos/josefs/Gradualizer/contributors","subscribers_url":"https://api.github.com/repos/josefs/Gradualizer/subscribers","subscription_url":"https://api.github.com/repos/josefs/Gradualizer/subscription","commits_url":"https://api.github.com/repos/josefs/Gradualizer/commits{/sha}","git_commits_url":"https://api.github.com/repos/josefs/Gradualizer/git/commits{/sha}","comments_url":"https://api.github.com/repos/josefs/Gradualizer/comments{/number}","issue_comment_url":"https://api.github.com/repos/josefs/Gradualizer/issues/comments{/number}","contents_url":"https://api.github.com/repos/josefs/Gradualizer/contents/{+path}","compare_url":"https://api.github.com/repos/josefs/Gradualizer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/josefs/Gradualizer/merges","archive_url":"https://api.github.com/repos/josefs/Gradualizer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/josefs/Gradualizer/downloads","issues_url":"https://api.github.com/repos/josefs/Gradualizer/issues{/number}","pulls_url":"https://api.github.com/repos/josefs/Gradualizer/pulls{/number}","milestones_url":"https://api.github.com/repos/josefs/Gradualizer/milestones{/number}","notifications_url":"https://api.github.com/repos/josefs/Gradualizer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/josefs/Gradualizer/labels{/name}","releases_url":"https://api.github.com/repos/josefs/Gradualizer/releases{/id}","deployments_url":"https://api.github.com/repos/josefs/Gradualizer/deployments","created_at":"2017-10-29T19:30:20Z","updated_at":"2018-11-11T18:17:38Z","pushed_at":"2018-11-12T12:52:22Z","git_url":"git://github.com/josefs/Gradualizer.git","ssh_url":"git@github.com:josefs/Gradualizer.git","clone_url":"https://github.com/josefs/Gradualizer.git","svn_url":"https://github.com/josefs/Gradualizer","homepage":null,"size":437,"stargazers_count":118,"watchers_count":118,"language":"Erlang","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"archived":false,"open_issues_count":26,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":7,"open_issues":26,"watchers":118,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/83"},"html":{"href":"https://github.com/josefs/Gradualizer/pull/83"},"issue":{"href":"https://api.github.com/repos/josefs/Gradualizer/issues/83"},"comments":{"href":"https://api.github.com/repos/josefs/Gradualizer/issues/83/comments"},"review_comments":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/83/comments"},"review_comment":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/josefs/Gradualizer/pulls/83/commits"},"statuses":{"href":"https://api.github.com/repos/josefs/Gradualizer/statuses/08165923349fcce84b5489595d863ffbda109f61"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"UlfNorell"}}