mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Add example given in ticket and ensure that works too
This commit is contained in:
parent
c258303f78
commit
38c452ae58
@ -832,17 +832,22 @@ class ArgumentAnalyzer
|
||||
$param_type->possibly_undefined = true;
|
||||
}
|
||||
|
||||
if ($param_type->hasCallableType()
|
||||
&& $param_type->isSingle()
|
||||
&& $input_type->isSingleStringLiteral()
|
||||
&& !\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap($input_type->getSingleStringLiteral()->value)
|
||||
) {
|
||||
if ($param_type->hasCallableType() && $param_type->isSingle()) {
|
||||
// we do this replacement early because later we don't have access to the
|
||||
// $statements_analyzer, which is necessary to understand string function names
|
||||
foreach ($input_type->getAtomicTypes() as $key => $atomic_type) {
|
||||
if (!$atomic_type instanceof Type\Atomic\TLiteralString
|
||||
|| \Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap($atomic_type->value)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$candidate_callable = CallableTypeComparator::getCallableFromAtomic(
|
||||
$codebase,
|
||||
$atomic_type,
|
||||
null,
|
||||
$statements_analyzer
|
||||
$statements_analyzer,
|
||||
true
|
||||
);
|
||||
|
||||
if ($candidate_callable) {
|
||||
|
@ -252,9 +252,14 @@ class CallableTypeComparator
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
$params[] = $param;
|
||||
}
|
||||
|
||||
$return_type = null;
|
||||
@ -267,6 +272,9 @@ class CallableTypeComparator
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ class TypeExpander
|
||||
bool $evaluate_class_constants = true,
|
||||
bool $evaluate_conditional_types = false,
|
||||
bool $final = false,
|
||||
bool $expand_generic = false
|
||||
bool $expand_generic = false,
|
||||
bool $expand_templates = false
|
||||
): Type\Union {
|
||||
$return_type = clone $return_type;
|
||||
|
||||
@ -50,7 +51,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if (is_array($parts)) {
|
||||
@ -99,7 +101,8 @@ class TypeExpander
|
||||
bool $evaluate_class_constants = true,
|
||||
bool $evaluate_conditional_types = false,
|
||||
bool $final = false,
|
||||
bool $expand_generic = false
|
||||
bool $expand_generic = false,
|
||||
bool $expand_templates = false
|
||||
) {
|
||||
if ($return_type instanceof TNamedObject
|
||||
|| $return_type instanceof TTemplateParam
|
||||
@ -116,7 +119,8 @@ class TypeExpander
|
||||
$parent_class,
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if ($extra_type instanceof TNamedObject && $extra_type->extra_types) {
|
||||
@ -160,7 +164,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if ($new_as_type instanceof TNamedObject) {
|
||||
@ -177,9 +182,14 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if ($expand_templates) {
|
||||
return array_values($new_as_type->getAtomicTypes());
|
||||
}
|
||||
|
||||
$return_type->as = $new_as_type;
|
||||
}
|
||||
|
||||
@ -286,7 +296,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if (is_array($recursively_fleshed_out_type)) {
|
||||
@ -364,7 +375,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if (\is_array($new_value_type)) {
|
||||
@ -397,7 +409,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if (!is_array($new_value_types)) {
|
||||
@ -432,7 +445,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
} elseif ($return_type instanceof Type\Atomic\TKeyedArray) {
|
||||
@ -446,7 +460,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
} elseif ($return_type instanceof Type\Atomic\TList) {
|
||||
@ -459,7 +474,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
|
||||
@ -474,7 +490,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -494,7 +511,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -509,7 +527,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -524,7 +543,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
}
|
||||
|
||||
@ -643,7 +663,8 @@ class TypeExpander
|
||||
bool $evaluate_class_constants = true,
|
||||
bool $evaluate_conditional_types = false,
|
||||
bool $final = false,
|
||||
bool &$expand_generic = false
|
||||
bool &$expand_generic = false,
|
||||
bool $expand_templates = false
|
||||
) {
|
||||
$new_as_type = self::expandUnion(
|
||||
$codebase,
|
||||
@ -654,7 +675,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
$return_type->as_type = $new_as_type;
|
||||
@ -673,7 +695,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
if (!is_array($candidate)) {
|
||||
@ -694,7 +717,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
$candidate_types = is_array($candidate) ? $candidate : [$candidate];
|
||||
@ -717,7 +741,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
$candidate_types = is_array($candidate) ? $candidate : [$candidate];
|
||||
@ -793,7 +818,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
$return_type->if_type = self::expandUnion(
|
||||
@ -805,7 +831,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
$return_type->else_type = self::expandUnion(
|
||||
@ -817,7 +844,8 @@ class TypeExpander
|
||||
$evaluate_class_constants,
|
||||
$evaluate_conditional_types,
|
||||
$final,
|
||||
$expand_generic
|
||||
$expand_generic,
|
||||
$expand_templates
|
||||
);
|
||||
|
||||
return $return_type;
|
||||
|
@ -2293,8 +2293,21 @@ class ClassTemplateTest extends TestCase
|
||||
/** @param ArrayCollection<int> $ints */
|
||||
function takesInts(ArrayCollection $ints) :void {}
|
||||
|
||||
/** @param ArrayCollection<int|string> $ints */
|
||||
function takesIntsOrStrings(ArrayCollection $ints) :void {}
|
||||
|
||||
takesInts((new ArrayCollection([ "a", "bc" ]))->map("strlen"));
|
||||
|
||||
/** @return ($s is "string" ? string : int) */
|
||||
function foo(string $s) {
|
||||
if ($s === "string") {
|
||||
return "hello";
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
takesIntsOrStrings((new ArrayCollection([ "a", "bc" ]))->map("foo"));
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @extends ArrayCollection<T>
|
||||
|
Loading…
x
Reference in New Issue
Block a user