mago icon indicating copy to clipboard operation
mago copied to clipboard

Negated isset check should strongly assert that a key for a non-nullable type is absent

Open dotdash opened this issue 3 months ago • 2 comments

🐞 Describe the Bug

A !isset check on a specific array key tells us that the value in the array slot is either undefined or null. If the array shape for that array tells us that the type for that value is non-nullable, we should report it as definitely undefined, not just possibly undefined.

🔄 Steps to Reproduce

  1. Run mago analyze on the given example.

⚙️ Configuration (mago.toml)

php-version = "8.4.0"

[source]
paths = ["src"]
includes = ["vendor"]
excludes = []

📜 Command Output

❯ MAGO_LOG=trace cargo run -- --workspace play analyze src/nisset.php
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s
     Running `target/debug/mago --workspace play analyze src/nisset.php`
2025-10-16T21:21:53.641632Z DEBUG main mago::config: Sourcing global configuration from /home/bsteinbrink/mago.toml.
2025-10-16T21:21:53.641700Z DEBUG main mago::config: Sourcing workspace configuration from play/mago.toml.
2025-10-16T21:21:53.644186Z  INFO main mago::config: Overriding workspace directory with play.
2025-10-16T21:21:53.644208Z DEBUG main mago::config: Configuration specifies 32 threads.
2025-10-16T21:21:53.644218Z DEBUG main mago::config: Configuration specifies a stack size of 12582912 bytes.
warning[possibly-undefined-string-array-index]: Possibly undefined array key 'bar' accessed on `array{'bar'?: string}`.
  ┌─ src/nisset.php:7:24
  │
7 │     var_dump($y['foo']['bar']); // This is reported as possibly-undefined although the type+check tells us it's definitely undefined
  │                        ^^^^^ Key 'bar' might not exist.
  │
  = The analysis indicates this specific key might not be set when this access occurs.
  = Help: Ensure the key 'bar' is always set before accessing it, or use `isset()` or the null coalesce operator (`??`) to handle potential missing keys.

error[undefined-string-array-index]: Undefined array key 'baz' accessed on `array{'bar'?: string}`.
  ┌─ src/nisset.php:8:24
  │
8 │     var_dump($y['foo']['baz']); // This is reported as undefined-string-array-index
  │                        ^^^^^ Key 'baz' does not exist.
  │
  = Attempting to access a non-existent string key will raise a warning/notice at runtime.
  = Help: Ensure the key 'baz' exists before accessing it, or use `isset()` or the null coalesce operator (`??`) to handle potential missing keys.

error: found 2 issues: 1 error(s), 1 warning(s)

📂 PHP Code Sample (If Applicable)

<?php declare(strict_types=1);

/** @var array{ foo?: array{ bar?: string} } $y **/
$y = ['foo' => ['bar' => 123]];

if (isset($y['foo']) && !isset($y['foo']['bar'])) {
    var_dump($y['foo']['bar']); // This is reported as possibly-undefined although the type+check tells us it's definitely undefined
    var_dump($y['foo']['baz']); // This is reported as undefined-string-array-index
}

🖥️ Operating System

Linux

📦 How did you install Mago?

Built from Source

📝 Additional Context

No response

dotdash avatar Oct 16 '25 21:10 dotdash

This might actually be a feature request 😅

dotdash avatar Oct 16 '25 21:10 dotdash

Yea, this is not a bug. but it makes sense to implement.

azjezz avatar Oct 17 '25 04:10 azjezz

repro: https://mago.carthage.software/playground#019b2a60-5a0d-a6e4-0848-fb9159458b96

azjezz avatar Dec 17 '25 03:12 azjezz