Skip to content

match expression#303

Open
i582 wants to merge 9 commits intomasterfrom
pmakhnev/match_expression
Open

match expression#303
i582 wants to merge 9 commits intomasterfrom
pmakhnev/match_expression

Conversation

@i582
Copy link
Contributor

@i582 i582 commented Sep 6, 2021

RFC: https://wiki.php.net/rfc/match_expression_v2

The basis is the conversion to rvalue statements list with switch with strict comparisons. For op_switch added is_match flag.

In PHP, a regular switch uses non-strict comparison, which leads to type casts, but the match uses strict comparison, which is why we need a new is_match flag in the op_switch node.

If this flag is set, then strict comparison will be used when generating the code for the switch.

If we consider the transformation superficially, then the following will be:

For example:

$a = match($b) {
  10 => 1,
  20 => 2,
  default => 3,
}

Converts to something like this:

$a = ({
  switch ($b) {
     case 10: {
        $tmp = 1; 
        break;
     }
     case 20: {
        $tmp = 2; 
        break;
     }
     default: {
        $tmp = 3; 
        break;
     }
  };
  $tmp;
});

If there are several conditions, then the code is generated only once
and all conditions fallthrough to this code:

For example:

$a = match($b) {
  10, 20 => 1,
  default => 3,
}

Converts to something like this:

$a = ({
  switch ($b) {
     case 10: {} // fallthrough
     case 20: {
        $tmp = 1; 
        break;
     }
     default: {
        $tmp = 3; 
        break;
     }
  };
  $tmp;
});

If there is no default branch, then the default version is generated.
The default version always gives a warning about an unhandled value.

PHP throws an UnhandledMatchError exception if the value is not handled.

For example:

$a = match($b) {
  10 => 1,
}

Converts to something like this:

$a = ({
  switch ($b) {
     case 10: {
        $tmp = 1; 
        break;
     }
     default: {
        warning("Unhandled match value '$b'"); 
        break;
     }
  };
  $tmp;
});

Checks

  • Due to the fact that we convert to switch, we automatically get a check for a duplicate.
Repeated case [10] in switch/match
  • Also added a check for several default
Match expressions may only contain one default arm

@i582 i582 added the PHP8 PHP8 feature label Sep 6, 2021
In PHP, a regular `switch` uses non-strict comparison, which leads
to type casts, but the `match` uses strict comparison, which is why
we need a new `is_match` flag in the `op_switch` node.

If this flag is set, then strict comparison will be used when
generating the code for the `switch`.
- Fixed incorrect parsing of expressions like "10, => 100".
- Improved code generation, now optimized code is generated
  for only strings and only ints.
- Added tests.
@i582 i582 changed the title WIP: match expression match expression Sep 12, 2021
@vkaverin
Copy link

vkaverin commented Feb 14, 2022

Is it possible to add here some kind of annotation to force exhaustion check at compile time instead of runtime warning to cover #428?

@Tsygankov-Slava Tsygankov-Slava mentioned this pull request Jul 3, 2023
44 tasks
@i582
Copy link
Contributor Author

i582 commented Feb 22, 2025

@Danil42Russia review please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PHP8 PHP8 feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants