packages/deriver/tests/Unit/Deriver/Evaluator/Execution/Call/Preparation/EntryPropertiesTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Execution\Call\Preparation;
6
7use Deriver\Deriver\Contributions;
8use Deriver\Deriver\DeriverConfig;
9use Deriver\Deriver\Evaluator\Call\Evaluators;
10use Deriver\Deriver\Evaluator\Call\Extensions;
11use Deriver\Deriver\Evaluator\Call\Registrations;
12use Deriver\Deriver\Evaluator\Call\StateRegistry;
13use Deriver\Deriver\Evaluator\EvaluatorConfig;
14use Deriver\Deriver\Evaluator\Evidence\Frontier;
15use Deriver\Deriver\Evaluator\Execution\Call\Native\Properties;
16use Deriver\Deriver\Evaluator\Execution\Call\Native\Signatures;
17use Deriver\Deriver\Evaluator\Execution\Call\Preparation\EntryProperties;
18use Deriver\Deriver\Evaluator\Execution\Call\TypeBinding;
19use Deriver\Deriver\Evaluator\Execution\Call\TypeCheck;
20use Deriver\Deriver\Evaluator\Execution\Completion\Completion;
21use Deriver\Deriver\Evaluator\Execution\Context;
22use Deriver\Deriver\Evaluator\Execution\EvaluatorConfig as ExecutionEvaluatorConfig;
23use Deriver\Deriver\Evaluator\Execution\Memory\Location;
24use Deriver\Deriver\Evaluator\Execution\Memory\Memory;
25use Deriver\Deriver\Evaluator\Execution\State;
26use Deriver\Deriver\Evaluator\Execution\Transfer\ObjectAccess;
27use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyLookup;
28use Deriver\Deriver\Evaluator\Execution\Transfer\ReferenceAssignment;
29use Deriver\Deriver\Evaluator\Request\Budget;
30use Deriver\Deriver\Evaluator\Request\QueryScope;
31use Deriver\Deriver\Evaluator\Request\ReturnQuery;
32use Deriver\Deriver\Evaluator\Scalar\Arrays;
33use Deriver\Deriver\Evaluator\Scalar\Operations;
34use Deriver\Deriver\Evaluator\TargetProfile;
35use Deriver\Deriver\Evaluator\Term;
36use Deriver\Deriver\Evaluator\TermKind;
37use Deriver\Deriver\Execution\QueryExecution;
38use Deriver\Deriver\Lowerer\Declaration\CallableIdentity;
39use Deriver\Deriver\Lowerer\Declaration\CallableSource;
40use Deriver\Deriver\Lowerer\Declaration\ConstantSignatures;
41use Deriver\Deriver\Lowerer\Declaration\Index;
42use Deriver\Deriver\Lowerer\Declaration\Indexer;
43use Deriver\Deriver\Lowerer\Declaration\Metadata\ClassDeclaration;
44use Deriver\Deriver\Lowerer\Declaration\Metadata\PropertyDeclaration;
45use Deriver\Deriver\Lowerer\Declaration\Traits\Composition;
46use Deriver\Deriver\Lowerer\ExpressionLowering;
47use Deriver\Deriver\Lowerer\Graph\BasicBlock;
48use Deriver\Deriver\Lowerer\Graph\CallableGraph;
49use Deriver\Deriver\Lowerer\Graph\Instruction;
50use Deriver\Deriver\Lowerer\Graph\Terminator;
51use Deriver\Deriver\Lowerer\Hierarchy\Builtins;
52use Deriver\Deriver\Lowerer\Hierarchy\Dispatch;
53use Deriver\Deriver\Lowerer\InstructionEmitter;
54use Deriver\Deriver\Lowerer\Lowerer;
55use Deriver\Deriver\Lowerer\LoweringScope;
56use Deriver\Deriver\MicroEvaluatorConversion;
57use Deriver\Deriver\Parser\Node\File;
58use Deriver\Deriver\Parser\Parser;
59use Deriver\Deriver\Parser\ParserConfig;
60use Deriver\Deriver\Parser\TargetSyntax;
61use Deriver\Deriver\Providers\ProviderExpansion;
62use Deriver\Deriver\Resolver\AssignmentPatterns;
63use Deriver\Deriver\Resolver\ClassScope;
64use Deriver\Deriver\Resolver\ExpressionValidation;
65use Deriver\Deriver\Resolver\MagicContext;
66use Deriver\Deriver\Resolver\Resolver;
67use Deriver\Deriver\SnapshotIdentity;
68use Deriver\Deriver\Sources\LineMap;
69use Deriver\Deriver\Sources\Path;
70use Deriver\Deriver\Sources\Source;
71use Deriver\Deriver\Sources\SourceRef;
72use Deriver\Deriver\Sources\Sources;
73use Deriver\Exception\InvalidInputException;
74use Deriver\Exception\ParserException;
75use Deriver\Exception\ResolutionException;
76use PHPUnit\Framework\Attributes\CoversClass;
77use PHPUnit\Framework\Attributes\DataProvider;
78use PHPUnit\Framework\Attributes\Small;
79use PHPUnit\Framework\Attributes\UsesClass;
80use PHPUnit\Framework\TestCase;
81
82#[UsesClass(Resolver::class)]
83#[UsesClass(ExpressionValidation::class)]
84#[UsesClass(ResolutionException::class)]
85#[UsesClass(ParserConfig::class)]
86#[UsesClass(ParserException::class)]
87#[CoversClass(EntryProperties::class)]
88#[UsesClass(BasicBlock::class)]
89#[UsesClass(CallableGraph::class)]
90#[UsesClass(CallableIdentity::class)]
91#[UsesClass(ClassDeclaration::class)]
92#[UsesClass(Instruction::class)]
93#[UsesClass(PropertyDeclaration::class)]
94#[UsesClass(Terminator::class)]
95#[UsesClass(Dispatch::class)]
96#[UsesClass(TypeBinding::class)]
97#[UsesClass(TypeCheck::class)]
98#[UsesClass(Completion::class)]
99#[UsesClass(Context::class)]
100#[UsesClass(State::class)]
101#[UsesClass(ObjectAccess::class)]
102#[UsesClass(PropertyLookup::class)]
103#[UsesClass(ReferenceAssignment::class)]
104#[UsesClass(Location::class)]
105#[UsesClass(Memory::class)]
106#[UsesClass(Extensions::class)]
107#[UsesClass(Evaluators::class)]
108#[UsesClass(StateRegistry::class)]
109#[UsesClass(DeriverConfig::class)]
110#[UsesClass(Sources::class)]
111#[UsesClass(Path::class)]
112#[UsesClass(Source::class)]
113#[UsesClass(TargetProfile::class)]
114#[UsesClass(Budget::class)]
115#[UsesClass(QueryScope::class)]
116#[UsesClass(ReturnQuery::class)]
117#[UsesClass(SourceRef::class)]
118#[UsesClass(Parser::class)]
119#[UsesClass(File::class)]
120#[UsesClass(Lowerer::class)]
121#[UsesClass(ExpressionLowering::class)]
122#[UsesClass(InstructionEmitter::class)]
123#[UsesClass(LoweringScope::class)]
124#[UsesClass(ConstantSignatures::class)]
125#[UsesClass(CallableSource::class)]
126#[UsesClass(Indexer::class)]
127#[UsesClass(Index::class)]
128#[UsesClass(Composition::class)]
129#[UsesClass(LineMap::class)]
130#[UsesClass(MagicContext::class)]
131#[UsesClass(AssignmentPatterns::class)]
132#[UsesClass(ClassScope::class)]
133#[UsesClass(TargetSyntax::class)]
134#[UsesClass(Arrays::class)]
135#[UsesClass(Operations::class)]
136#[UsesClass(Term::class)]
137#[UsesClass(Builtins::class)]
138#[UsesClass(Properties::class)]
139#[UsesClass(Signatures::class)]
140#[Small]
141final class EntryPropertiesTest extends TestCase
142{
143    public function testApplyWithoutPropertiesLeavesTheEntryStateUntouched(): void
144    {
145        $symbol = 'free';
146        $source = '<?php declare(strict_types=1); class Base{private string $table="users";protected ?int $limit=null;}' . 'final class Box extends Base{private string $order="name";public static int $count=0;public int|string $key=0;public $loose;function run(){}static function make(){}}function free(){}';
147        $budget = new Budget();
148        $configuration = new DeriverConfig();
149        $contributions = new Contributions();
150        $input = new Sources([new Source('fixture.php', $source)]);
151        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
152        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
153        $contributions1 = $providers->contributions;
154        $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
155        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
156        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
157        $snapshotId = $identity->id;
158        $input1 = $providers->input;
159        $parser = new Parser(new ParserConfig($target->version));
160        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input1, false));
161        $program1 = new Index($snapshotId, $trees);
162        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
163        $snapshotId1 = 'test';
164        $input2 = new Sources([new Source('fixture.php', $source)]);
165        $profile = $execution->configuration->target;
166        $parser1 = new Parser(new ParserConfig($profile->version));
167        $trees1 = array_map(static fn (Source $source2): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source2->path), $source2->contents, $source2->declarationsOnly))), iterator_to_array($input2, false));
168        $program = new Index($snapshotId1, $trees1);
169        $context1 = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
170        $body1 = $context1->program->callable($symbol);
171        self::assertNotNull($body1);
172        [$context, $body] = [$context1, $body1];
173        $state = new State();
174        (new EntryProperties($context))->apply($body, null, [], $state);
175        self::assertSame([], $state->memory->cells);
176        self::assertSame([], $state->memory->propertyTypes);
177    }
178    public function testApplyWritesDeclaredSlotsAndKeepsTheRecordOpenForUnsuppliedProperties(): void
179    {
180        $symbol = 'Box::run';
181        $source = '<?php declare(strict_types=1); class Base{private string $table="users";protected ?int $limit=null;}' . 'final class Box extends Base{private string $order="name";public static int $count=0;public int|string $key=0;public $loose;function run(){}static function make(){}}function free(){}';
182        $budget = new Budget();
183        $configuration = new DeriverConfig();
184        $contributions = new Contributions();
185        $input = new Sources([new Source('fixture.php', $source)]);
186        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
187        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
188        $contributions1 = $providers->contributions;
189        $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
190        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
191        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
192        $snapshotId = $identity->id;
193        $input1 = $providers->input;
194        $parser = new Parser(new ParserConfig($target->version));
195        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input1, false));
196        $program1 = new Index($snapshotId, $trees);
197        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
198        $snapshotId1 = 'test';
199        $input2 = new Sources([new Source('fixture.php', $source)]);
200        $profile = $execution->configuration->target;
201        $parser1 = new Parser(new ParserConfig($profile->version));
202        $trees1 = array_map(static fn (Source $source2): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source2->path), $source2->contents, $source2->declarationsOnly))), iterator_to_array($input2, false));
203        $program = new Index($snapshotId1, $trees1);
204        $context1 = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
205        $body1 = $context1->program->callable($symbol);
206        self::assertNotNull($body1);
207        [$context, $body] = [$context1, $body1];
208        $state = new State();
209        $order = Term::constant('email');
210        (new EntryProperties($context))->apply($body, Term::parameter('this', 'Box'), ['order' => $order, 'table' => Term::constant('posts'), 'limit' => Term::constant(null), 'loose' => Term::array([])], $state);
211        $record = $state->memory->cells['object:this'];
212        self::assertSame(['Box::order', 'Base::table', 'limit', 'loose'], array_keys($record->operands));
213        self::assertSame($order, $record->operands['Box::order']);
214        self::assertSame('posts', $record->operands['Base::table']->native());
215        self::assertTrue($record->attributes['open']);
216        self::assertSame(['Box::order' => 'string', 'Base::table' => 'string', 'limit' => 'int|null', 'loose' => 'mixed'], $state->memory->propertyTypes['object:this']);
217    }
218    public function testApplyResolvesTheClassOfAnExplicitReceiverIdentity(): void
219    {
220        $symbol = 'Box::run';
221        $source = '<?php declare(strict_types=1); class Base{private string $table="users";protected ?int $limit=null;}' . 'final class Box extends Base{private string $order="name";public static int $count=0;public int|string $key=0;public $loose;function run(){}static function make(){}}function free(){}';
222        $budget = new Budget();
223        $configuration = new DeriverConfig();
224        $contributions = new Contributions();
225        $input = new Sources([new Source('fixture.php', $source)]);
226        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
227        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
228        $contributions1 = $providers->contributions;
229        $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
230        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
231        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
232        $snapshotId = $identity->id;
233        $input1 = $providers->input;
234        $parser = new Parser(new ParserConfig($target->version));
235        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input1, false));
236        $program1 = new Index($snapshotId, $trees);
237        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
238        $snapshotId1 = 'test';
239        $input2 = new Sources([new Source('fixture.php', $source)]);
240        $profile = $execution->configuration->target;
241        $parser1 = new Parser(new ParserConfig($profile->version));
242        $trees1 = array_map(static fn (Source $source2): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source2->path), $source2->contents, $source2->declarationsOnly))), iterator_to_array($input2, false));
243        $program = new Index($snapshotId1, $trees1);
244        $context1 = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
245        $body1 = $context1->program->callable($symbol);
246        self::assertNotNull($body1);
247        [$context, $body] = [$context1, $body1];
248        $state = new State();
249        (new EntryProperties($context))->apply($body, new Term(TermKind::Object, 'provided', attributes: ['class' => '\Box']), ['key' => Term::constant('k')], $state);
250        self::assertSame('k', $state->memory->cells['object:provided']->operands['key']->native());
251    }
252    public function testApplyKeepsASymbolicValueWithinTheDeclaredType(): void
253    {
254        $symbol = 'Box::run';
255        $source = '<?php declare(strict_types=1); class Base{private string $table="users";protected ?int $limit=null;}' . 'final class Box extends Base{private string $order="name";public static int $count=0;public int|string $key=0;public $loose;function run(){}static function make(){}}function free(){}';
256        $budget = new Budget();
257        $configuration = new DeriverConfig();
258        $contributions = new Contributions();
259        $input = new Sources([new Source('fixture.php', $source)]);
260        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
261        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
262        $contributions1 = $providers->contributions;
263        $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
264        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
265        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
266        $snapshotId = $identity->id;
267        $input1 = $providers->input;
268        $parser = new Parser(new ParserConfig($target->version));
269        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input1, false));
270        $program1 = new Index($snapshotId, $trees);
271        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
272        $snapshotId1 = 'test';
273        $input2 = new Sources([new Source('fixture.php', $source)]);
274        $profile = $execution->configuration->target;
275        $parser1 = new Parser(new ParserConfig($profile->version));
276        $trees1 = array_map(static fn (Source $source2): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source2->path), $source2->contents, $source2->declarationsOnly))), iterator_to_array($input2, false));
277        $program = new Index($snapshotId1, $trees1);
278        $context1 = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
279        $body1 = $context1->program->callable($symbol);
280        self::assertNotNull($body1);
281        [$context, $body] = [$context1, $body1];
282        $state = new State();
283        (new EntryProperties($context))->apply($body, Term::parameter('this', 'Box'), ['order' => Term::parameter('order')], $state);
284        $value = $state->memory->cells['object:this']->operands['Box::order'];
285        self::assertFalse($value->isConcrete());
286        self::assertSame('string', $value->attributes['type'] ?? null);
287    }
288    /**
289     * @param string $symbol Entry callable
290     * @param Term|null $receiver Bound receiver
291     * @param array<string, Term> $properties Supplied values
292     */
293    #[DataProvider('providerRejected')]
294    public function testApplyRejectsPropertiesNoPhpObjectCanHave(string $symbol, ?Term $receiver, array $properties, string $message): void
295    {
296        $source = '<?php declare(strict_types=1); class Base{private string $table="users";protected ?int $limit=null;}' . 'final class Box extends Base{private string $order="name";public static int $count=0;public int|string $key=0;public $loose;function run(){}static function make(){}}function free(){}';
297        $budget = new Budget();
298        $configuration = new DeriverConfig();
299        $contributions = new Contributions();
300        $input = new Sources([new Source('fixture.php', $source)]);
301        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
302        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
303        $contributions1 = $providers->contributions;
304        $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
305        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
306        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
307        $snapshotId = $identity->id;
308        $input1 = $providers->input;
309        $parser = new Parser(new ParserConfig($target->version));
310        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input1, false));
311        $program1 = new Index($snapshotId, $trees);
312        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
313        $snapshotId1 = 'test';
314        $input2 = new Sources([new Source('fixture.php', $source)]);
315        $profile = $execution->configuration->target;
316        $parser1 = new Parser(new ParserConfig($profile->version));
317        $trees1 = array_map(static fn (Source $source2): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source2->path), $source2->contents, $source2->declarationsOnly))), iterator_to_array($input2, false));
318        $program = new Index($snapshotId1, $trees1);
319        $context1 = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
320        $body1 = $context1->program->callable($symbol);
321        self::assertNotNull($body1);
322        [$context, $body] = [$context1, $body1];
323        $this->expectException(InvalidInputException::class);
324        $this->expectExceptionMessage($message);
325        (new EntryProperties($context))->apply($body, $receiver, $properties, new State());
326    }
327    /**
328     * @return iterable<string, array{string, Term|null, array<string, Term>, string}>
329     */
330    public static function providerRejected(): iterable
331    {
332        $value = ['order' => Term::constant('x')];
333        yield 'function entry' => ['free', null, $value, 'Entry properties require an instance receiver: free'];
334        yield 'static entry' => ['Box::make', null, $value, 'Entry properties require an instance receiver: Box::make'];
335        yield 'anonymous receiver identity' => ['Box::run', new Term(TermKind::Object, attributes: ['class' => 'Box']), $value, 'Entry properties require an instance receiver'];
336        yield 'undeclared property' => ['Box::run', Term::parameter('this', 'Box'), ['missing' => Term::constant('x')], 'Entry property is not a declared instance property: Box::$missing'];
337        yield 'static property' => ['Box::run', Term::parameter('this', 'Box'), ['count' => Term::constant(1)], 'Entry property is not a declared instance property: Box::$count'];
338        yield 'scalar type violation' => ['Box::run', Term::parameter('this', 'Box'), ['order' => Term::constant(1)], 'Entry property value does not satisfy the declared type string: Box::$order'];
339        yield 'nullable type violation' => ['Box::run', Term::parameter('this', 'Box'), ['limit' => Term::constant('ten')], 'Entry property value does not satisfy the declared type int|null: Box::$limit'];
340        yield 'union type violation' => ['Box::run', Term::parameter('this', 'Box'), ['key' => Term::constant(1.5)], 'Entry property value does not satisfy the declared type int|string: Box::$key'];
341    }
342}
343