1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Improve array coercion checks

This commit is contained in:
Matthew Brown 2018-11-01 23:31:40 -04:00
parent 1152aa953f
commit ccf5de0418
2 changed files with 103 additions and 65 deletions

View File

@ -494,74 +494,90 @@ class ArrayFetchChecker
$array_access_type = Type::getMixed();
}
} elseif ((TypeChecker::isContainedBy(
$codebase,
$offset_type,
$generic_key_type->isMixed()
? new Type\Union([ new TInt, new TString ])
: $generic_key_type,
true,
$offset_type->ignore_falsable_issues,
$has_scalar_match,
$type_coerced,
$type_coerced_from_mixed,
$to_string_cast,
$type_coerced_from_scalar
)
|| $type_coerced_from_scalar
|| $type_coerced_from_mixed
|| $in_assignment)
&& !$to_string_cast
) {
if ($replacement_type) {
$generic_params = Type::combineUnionTypes(
$type->getGenericValueType(),
$replacement_type
);
$new_key_type = Type::combineUnionTypes(
$generic_key_type,
$offset_type
);
$property_count = $type->sealed ? count($type->properties) : null;
$type = new TArray([
$new_key_type,
$generic_params,
]);
if (!$stmt->dim && $property_count) {
++$property_count;
$type->count = $property_count;
}
if (!$array_access_type) {
$array_access_type = clone $generic_params;
} else {
$array_access_type = Type::combineUnionTypes(
$array_access_type,
$generic_params
);
}
} else {
if (!$array_access_type) {
$array_access_type = $type->getGenericValueType();
} else {
$array_access_type = Type::combineUnionTypes(
$array_access_type,
$type->getGenericValueType()
);
}
}
$has_valid_offset = true;
} else {
if (!$inside_isset || $type->sealed) {
$expected_offset_types[] = (string)$generic_key_type->getId();
$key_type = $generic_key_type->isMixed()
? new Type\Union([ new TInt, new TString ])
: $generic_key_type;
$is_contained = TypeChecker::isContainedBy(
$codebase,
$offset_type,
$key_type,
true,
$offset_type->ignore_falsable_issues,
$has_scalar_match,
$type_coerced,
$type_coerced_from_mixed,
$to_string_cast,
$type_coerced_from_scalar
);
if ($inside_isset && !$is_contained) {
$is_contained = TypeChecker::canBeContainedBy(
$codebase,
$offset_type,
$key_type,
true,
$offset_type->ignore_falsable_issues
);
}
$array_access_type = Type::getMixed();
if (($is_contained
|| $type_coerced_from_scalar
|| $type_coerced_from_mixed
|| $in_assignment)
&& !$to_string_cast
) {
if ($replacement_type) {
$generic_params = Type::combineUnionTypes(
$type->getGenericValueType(),
$replacement_type
);
$new_key_type = Type::combineUnionTypes(
$generic_key_type,
$offset_type
);
$property_count = $type->sealed ? count($type->properties) : null;
$type = new TArray([
$new_key_type,
$generic_params,
]);
if (!$stmt->dim && $property_count) {
++$property_count;
$type->count = $property_count;
}
if (!$array_access_type) {
$array_access_type = clone $generic_params;
} else {
$array_access_type = Type::combineUnionTypes(
$array_access_type,
$generic_params
);
}
} else {
if (!$array_access_type) {
$array_access_type = $type->getGenericValueType();
} else {
$array_access_type = Type::combineUnionTypes(
$array_access_type,
$type->getGenericValueType()
);
}
}
$has_valid_offset = true;
} else {
if (!$inside_isset || $type->sealed) {
$expected_offset_types[] = (string)$generic_key_type->getId();
}
$array_access_type = Type::getMixed();
}
}
}
continue;

View File

@ -447,6 +447,28 @@ class ValueTest extends TestCase
}
}',
],
'coercePossibleOffset' => [
'<?php
class A {
const FOO = "foo";
const BAR = "bar";
const BAT = "bat";
const BAM = "bam";
/** @var self::FOO|self::BAR|self::BAT|null $s */
public $s;
public function isFooOrBar() : void {
$map = [
A::FOO => 1,
A::BAR => 1,
A::BAM => 1,
];
if (isset($map[$this->s])) {}
}
}'
],
];
}