Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lift restrictions for matching of binaries and maps #6415

Merged

Commits on Dec 13, 2022

  1. Lift restrictions for matching of binaries and maps

    There has always been an implementation limitation for matching
    of binaries (for technical reasons). For example:
    
        foo(Bin) ->
            <<A:8>> = <<X:4,Y:4>> = Bin,
            {A,X,Y}.
    
    This would fail to compile with the following message:
    
        t.erl:5:5: binary patterns cannot be matched in parallel using '='
        %    5|     <<A:8>> = <<X:4,Y:4>> = Bin,
        %     |     ^
    
    This commit lifts this restriction, making the example legal.
    
    A restriction for map matching is also lifted, but before we can
    describe that, we'll need a digression to talk about the `=` operator.
    
    The `=` operator can be used for two similar but slightly differently
    purposes.
    
    When used in a pattern in a clause, for example in a function head,
    both the left-hand and right-hand side operands must be patterns:
    
        Pattern1 = Pattern2
    
    For example:
    
        bar(#{a := A} = #{b := B}) -> {A, B}.
    
    The following example will not compile because the right-hand side
    is not a pattern but an expression:
    
        wrong(#{a := A} = #{b => B}) -> {A, B}.
    
        t.erl:4:23: illegal pattern
        %    4| wrong(#{a := A} = #{b => B}) -> {A, B}.
        %     |                       ^
    
    Used in this context, the `=` operator does not imply that the two
    patterns are matched in any particular order. Attempting to use a
    variable matched out on the left-hand side on the right-hand side, or
    vice versa, will fail:
    
        also_wrong1(#{B := A} = #{b := B}) -> {A,B}.
        also_wrong2(#{a := A} = #{A := B}) -> {A,B}.
    
        t.erl:6:15: variable 'B' is unbound
        %    6| also_wrong1(#{B := A} = #{b := B}) -> {A,B}.
        %     |               ^
    
        t.erl:7:27: variable 'A' is unbound
        %    7| also_wrong2(#{a := A} = #{A := B}) -> {A,B}.
        %     |                           ^
    
    The other way to use `=` is in a function body. Used in this way,
    the right-hand side must be an expression:
    
        Pattern = Expression
    
    For example:
    
        foobar(Value) ->
            #{a := A} = #{a => Value},
            A.
    
    Used in this context, the right-hand side of `=` must **not** be a pattern:
    
        illegal_foobar(Value) ->
            #{a := A} = #{a := Value},
            A.
    
        t.erl:18:21: only association operators '=>' are allowed in map construction
        %   18|     #{a := A} = #{a := Value},
        %     |                     ^
    
    When used in a body context, the value of the `=` operator is the
    value of its right-hand side operand. When multiple `=` operators are
    combined, they are evaluted from right to left. That means that any
    number of patterns can be matched at once:
    
        Pattern1 = Pattern2 = ... = PatternN = Expr
    
    which is equivalent to:
    
        Var = Expr
        PatternN = Var
           .
           .
           .
        Pattern2 = Var
        Pattern1 = Var
    
    Given that there is a well-defined evaluation order from right to
    left, one would expect that the following example would be legal:
    
        baz(M) ->
            #{K := V} = #{k := K} = M,
            V.
    
    It is not. In Erlang/OTP 25 or earlier, the compilation fails with the
    following message:
    
        t.erl:28:7: variable 'K' is unbound
        %   28|     #{K := V} = #{k := K} = M,
        %     |       ^
    
    That restriction is now lifted, making the example legal.
    
    Closes erlang#6348
    Closes erlang#6444
    Closes erlang#6467
    bjorng committed Dec 13, 2022
    Configuration menu
    Copy the full SHA
    6a9ebe6 View commit details
    Browse the repository at this point in the history