Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -4238,6 +4238,11 @@ public function applySpecifiedTypes(SpecifiedTypes $specifiedTypes): self
// a combinatorially-grown offset union doubles it with every isset()-
// style check and gets skipped (overwrites assign, they never narrow)
continue;
} elseif ($trackedNativeType === null) {
// tracked with its PHPDoc type only (e.g. by a conditional holder) -
// the native base is still read from the scope, not taken from
// the PHPDoc type
$trackedNativeType = $scope->getCurrentTypesOfSpecifiedExpr($expr)[1] ?? null;
}

if (isset($typeSpecification['terms'])) {
Expand Down
2 changes: 1 addition & 1 deletion src/Turbo/TurboExtensionEnabler.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
final class TurboExtensionEnabler
{

public const EXPECTED_EXTENSION_VERSION = 'a0f7086';
public const EXPECTED_EXTENSION_VERSION = 'f13ee08';

private static bool $active = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,9 @@ public function testBug15250(): void
$this->analyse([__DIR__ . '/data/bug-15250.php'], []);
}

public function testBug15404(): void
{
$this->analyse([__DIR__ . '/data/bug-15404.php'], []);
}

}
17 changes: 17 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-15404.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace Bug15404;

/** @param array{projects?: list<string>} $s */
function a(array $s): void
{
$has = isset($s['projects']);
if (!$has) {
return;
}
foreach ($s['projects'] as $p) {
if (!is_string($p)) {
throw new \InvalidArgumentException();
}
}
}
24 changes: 24 additions & 0 deletions turbo-ext/src/MutatingScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7999,6 +7999,30 @@ class MutatingScope
skipSpecification = true;
}
}
if (!skipSpecification && !hasTrackedNative) {
/* tracked with its PHPDoc type only (e.g. by a conditional
* holder) - the native base is still read from the scope,
* not taken from the PHPDoc type */
zval exprZv;
ZVAL_OBJ(&exprZv, expr);
zv::Val currentTypes = otherPrivate(scopeObject, PT_LC("getcurrenttypesofspecifiedexpr"), 1, &exprZv, [&](MutatingScope &other) {
return other.getCurrentTypesOfSpecifiedExpr(expr);
});
if (UNEXPECTED(currentTypes.isUndef())) return zv::Val();
if (Z_TYPE_P(currentTypes.raw()) != IS_NULL) {
if (UNEXPECTED(Z_TYPE_P(currentTypes.raw()) != IS_ARRAY)) {
zend_throw_error(NULL, "phpstan_turbo: getCurrentTypesOfSpecifiedExpr() answered an unexpected shape");
return zv::Val();
}
zval *native = zend_hash_index_find(Z_ARRVAL_P(currentTypes.raw()), 1);
if (UNEXPECTED(native == NULL)) {
zend_throw_error(NULL, "phpstan_turbo: getCurrentTypesOfSpecifiedExpr() answered an unexpected shape");
return zv::Val();
}
trackedNativeType = zv::Val::copyOf(zv::Ref(native));
hasTrackedNative = true;
}
}
}
if (skipSpecification) continue;

Expand Down
Loading