mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Add more robust template constraint checks
This commit is contained in:
parent
ed68cb973d
commit
1d2a0f8b39
@ -4,6 +4,7 @@ namespace Psalm\Type;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Internal\Analyzer\TypeAnalyzer;
|
||||
use Psalm\Storage\FileStorage;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TFloat;
|
||||
@ -823,7 +824,15 @@ class Union
|
||||
];
|
||||
}
|
||||
} elseif ($add_upper_bound && $input_type) {
|
||||
$template_types[$key][0] = clone $input_type;
|
||||
if ($codebase
|
||||
&& TypeAnalyzer::isContainedBy(
|
||||
$codebase,
|
||||
$input_type,
|
||||
$template_types[$key][0]
|
||||
)
|
||||
) {
|
||||
$template_types[$key][0] = clone $input_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($atomic_type instanceof Type\Atomic\TGenericParamClass
|
||||
|
@ -1949,6 +1949,34 @@ class TemplateTest extends TestCase
|
||||
'$b' => 'null|SpecificEntity',
|
||||
]
|
||||
],
|
||||
'multipleArgConstraints' => [
|
||||
'<?php
|
||||
class A {}
|
||||
class AChild extends A {}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param callable(T):void $c1
|
||||
* @param callable(T):void $c2
|
||||
* @param T $a
|
||||
*/
|
||||
function foo(callable $c1, callable $c2, $a): void {
|
||||
$c1($a);
|
||||
$c2($a);
|
||||
}
|
||||
|
||||
foo(
|
||||
function(A $_a) : void {},
|
||||
function(A $_a) : void {},
|
||||
new A()
|
||||
);
|
||||
|
||||
foo(
|
||||
function(A $_a) : void {},
|
||||
function(A $_a) : void {},
|
||||
new AChild()
|
||||
);'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -2474,6 +2502,75 @@ class TemplateTest extends TestCase
|
||||
takesReturnTCallable($b);',
|
||||
'error_message' => 'InvalidScalarArgument',
|
||||
],
|
||||
'multipleArgConstraintWithMoreRestrictiveFirstArg' => [
|
||||
'<?php
|
||||
class A {}
|
||||
class AChild extends A {}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param callable(T):void $c1
|
||||
* @param callable(T):void $c2
|
||||
* @param T $a
|
||||
*/
|
||||
function foo(callable $c1, callable $c2, $a): void {
|
||||
$c1($a);
|
||||
$c2($a);
|
||||
}
|
||||
|
||||
foo(
|
||||
function(AChild $_a) : void {},
|
||||
function(A $_a) : void {},
|
||||
new A()
|
||||
);',
|
||||
'error_message' => 'TypeCoercion',
|
||||
],
|
||||
'multipleArgConstraintWithMoreRestrictiveSecondArg' => [
|
||||
'<?php
|
||||
class A {}
|
||||
class AChild extends A {}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param callable(T):void $c1
|
||||
* @param callable(T):void $c2
|
||||
* @param T $a
|
||||
*/
|
||||
function foo(callable $c1, callable $c2, $a): void {
|
||||
$c1($a);
|
||||
$c2($a);
|
||||
}
|
||||
|
||||
foo(
|
||||
function(A $_a) : void {},
|
||||
function(AChild $_a) : void {},
|
||||
new A()
|
||||
);',
|
||||
'error_message' => 'TypeCoercion',
|
||||
],
|
||||
'multipleArgConstraintWithLessRestrictiveThirdArg' => [
|
||||
'<?php
|
||||
class A {}
|
||||
class AChild extends A {}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param callable(T):void $c1
|
||||
* @param callable(T):void $c2
|
||||
* @param T $a
|
||||
*/
|
||||
function foo(callable $c1, callable $c2, $a): void {
|
||||
$c1($a);
|
||||
$c2($a);
|
||||
}
|
||||
|
||||
foo(
|
||||
function(AChild $_a) : void {},
|
||||
function(AChild $_a) : void {},
|
||||
new A()
|
||||
);',
|
||||
'error_message' => 'TypeCoercion',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user