[php-src] Issue #20684: Nullsafe operator ?-> incorrectly short-circuits subsequent array access [] (Precedence Violation)

[email protected] (azjezz)
Newsgroups php.bugs
Message-ID <pfE8VJHRe12K2uby5qV0g5qFMGpGkbtlOU29wuzPIzQ@main.internal.php.net>
Issue: https://github.com/php/php-src/issues/20684
Author: azjezz

### Description

The nullsafe operator (`?->`) short-circuits execution of subsequent array access operations (`[]`) if the base object is `null`. This behavior violates operator precedence rules.

The array subscript `[]` applies to the result of the method call/property access.

Expression: `$nullable?->meth()[0]`

- Since `$nullable` is `null`, `$nullable?->meth()` evaluates to `null`.
- The remaining expression is effectively `(null)[0]`.
- This should trigger a Warning, but currently returns `null` silently.

The compiler generates a `JMP_NULL` that skips the `FETCH_DIM_R` opcode entirely. This is incorrect because the array access is outside the scope of the nullsafe interaction. The issue is even more evident when parentheses are used to strictly contain the nullsafe expression, yet the compiler still jumps over the array access.

Test:

```
<?php

function example(): void {
    $nullable = null;
    
    // Case 1: Standard Chain
    // Precedence dictates this is ($nullable?->meth())[0]
    // Expected: Warning (accessing offset 0 on null)
    // Actual: Silent null
    $nullable?->meth()[0]; 

    // Case 2: Parenthesized
    // The grouping explicitly separates the operations.
    // Expected: Warning
    // Actual: Silent null
    ($nullable?->meth())[0]; 

    // Case 3: Control
    // Demonstrates that accessing an offset on null throws a warning.
    (null)[0]; 
}

example();
```

Expected Result:

```
Warning: Trying to access array offset on value of type null in %s on line %d
Warning: Trying to access array offset on value of type null in %s on line %d
Warning: Trying to access array offset on value of type null in %s on line %d
```

Actual Result:

```
Warning: Trying to access array offset on value of type null in %s on line %d
```

(Only the control case emits the warning)

The issue is confirmed by the generated opcodes. The `JMP_NULL` instruction (generated by `?->`) targets the instruction after the `FETCH_DIM_R` (array access).

In the dump below (for `($nullable?->meth())[0]`), `JMP_NULL` at line #6 jumps to ~5. The `FETCH_DIM_R` at #9 writes to ~5. The jump skips the fetch, improperly treating the array access as part of the nullsafe short-circuit.

```opcode
filename:       /in/n6rgk
function name:  example
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
    6     1        JMP_NULL                                         ~3      !0
          2        INIT_METHOD_CALL                                         !0, 'meth'
          3        DO_FCALL                                      0  $2      
          4        FETCH_DIM_R                                      ~3      $2, 0
          5        FREE                                                     ~3
    7     6        JMP_NULL                                         ~5      !0   <-- Jumps to result of FETCH_DIM_R
          7        INIT_METHOD_CALL                                         !0, 'meth'
          8        DO_FCALL                                      0  $4      
          9        FETCH_DIM_R                                      ~5      $4, 0
         10        FREE                                                     ~5
```



### PHP Version

```plain
All supported versions
```

### Operating System

N/A
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.