2016-12-27 19:58:58 +01:00
|
|
|
|
<?php
|
2018-11-06 03:57:36 +01:00
|
|
|
|
namespace Psalm\Internal;
|
2016-12-27 19:58:58 +01:00
|
|
|
|
|
2019-06-26 22:52:29 +02:00
|
|
|
|
use function array_diff;
|
2019-07-05 22:24:00 +02:00
|
|
|
|
use function array_keys;
|
|
|
|
|
use function array_map;
|
|
|
|
|
use function array_values;
|
|
|
|
|
use function count;
|
|
|
|
|
use function implode;
|
2019-06-26 22:52:29 +02:00
|
|
|
|
use function json_encode;
|
2019-07-05 22:24:00 +02:00
|
|
|
|
use function ksort;
|
2019-06-26 22:52:29 +02:00
|
|
|
|
use function md5;
|
2019-07-05 22:24:00 +02:00
|
|
|
|
use function sort;
|
2019-06-26 22:52:29 +02:00
|
|
|
|
use function spl_object_hash;
|
|
|
|
|
|
2018-12-02 00:37:49 +01:00
|
|
|
|
/**
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
2016-12-27 19:58:58 +01:00
|
|
|
|
class Clause
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* An array of strings of the form
|
|
|
|
|
* [
|
2017-10-22 17:57:41 +02:00
|
|
|
|
* '$a' => ['falsy'],
|
|
|
|
|
* '$b' => ['!falsy'],
|
2016-12-27 19:58:58 +01:00
|
|
|
|
* '$c' => ['!null'],
|
|
|
|
|
* '$d' => ['string', 'int']
|
|
|
|
|
* ]
|
|
|
|
|
*
|
|
|
|
|
* representing the formula
|
|
|
|
|
*
|
|
|
|
|
* !$a || $b || $c !== null || is_string($d) || is_int($d)
|
|
|
|
|
*
|
2019-10-09 15:17:43 +02:00
|
|
|
|
* @var array<string, non-empty-list<string>>
|
2016-12-27 19:58:58 +01:00
|
|
|
|
*/
|
|
|
|
|
public $possibilities;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An array of things that are not true
|
|
|
|
|
* [
|
2017-10-22 17:57:41 +02:00
|
|
|
|
* '$a' => ['!falsy'],
|
|
|
|
|
* '$b' => ['falsy'],
|
2016-12-27 19:58:58 +01:00
|
|
|
|
* '$c' => ['null'],
|
|
|
|
|
* '$d' => ['!string', '!int']
|
|
|
|
|
* ]
|
|
|
|
|
* represents the formula
|
|
|
|
|
*
|
|
|
|
|
* $a && !$b && $c === null && !is_string($d) && !is_int($d)
|
|
|
|
|
*
|
2019-10-09 15:17:43 +02:00
|
|
|
|
* @var array<string, non-empty-list<string>>|null
|
2016-12-27 19:58:58 +01:00
|
|
|
|
*/
|
|
|
|
|
public $impossibilities;
|
|
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
|
public $wedge;
|
|
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
|
public $reconcilable;
|
|
|
|
|
|
2018-05-07 20:52:45 +02:00
|
|
|
|
/** @var bool */
|
|
|
|
|
public $generated = false;
|
|
|
|
|
|
2016-12-27 19:58:58 +01:00
|
|
|
|
/**
|
2019-10-09 15:17:43 +02:00
|
|
|
|
* @param array<string, non-empty-list<string>> $possibilities
|
2016-12-27 19:58:58 +01:00
|
|
|
|
* @param bool $wedge
|
|
|
|
|
* @param bool $reconcilable
|
2018-05-07 20:52:45 +02:00
|
|
|
|
* @param bool $generated
|
2016-12-27 19:58:58 +01:00
|
|
|
|
*/
|
2018-05-07 20:52:45 +02:00
|
|
|
|
public function __construct(array $possibilities, $wedge = false, $reconcilable = true, $generated = false)
|
2016-12-27 19:58:58 +01:00
|
|
|
|
{
|
|
|
|
|
$this->possibilities = $possibilities;
|
|
|
|
|
$this->wedge = $wedge;
|
|
|
|
|
$this->reconcilable = $reconcilable;
|
2018-05-07 20:52:45 +02:00
|
|
|
|
$this->generated = $generated;
|
2016-12-27 19:58:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param Clause $other_clause
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2016-12-27 19:58:58 +01:00
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function contains(Clause $other_clause)
|
|
|
|
|
{
|
2017-03-20 04:26:45 +01:00
|
|
|
|
if (count($other_clause->possibilities) > count($this->possibilities)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-27 19:58:58 +01:00
|
|
|
|
foreach ($other_clause->possibilities as $var => $possible_types) {
|
|
|
|
|
if (!isset($this->possibilities[$var]) || count(array_diff($possible_types, $this->possibilities[$var]))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets a hash of the object – will be unique if we're unable to easily reconcile this with others
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getHash()
|
|
|
|
|
{
|
|
|
|
|
ksort($this->possibilities);
|
|
|
|
|
|
2017-02-02 06:45:23 +01:00
|
|
|
|
foreach ($this->possibilities as &$possible_types) {
|
2016-12-27 19:58:58 +01:00
|
|
|
|
sort($possible_types);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-18 16:18:04 +02:00
|
|
|
|
$possibility_string = json_encode($this->possibilities);
|
|
|
|
|
if (!$possibility_string) {
|
2019-07-05 22:24:00 +02:00
|
|
|
|
return (string) \mt_rand(0, 10000000);
|
2017-09-18 16:18:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return md5($possibility_string) .
|
2016-12-27 19:58:58 +01:00
|
|
|
|
($this->wedge || !$this->reconcilable ? spl_object_hash($this) : '');
|
|
|
|
|
}
|
2018-05-07 07:26:06 +02:00
|
|
|
|
|
|
|
|
|
public function __toString()
|
|
|
|
|
{
|
|
|
|
|
return implode(
|
|
|
|
|
' || ',
|
|
|
|
|
array_map(
|
|
|
|
|
/**
|
|
|
|
|
* @param string $var_id
|
|
|
|
|
* @param string[] $values
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function ($var_id, $values) {
|
|
|
|
|
return implode(
|
2018-05-07 20:52:45 +02:00
|
|
|
|
' || ',
|
2018-05-07 07:26:06 +02:00
|
|
|
|
array_map(
|
|
|
|
|
/**
|
|
|
|
|
* @param string $value
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function ($value) use ($var_id) {
|
|
|
|
|
if ($value === 'falsy') {
|
|
|
|
|
return '!' . $var_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($value === '!falsy') {
|
|
|
|
|
return $var_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $var_id . '==' . $value;
|
|
|
|
|
},
|
|
|
|
|
$values
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
array_keys($this->possibilities),
|
|
|
|
|
array_values($this->possibilities)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
2016-12-27 19:58:58 +01:00
|
|
|
|
}
|