Skip to content

Commit

Permalink
Add example given in ticket and ensure that works too
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed May 24, 2021
1 parent c258303 commit 38c452a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -832,17 +832,22 @@ public static function verifyType(
$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) {
Expand Down
8 changes: 8 additions & 0 deletions src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,14 @@ public static function getCallableFromAtomic(
null,
null,
true,
true,
false,
false,
true
);
}

$params[] = $param;
}

$return_type = null;
Expand All @@ -267,6 +272,9 @@ public static function getCallableFromAtomic(
null,
null,
true,
true,
false,
false,
true
);
}
Expand Down
76 changes: 52 additions & 24 deletions src/Psalm/Internal/Type/TypeExpander.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public static function expandUnion(
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;

Expand All @@ -50,7 +51,8 @@ public static function expandUnion(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if (is_array($parts)) {
Expand Down Expand Up @@ -99,7 +101,8 @@ public static function expandAtomic(
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
Expand All @@ -116,7 +119,8 @@ public static function expandAtomic(
$parent_class,
$evaluate_class_constants,
$evaluate_conditional_types,
$expand_generic
$expand_generic,
$expand_templates
);

if ($extra_type instanceof TNamedObject && $extra_type->extra_types) {
Expand Down Expand Up @@ -160,7 +164,8 @@ public static function expandAtomic(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if ($new_as_type instanceof TNamedObject) {
Expand All @@ -177,9 +182,14 @@ public static function expandAtomic(
$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;
}

Expand Down Expand Up @@ -286,7 +296,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if (is_array($recursively_fleshed_out_type)) {
Expand Down Expand Up @@ -364,7 +375,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if (\is_array($new_value_type)) {
Expand Down Expand Up @@ -397,7 +409,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if (!is_array($new_value_types)) {
Expand Down Expand Up @@ -432,7 +445,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}
} elseif ($return_type instanceof Type\Atomic\TKeyedArray) {
Expand All @@ -446,7 +460,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}
} elseif ($return_type instanceof Type\Atomic\TList) {
Expand All @@ -459,7 +474,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}

Expand All @@ -474,7 +490,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}
}
Expand All @@ -494,7 +511,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}
}
Expand All @@ -509,7 +527,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}
}
Expand All @@ -524,7 +543,8 @@ function ($constant_name) use ($const_name_part): bool {
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);
}

Expand Down Expand Up @@ -643,7 +663,8 @@ private static function expandConditional(
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,
Expand All @@ -654,7 +675,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

$return_type->as_type = $new_as_type;
Expand All @@ -673,7 +695,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

if (!is_array($candidate)) {
Expand All @@ -694,7 +717,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

$candidate_types = is_array($candidate) ? $candidate : [$candidate];
Expand All @@ -717,7 +741,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

$candidate_types = is_array($candidate) ? $candidate : [$candidate];
Expand Down Expand Up @@ -793,7 +818,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

$return_type->if_type = self::expandUnion(
Expand All @@ -805,7 +831,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

$return_type->else_type = self::expandUnion(
Expand All @@ -817,7 +844,8 @@ private static function expandConditional(
$evaluate_class_constants,
$evaluate_conditional_types,
$final,
$expand_generic
$expand_generic,
$expand_templates
);

return $return_type;
Expand Down
13 changes: 13 additions & 0 deletions tests/Template/ClassTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2293,8 +2293,21 @@ public function map(callable $callback) {
/** @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>
Expand Down

0 comments on commit 38c452a

Please sign in to comment.