diff --git a/src/Psalm/Internal/Stubs/CoreGenericClasses.php b/src/Psalm/Internal/Stubs/CoreGenericClasses.php index a86cc5705..7af220925 100644 --- a/src/Psalm/Internal/Stubs/CoreGenericClasses.php +++ b/src/Psalm/Internal/Stubs/CoreGenericClasses.php @@ -1195,3 +1195,22 @@ class ReflectionClass implements Reflector { */ public function newInstanceWithoutConstructor() : object; } + +/** + * @template-covariant T as object + * @psalm-immutable + */ +final class WeakReference +{ + // always fail + public function __construct(); + /** + * @template TIn as object + * @param TIn $referent + * @return WeakReference + */ + public static function create(object $referent): WeakReference; + + /** @return ?T */ + public function get(): ?object; +} diff --git a/tests/Template/ClassTemplateTest.php b/tests/Template/ClassTemplateTest.php index 192c4d4f7..59698fbdb 100644 --- a/tests/Template/ClassTemplateTest.php +++ b/tests/Template/ClassTemplateTest.php @@ -2067,6 +2067,22 @@ class ClassTemplateTest extends TestCase takesInts((new ArrayCollection([ "a", "bc" ]))->map("strlen"));' ], + 'weakReferenceIsTyped' => [ + 'get(); + ', + [ '$ex' => 'Exception|null' ], + ], + 'weakReferenceIsCovariant' => [ + ' $_ref */ + function acceptsThrowableRef(WeakReference $_ref): void {} + + acceptsThrowableRef(WeakReference::create(new Exception)); + ' + ] ]; }