Skip to content
Permalink
Browse files

Fix #2321 - prevent inferred template coercion

  • Loading branch information
muglug committed Nov 11, 2019
1 parent 79acbad commit 46d163996e2d2c987934f84122a302e824841eaa
Showing with 74 additions and 33 deletions.
  1. +3 −3 src/Psalm/Internal/Analyzer/TypeAnalyzer.php
  2. +71 −30 tests/Template/ClassTemplateTest.php
@@ -1940,11 +1940,11 @@ private static function isMatchingTypeContainedBy(
&& !$container_param->hasTemplate()
&& !$input_param->hasTemplate()
) {
if ($input_param->had_template
|| $input_param->hasEmptyArray()
if ($input_param->hasEmptyArray()
|| $input_param->hasLiteralValue()
) {
if (!$atomic_comparison_result->replacement_atomic_type) {
$atomic_comparison_result->replacement_atomic_type = clone $input_type_part;
}
@@ -1966,7 +1966,7 @@ private static function isMatchingTypeContainedBy(
$container_param->ignore_falsable_issues,
$param_comparison_result,
$allow_interface_equality
) || $atomic_comparison_result->type_coerced
) || $param_comparison_result->type_coerced
) {
if ($container_param->hasMixed() || $container_param->isArrayKey()) {
$atomic_comparison_result->type_coerced_from_mixed = true;
@@ -1682,7 +1682,7 @@ class Base {}
class Child extends Base {}
/**
* @template T
* @template-covariant T
*/
class Foo
{
@@ -1700,7 +1700,7 @@ function returnFooBase() : Foo {
],
'allowMoreSpecificArray' => [
'<?php
/** @template T */
/** @template-covariant T */
class Foo {
/** @param \Closure():T $closure */
public function __construct($closure) {}
@@ -1715,6 +1715,33 @@ public function __construct() {
}
}'
],
'specializeTypeInPropertyAssignment' => [
'<?php
/** @template-covariant T */
class Foo {
/** @var \Closure():T $closure */
private $closure;
/** @param \Closure():T $closure */
public function __construct($closure)
{
$this->closure = $closure;
}
}
class Bar {
/** @var Foo<array> */
private $FooArray;
public function __construct() {
$this->FooArray = new Foo(function(): array { return ["foo" => "bar"]; });
expectsShape($this->FooArray);
}
}
/** @param Foo<array{foo: string}> $_ */
function expectsShape($_): void {}',
],
'reflectTemplatedClass' => [
'<?php
/** @template T1 of object */
@@ -2446,34 +2473,6 @@ function returnFooBase() {
function takesFooDerived($foo): void {}',
'error_message' => 'InvalidReturnStatement'
],
'specializeTypeInPropertyAssignment' => [
'<?php
/** @template T */
class Foo {
/** @var \Closure():T $closure */
private $closure;
/** @param \Closure():T $closure */
public function __construct($closure)
{
$this->closure = $closure;
}
}
class Bar {
/** @var Foo<array> */
private $FooArray;
public function __construct() {
$this->FooArray = new Foo(function(): array { return ["foo" => "bar"]; });
expectsShape($this->FooArray);
}
}
/** @param Foo<array{foo: string}> $_ */
function expectsShape($_): void {}',
'error_message' => 'MixedArgumentTypeCoercion'
],
'preventUseWithMoreSpecificParamInt' => [
'<?php
/** @template T */
@@ -2508,6 +2507,48 @@ function usesCollection(Collection $col): void {
}',
'error_message' => 'InvalidArgument'
],
'preventTemplatedCorrectionBeingWrittenTo' => [
'<?php
namespace NS;
/**
* @template TKey
* @template TValue
*/
class ArrayCollection {
/** @var array<TKey,TValue> */
private $data;
/** @param array<TKey,TValue> $data */
public function __construct(array $data) {
$this->data = $data;
}
/**
* @param TKey $key
* @param TValue $value
*/
public function addItem($key, $value) : void {
$this->data[$key] = $value;
}
}
class Item {}
class SubItem extends Item {}
class OtherSubItem extends Item {}
/**
* @param ArrayCollection<int,Item> $i
*/
function takesCollectionOfItems(ArrayCollection $i): void {
$i->addItem(10, new OtherSubItem);
}
$subitem_collection = new ArrayCollection([ new SubItem ]);
takesCollectionOfItems($subitem_collection);',
'error_message' => 'InvalidArgument'
],
];
}
}

0 comments on commit 46d1639

Please sign in to comment.
You can’t perform that action at this time.