Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:26
erlang
1421-Refine-types-for-min-2-and-max-2.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 1421-Refine-types-for-min-2-and-max-2.patch of Package erlang
From 741d65ff54a728ea37fe0930139bde47fbca61c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Sat, 10 Jun 2023 06:05:27 +0200 Subject: [PATCH] Refine types for `min/2` and `max/2` For this example: clamped_add(A) when is_integer(A) -> min(max(A, 0), 10) + 100. the compiler will now be able to infer the range 1 through 10 for the `A` variable when it is used by the plus operator: {gc_bif,'+',{f,0},1,[{tr,{x,0},{t_integer,{0,10}}},{integer,100}],{x,0}}. --- lib/compiler/src/beam_bounds.erl | 21 ++++---- lib/compiler/src/beam_call_types.erl | 68 +++++++++++++++++++------ lib/compiler/test/beam_bounds_SUITE.erl | 8 +++ lib/compiler/test/bif_SUITE.erl | 54 +++++++++++++++++++- 4 files changed, 121 insertions(+), 30 deletions(-) diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl index 2df33a2d5e..01a121780b 100644 --- a/lib/compiler/src/beam_bounds.erl +++ b/lib/compiler/src/beam_bounds.erl @@ -222,19 +222,13 @@ bounds('bsl', R1, R2) -> any end; bounds(max, R1, R2) -> - case {R1,R2} of - {{A,B},{C,D}} -> - normalize({inf_max(A, C),inf_max(B, D)}); - {_,_} -> - any - end; + {A,B} = expand(R1), + {C,D} = expand(R2), + normalize({inf_max(A, C),inf_max(B, D)}); bounds(min, R1, R2) -> - case {R1,R2} of - {{A,B},{C,D}} -> - normalize({inf_min(A, C),inf_min(B, D)}); - {_,_} -> - any - end. + {A,B} = expand(R1), + {C,D} = expand(R2), + normalize({inf_min(A, C),inf_min(B, D)}). -spec relop(relop(), range(), range()) -> bool_result(). @@ -511,6 +505,9 @@ infer_relop_types_1('>', {A,B}, {C,D}) -> %%% need any special handling of '+inf'. %%% +expand(any) -> {'-inf','+inf'}; +expand({_,_}=R) -> R. + normalize({'-inf','-inf'}) -> {'-inf',-1}; normalize({'-inf','+inf'}) -> diff --git a/lib/compiler/src/beam_call_types.erl b/lib/compiler/src/beam_call_types.erl index 4adfad3b2d..6fc6086651 100644 --- a/lib/compiler/src/beam_call_types.erl +++ b/lib/compiler/src/beam_call_types.erl @@ -618,25 +618,61 @@ types(erlang, make_fun, [_,_,Arity0]) -> end, sub_unsafe(Type, [#t_atom{}, #t_atom{}, #t_integer{}]); -types(erlang, Op, [LHS,RHS]) when Op =:= min; Op =:= max -> - R1 = get_range(LHS), - R2 = get_range(RHS), - R = beam_bounds:bounds(Op, R1, R2), - - %% We cannot use mixed_arith_types/1 here as we will return either argument - %% unchanged. The result will not be converted to a float if one of the - %% arguments is a float. - %% - %% 1235.0 = 1 + 1234.0 - %% 1 = erlang:min(1, 1234.0) +types(erlang, min, [LHS,RHS]) -> + R1 = case get_range(meet(LHS, #t_number{})) of + none -> any; + R10 -> R10 + end, + R2 = case get_range(meet(RHS, #t_number{})) of + none -> any; + R20 -> R20 + end, + R = beam_bounds:bounds(min, R1, R2), RetType = case {LHS, RHS} of - {#t_integer{}, #t_integer{}} -> #t_integer{elements=R}; - {#t_integer{}, #t_number{}} -> #t_number{elements=R}; - {#t_number{}, #t_integer{}} -> #t_number{elements=R}; - {#t_number{}, #t_number{}} -> #t_number{elements=R}; - {_, _} -> join(LHS, RHS) + {#t_integer{}, #t_integer{}} -> + #t_integer{elements=R}; + {#t_integer{}, _} -> + #t_number{elements=R}; + {#t_number{}, _} -> + #t_number{elements=R}; + {#t_float{}, _} -> + #t_number{elements=R}; + {_, #t_integer{}} -> + #t_number{elements=R}; + {_, #t_number{}} -> + #t_number{elements=R}; + {_, #t_float{}} -> + #t_number{elements=R}; + {_, _} -> + join(LHS, RHS) end, + sub_unsafe(RetType, [any, any]); +types(erlang, max, [LHS,RHS]) -> + RetType = + case get_range(LHS, RHS, #t_number{}) of + {_, none, _} -> + join(LHS, RHS); + {_, _, none} -> + join(LHS, RHS); + {_, R1, R2} -> + R = beam_bounds:bounds(max, R1, R2), + case {LHS, RHS} of + {#t_integer{}, #t_integer{}} -> + #t_integer{elements=R}; + {any, #t_integer{elements={Min,_}}} when is_integer(Min) -> + beam_types:subtract(any, #t_number{elements={'-inf',Min}}); + {#t_integer{elements={Min,_}}, any} when is_integer(Min) -> + beam_types:subtract(any, #t_number{elements={'-inf',Min}}); + {_, _} -> + case join(LHS, RHS) of + #t_number{} -> + #t_number{elements=R}; + Join -> + Join + end + end + end, sub_unsafe(RetType, [any, any]); types(erlang, Name, Args) -> diff --git a/lib/compiler/test/beam_bounds_SUITE.erl b/lib/compiler/test/beam_bounds_SUITE.erl index 424a8b0a84..65734986d5 100644 --- a/lib/compiler/test/beam_bounds_SUITE.erl +++ b/lib/compiler/test/beam_bounds_SUITE.erl @@ -287,6 +287,10 @@ min_bounds(_Config) -> {1,100} = min_bounds({1,100}, {100,'+inf'}), {100,200} = min_bounds({150,200}, {100,'+inf'}), + {'-inf',10} = min_bounds({1,10}, any), + any = min_bounds({1,'+inf'}, any), + {'-inf',777} = min_bounds(any, {'-inf',777}), + ok. min_bounds(R1, R2) -> @@ -309,6 +313,10 @@ max_bounds(_Config) -> {100,'+inf'} = max_bounds({1,100}, {100,'+inf'}), {150,'+inf'} = max_bounds({150,200}, {100,'+inf'}), + {1,'+inf'} = max_bounds({1,99}, any), + {10,'+inf'} = max_bounds({10,'+inf'}, any), + any = max_bounds({'-inf',70}, any), + ok. max_bounds(R1, R2) -> diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl index e58db29114..c3610117c3 100644 --- a/lib/compiler/test/bif_SUITE.erl +++ b/lib/compiler/test/bif_SUITE.erl @@ -45,6 +45,7 @@ groups() -> ]}]. init_per_suite(Config) -> + _ = id(Config), test_lib:recompile(?MODULE), Config. @@ -208,6 +209,36 @@ min_max(_Config) -> true = bool_max_true(True, False), true = bool_max_true(True, True), + 11 = min_increment(100), + 11 = min_increment(10), + 10 = min_increment(9), + 1 = min_increment(0), + 0 = min_increment(-1), + 11 = min_increment(a), + + {42,42} = max_number(id(42)), + {42,42.0} = max_number(id(42.0)), + {-1,1} = max_number(id(-1)), + {-1,1} = max_number(id(-1.0)), + + 100 = int_clamped_add(-1), + 100 = int_clamped_add(0), + 105 = int_clamped_add(5), + 110 = int_clamped_add(10), + 110 = int_clamped_add(11), + + 100 = num_clamped_add(-1), + 100 = num_clamped_add(0), + 105 = num_clamped_add(5), + 110 = num_clamped_add(10), + 110 = num_clamped_add(11), + + 105 = num_clamped_add(5), + 105.0 = num_clamped_add(5.0), + 110 = num_clamped_add(a), + 110 = num_clamped_add({a,b,c}), + 110 = num_clamped_add({a,b,c}), + ok. %% GH-7170: The following functions would cause a crash in @@ -222,8 +253,27 @@ bool_min_true(A, B) when is_boolean(A), is_boolean(B) -> bool_max_false(A, B) when is_boolean(A), is_boolean(B) -> false = max(A, B). -bool_max_true(A, B) when is_boolean(A), is_boolean(B) -> - true = max(A, B). +bool_max_true(A, B) when is_boolean(B) -> + true = max(A, B), + if + is_boolean(A) -> + true = max(A, B) + end. + +max_number(A) -> + Res = {trunc(A), max(A, 1)}, + Res = {trunc(A), max(1, A)}. + +min_increment(A) -> + Res = min(10, A) + 1, + Res = min(A, 10) + 1, + Res = min(id(A), 10) + 1. + +int_clamped_add(A) when is_integer(A) -> + min(max(A, 0), 10) + 100. + +num_clamped_add(A) -> + min(max(A, 0), 10) + 100. %%% %%% Common utilities. -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor