packages/deriver/tests/Unit/Deriver/Evaluator/Execution/Call/Native/InvocationTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Execution\Call\Native;
6
7use Deriver\Deriver;
8use Deriver\Deriver\Candidate\ResultRef;
9use Deriver\Deriver\Candidate\Snapshot;
10use Deriver\Deriver\Candidate\Statistics;
11use Deriver\Deriver\Contributions;
12use Deriver\Deriver\DeriverConfig;
13use Deriver\Deriver\Evaluator\Call\BoundInstruction;
14use Deriver\Deriver\Evaluator\Call\Evaluators;
15use Deriver\Deriver\Evaluator\Call\Extensions;
16use Deriver\Deriver\Evaluator\Call\Provider\DispatchDecision;
17use Deriver\Deriver\Evaluator\Call\Provider\DispatchRequest;
18use Deriver\Deriver\Evaluator\Call\Registrations;
19use Deriver\Deriver\Evaluator\Call\StateRegistry;
20use Deriver\Deriver\Evaluator\EvaluatorConfig;
21use Deriver\Deriver\Evaluator\Evidence\Frontier;
22use Deriver\Deriver\Evaluator\Execution\Call\Allocation;
23use Deriver\Deriver\Evaluator\Execution\Call\ArgumentBinding;
24use Deriver\Deriver\Evaluator\Execution\Call\ArgumentOrder;
25use Deriver\Deriver\Evaluator\Execution\Call\CallExecutor;
26use Deriver\Deriver\Evaluator\Execution\Call\CallResolution;
27use Deriver\Deriver\Evaluator\Execution\Call\Creation\Access;
28use Deriver\Deriver\Evaluator\Execution\Call\Member\Invocation as MemberInvocation;
29use Deriver\Deriver\Evaluator\Execution\Call\MethodInvocation;
30use Deriver\Deriver\Evaluator\Execution\Call\Native\Invocation;
31use Deriver\Deriver\Evaluator\Execution\Call\Native\Properties;
32use Deriver\Deriver\Evaluator\Execution\Call\Native\Signatures;
33use Deriver\Deriver\Evaluator\Execution\Call\ParameterBinding;
34use Deriver\Deriver\Evaluator\Execution\Call\PassedArgument;
35use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Arguments;
36use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Creation;
37use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Methods;
38use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Modes;
39use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Resolution;
40use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Target;
41use Deriver\Deriver\Evaluator\Execution\Call\Preparation\Transfer;
42use Deriver\Deriver\Evaluator\Execution\Call\ProviderDispatch;
43use Deriver\Deriver\Evaluator\Execution\Call\TypeBinding;
44use Deriver\Deriver\Evaluator\Execution\Call\TypeCheck;
45use Deriver\Deriver\Evaluator\Execution\Call\UnknownCall;
46use Deriver\Deriver\Evaluator\Execution\Completion\Alternative;
47use Deriver\Deriver\Evaluator\Execution\Completion\Assessment;
48use Deriver\Deriver\Evaluator\Execution\Completion\Completion;
49use Deriver\Deriver\Evaluator\Execution\Completion\CompletionKind;
50use Deriver\Deriver\Evaluator\Execution\Completion\StorageSnapshot;
51use Deriver\Deriver\Evaluator\Execution\Constant\ClassNames;
52use Deriver\Deriver\Evaluator\Execution\Context;
53use Deriver\Deriver\Evaluator\Execution\Control\ExceptionChain;
54use Deriver\Deriver\Evaluator\Execution\Control\ExceptionMatch;
55use Deriver\Deriver\Evaluator\Execution\Control\Handler;
56use Deriver\Deriver\Evaluator\Execution\Control\ObservationLimit;
57use Deriver\Deriver\Evaluator\Execution\Control\StateJoin;
58use Deriver\Deriver\Evaluator\Execution\Control\Unwinding;
59use Deriver\Deriver\Evaluator\Execution\Demand\Cell;
60use Deriver\Deriver\Evaluator\Execution\Demand\Components;
61use Deriver\Deriver\Evaluator\Execution\Demand\Discovery;
62use Deriver\Deriver\Evaluator\Execution\Demand\Key;
63use Deriver\Deriver\Evaluator\Execution\Demand\Table;
64use Deriver\Deriver\Evaluator\Execution\Dependencies;
65use Deriver\Deriver\Evaluator\Execution\Evaluator;
66use Deriver\Deriver\Evaluator\Execution\EvaluatorConfig as ExecutionEvaluatorConfig;
67use Deriver\Deriver\Evaluator\Execution\Havoc;
68use Deriver\Deriver\Evaluator\Execution\InstructionTransfer;
69use Deriver\Deriver\Evaluator\Execution\Memory\Location;
70use Deriver\Deriver\Evaluator\Execution\Memory\Materialization;
71use Deriver\Deriver\Evaluator\Execution\Memory\Memory;
72use Deriver\Deriver\Evaluator\Execution\Memory\ReferenceConstraint;
73use Deriver\Deriver\Evaluator\Execution\Memory\Slots\SlotReference;
74use Deriver\Deriver\Evaluator\Execution\Memory\Slots\StateStorage;
75use Deriver\Deriver\Evaluator\Execution\Memory\StorageCapture;
76use Deriver\Deriver\Evaluator\Execution\ObservationCollector;
77use Deriver\Deriver\Evaluator\Execution\Operation\Conversions;
78use Deriver\Deriver\Evaluator\Execution\Operation\ScalarErrors;
79use Deriver\Deriver\Evaluator\Execution\State;
80use Deriver\Deriver\Evaluator\Execution\Summary\CompletionRecord;
81use Deriver\Deriver\Evaluator\Execution\Summary\Evaluation;
82use Deriver\Deriver\Evaluator\Execution\Summary\Invocation as SummaryInvocation;
83use Deriver\Deriver\Evaluator\Execution\Summary\Isolation;
84use Deriver\Deriver\Evaluator\Execution\Trace\Derivation;
85use Deriver\Deriver\Evaluator\Execution\Transfer\CallableTransfer;
86use Deriver\Deriver\Evaluator\Execution\Transfer\ConstantTransfer;
87use Deriver\Deriver\Evaluator\Execution\Transfer\MemoryStep;
88use Deriver\Deriver\Evaluator\Execution\Transfer\ObjectAccess;
89use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyAccessCheck;
90use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyLookup;
91use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyMagic;
92use Deriver\Deriver\Evaluator\Execution\Transfer\PropertySlot;
93use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyTransfer;
94use Deriver\Deriver\Evaluator\Execution\Transfer\PureStep;
95use Deriver\Deriver\Evaluator\Execution\Transfer\ReferenceAssignment;
96use Deriver\Deriver\Evaluator\Request\Budget;
97use Deriver\Deriver\Evaluator\Request\EntryPoint;
98use Deriver\Deriver\Evaluator\Request\QueryScope;
99use Deriver\Deriver\Evaluator\Request\ReturnQuery;
100use Deriver\Deriver\Evaluator\Scalar\Arithmetic;
101use Deriver\Deriver\Evaluator\Scalar\Arrays;
102use Deriver\Deriver\Evaluator\Scalar\Comparison;
103use Deriver\Deriver\Evaluator\Scalar\Identity;
104use Deriver\Deriver\Evaluator\Scalar\NumericString;
105use Deriver\Deriver\Evaluator\Scalar\Operations;
106use Deriver\Deriver\Evaluator\TargetProfile;
107use Deriver\Deriver\Evaluator\Term;
108use Deriver\Deriver\Evaluator\TermKind;
109use Deriver\Deriver\Execution\DerivationResult;
110use Deriver\Deriver\Execution\QueryExecution;
111use Deriver\Deriver\Execution\ResultAssessment;
112use Deriver\Deriver\Identity\QueryEncoding;
113use Deriver\Deriver\Identity\ValueGraph;
114use Deriver\Deriver\Lowerer\AggregateLowering;
115use Deriver\Deriver\Lowerer\AssignmentLowering;
116use Deriver\Deriver\Lowerer\CallLowering;
117use Deriver\Deriver\Lowerer\Control\DestructuringLowering;
118use Deriver\Deriver\Lowerer\Control\ExceptionLowering;
119use Deriver\Deriver\Lowerer\Declaration\CallableIdentity;
120use Deriver\Deriver\Lowerer\Declaration\CallableSource;
121use Deriver\Deriver\Lowerer\Declaration\ConstantSignatures;
122use Deriver\Deriver\Lowerer\Declaration\Index;
123use Deriver\Deriver\Lowerer\Declaration\Indexer;
124use Deriver\Deriver\Lowerer\Declaration\Metadata\ClassDeclaration;
125use Deriver\Deriver\Lowerer\Declaration\Metadata\PropertyDeclaration;
126use Deriver\Deriver\Lowerer\Declaration\Traits\Composition;
127use Deriver\Deriver\Lowerer\EffectInspection;
128use Deriver\Deriver\Lowerer\ExpressionLowering;
129use Deriver\Deriver\Lowerer\Graph\Argument;
130use Deriver\Deriver\Lowerer\Graph\BasicBlock;
131use Deriver\Deriver\Lowerer\Graph\CallableGraph;
132use Deriver\Deriver\Lowerer\Graph\CatchTarget;
133use Deriver\Deriver\Lowerer\Graph\ExceptionRegion;
134use Deriver\Deriver\Lowerer\Graph\Instruction;
135use Deriver\Deriver\Lowerer\Graph\Parameter;
136use Deriver\Deriver\Lowerer\Graph\Terminator;
137use Deriver\Deriver\Lowerer\Hierarchy\Access as HierarchyAccess;
138use Deriver\Deriver\Lowerer\Hierarchy\Builtins;
139use Deriver\Deriver\Lowerer\Hierarchy\Dispatch;
140use Deriver\Deriver\Lowerer\InstructionEmitter;
141use Deriver\Deriver\Lowerer\Lowerer;
142use Deriver\Deriver\Lowerer\LoweringScope;
143use Deriver\Deriver\Lowerer\StatementLowering;
144use Deriver\Deriver\MicroEvaluatorConversion;
145use Deriver\Deriver\Parser\Node\File;
146use Deriver\Deriver\Parser\Parser;
147use Deriver\Deriver\Parser\ParserConfig;
148use Deriver\Deriver\Parser\TargetSyntax;
149use Deriver\Deriver\Providers\ProviderExpansion;
150use Deriver\Deriver\Resolver\AssignmentPatterns;
151use Deriver\Deriver\Resolver\ClassScope;
152use Deriver\Deriver\Resolver\ExpressionValidation;
153use Deriver\Deriver\Resolver\MagicContext;
154use Deriver\Deriver\Resolver\Resolver;
155use Deriver\Deriver\Selection\QueryValidation;
156use Deriver\Deriver\SnapshotIdentity;
157use Deriver\Deriver\Sources\LineMap;
158use Deriver\Deriver\Sources\Path;
159use Deriver\Deriver\Sources\Source;
160use Deriver\Deriver\Sources\SourceRef;
161use Deriver\Deriver\Sources\Sources;
162use Deriver\Exception\ParserException;
163use Deriver\Exception\ResolutionException;
164use JsonException;
165use PHPUnit\Framework\Attributes\CoversClass;
166use PHPUnit\Framework\Attributes\DataProvider;
167use PHPUnit\Framework\Attributes\Small;
168use PHPUnit\Framework\Attributes\UsesClass;
169use PHPUnit\Framework\TestCase;
170
171/**
172 * @covers \Deriver\Deriver\Evaluator\Execution\Call\Native\Invocation
173 */
174#[UsesClass(Resolver::class)]
175#[UsesClass(ExpressionValidation::class)]
176#[UsesClass(ResolutionException::class)]
177#[UsesClass(ParserConfig::class)]
178#[UsesClass(ParserException::class)]
179#[CoversClass(Invocation::class)]
180#[UsesClass(QueryExecution::class)]
181#[UsesClass(QueryValidation::class)]
182#[UsesClass(ResultAssessment::class)]
183#[UsesClass(Deriver::class)]
184#[UsesClass(Argument::class)]
185#[UsesClass(BasicBlock::class)]
186#[UsesClass(CallableGraph::class)]
187#[UsesClass(CallableIdentity::class)]
188#[UsesClass(CatchTarget::class)]
189#[UsesClass(ClassDeclaration::class)]
190#[UsesClass(ExceptionRegion::class)]
191#[UsesClass(Instruction::class)]
192#[UsesClass(Parameter::class)]
193#[UsesClass(PropertyDeclaration::class)]
194#[UsesClass(Terminator::class)]
195#[UsesClass(Allocation::class)]
196#[UsesClass(ArgumentBinding::class)]
197#[UsesClass(ArgumentOrder::class)]
198#[UsesClass(CallExecutor::class)]
199#[UsesClass(CallResolution::class)]
200#[UsesClass(Access::class)]
201#[UsesClass(Builtins::class)]
202#[UsesClass(Dispatch::class)]
203#[UsesClass(HierarchyAccess::class)]
204#[UsesClass(MemberInvocation::class)]
205#[UsesClass(MethodInvocation::class)]
206#[UsesClass(Properties::class)]
207#[UsesClass(Signatures::class)]
208#[UsesClass(ParameterBinding::class)]
209#[UsesClass(PassedArgument::class)]
210#[UsesClass(Arguments::class)]
211#[UsesClass(Creation::class)]
212#[UsesClass(Methods::class)]
213#[UsesClass(Modes::class)]
214#[UsesClass(Resolution::class)]
215#[UsesClass(Target::class)]
216#[UsesClass(Transfer::class)]
217#[UsesClass(ProviderDispatch::class)]
218#[UsesClass(TypeBinding::class)]
219#[UsesClass(TypeCheck::class)]
220#[UsesClass(UnknownCall::class)]
221#[UsesClass(Completion::class)]
222#[UsesClass(ClassNames::class)]
223#[UsesClass(Context::class)]
224#[UsesClass(ExceptionChain::class)]
225#[UsesClass(ExceptionMatch::class)]
226#[UsesClass(Handler::class)]
227#[UsesClass(ObservationLimit::class)]
228#[UsesClass(StateJoin::class)]
229#[UsesClass(Unwinding::class)]
230#[UsesClass(Cell::class)]
231#[UsesClass(Components::class)]
232#[UsesClass(Discovery::class)]
233#[UsesClass(Key::class)]
234#[UsesClass(Table::class)]
235#[UsesClass(Dependencies::class)]
236#[UsesClass(Havoc::class)]
237#[UsesClass(InstructionTransfer::class)]
238#[UsesClass(Evaluator::class)]
239#[UsesClass(SlotReference::class)]
240#[UsesClass(StateStorage::class)]
241#[UsesClass(ObservationCollector::class)]
242#[UsesClass(Conversions::class)]
243#[UsesClass(ScalarErrors::class)]
244#[UsesClass(State::class)]
245#[UsesClass(CompletionRecord::class)]
246#[UsesClass(Evaluation::class)]
247#[UsesClass(SummaryInvocation::class)]
248#[UsesClass(Isolation::class)]
249#[UsesClass(CallableTransfer::class)]
250#[UsesClass(ConstantTransfer::class)]
251#[UsesClass(MemoryStep::class)]
252#[UsesClass(ObjectAccess::class)]
253#[UsesClass(PropertyAccessCheck::class)]
254#[UsesClass(PropertyLookup::class)]
255#[UsesClass(PropertyMagic::class)]
256#[UsesClass(PropertySlot::class)]
257#[UsesClass(PropertyTransfer::class)]
258#[UsesClass(PureStep::class)]
259#[UsesClass(ReferenceAssignment::class)]
260#[UsesClass(Location::class)]
261#[UsesClass(Materialization::class)]
262#[UsesClass(Memory::class)]
263#[UsesClass(ReferenceConstraint::class)]
264#[UsesClass(StorageCapture::class)]
265#[UsesClass(DispatchDecision::class)]
266#[UsesClass(DispatchRequest::class)]
267#[UsesClass(Extensions::class)]
268#[UsesClass(ProviderExpansion::class)]
269#[UsesClass(Evaluators::class)]
270#[UsesClass(StateRegistry::class)]
271#[UsesClass(DeriverConfig::class)]
272#[UsesClass(EntryPoint::class)]
273#[UsesClass(Sources::class)]
274#[UsesClass(Path::class)]
275#[UsesClass(Snapshot::class)]
276#[UsesClass(Source::class)]
277#[UsesClass(TargetProfile::class)]
278#[UsesClass(Budget::class)]
279#[UsesClass(QueryScope::class)]
280#[UsesClass(ReturnQuery::class)]
281#[UsesClass(ResultRef::class)]
282#[UsesClass(SourceRef::class)]
283#[UsesClass(Alternative::class)]
284#[UsesClass(Assessment::class)]
285#[UsesClass(Derivation::class)]
286#[UsesClass(DerivationResult::class)]
287#[UsesClass(Frontier::class)]
288#[UsesClass(QueryEncoding::class)]
289#[UsesClass(ValueGraph::class)]
290#[UsesClass(Statistics::class)]
291#[UsesClass(StorageSnapshot::class)]
292#[UsesClass(Parser::class)]
293#[UsesClass(File::class)]
294#[UsesClass(AggregateLowering::class)]
295#[UsesClass(AssignmentLowering::class)]
296#[UsesClass(CallLowering::class)]
297#[UsesClass(Lowerer::class)]
298#[UsesClass(DestructuringLowering::class)]
299#[UsesClass(ExceptionLowering::class)]
300#[UsesClass(EffectInspection::class)]
301#[UsesClass(ExpressionLowering::class)]
302#[UsesClass(InstructionEmitter::class)]
303#[UsesClass(LoweringScope::class)]
304#[UsesClass(StatementLowering::class)]
305#[UsesClass(ConstantSignatures::class)]
306#[UsesClass(CallableSource::class)]
307#[UsesClass(Indexer::class)]
308#[UsesClass(Index::class)]
309#[UsesClass(Composition::class)]
310#[UsesClass(LineMap::class)]
311#[UsesClass(MagicContext::class)]
312#[UsesClass(AssignmentPatterns::class)]
313#[UsesClass(ClassScope::class)]
314#[UsesClass(TargetSyntax::class)]
315#[UsesClass(Arithmetic::class)]
316#[UsesClass(Arrays::class)]
317#[UsesClass(Comparison::class)]
318#[UsesClass(Identity::class)]
319#[UsesClass(NumericString::class)]
320#[UsesClass(Operations::class)]
321#[UsesClass(Term::class)]
322#[Small]
323final class InvocationTest extends TestCase
324{
325    public function testApplyChecksInternalConstructorTypes(): void
326    {
327        $source = '<?php function target(){try{new Exception(previous:new stdClass);}catch(TypeError $e){return "type";}return 999;}';
328        $symbol = 'target';
329        $input = new Sources([new Source('fixture.php', $source)]);
330        $configuration = new DeriverConfig();
331        $contributions = new Contributions();
332        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
333        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
334        $contributions1 = $providers->contributions;
335        $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);
336        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
337        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
338        $snapshotId = $identity->id;
339        $input1 = $providers->input;
340        $parser = new Parser(new ParserConfig($target->version));
341        $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));
342        $program = new Index($snapshotId, $trees);
343        $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
344        self::assertSame('type', $result->normalOutcomes[0]->values['return']->native());
345        self::assertSame([], $result->frontiers);
346    }
347    public function testCoercionsAppliesNullConversionOnlyInWeakNativeCalls(): void
348    {
349        $source = '<?php function target(){return 1;}';
350        $budget = new Budget();
351        $configuration = new DeriverConfig();
352        $contributions = new Contributions();
353        $input = new Sources([new Source('fixture.php', $source)]);
354        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
355        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
356        $contributions1 = $providers->contributions;
357        $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);
358        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
359        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
360        $snapshotId = $identity->id;
361        $input1 = $providers->input;
362        $parser = new Parser(new ParserConfig($target->version));
363        $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));
364        $program1 = new Index($snapshotId, $trees);
365        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
366        $snapshotId1 = 'test';
367        $input2 = new Sources([new Source('fixture.php', $source)]);
368        $profile = $execution->configuration->target;
369        $parser1 = new Parser(new ParserConfig($profile->version));
370        $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));
371        $program = new Index($snapshotId1, $trees1);
372        $invocation = new Invocation(new Evaluator(new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators)));
373        $source3 = '<?php function target(){return 1;}';
374        $budget1 = new Budget();
375        $configuration1 = new DeriverConfig();
376        $contributions2 = new Contributions();
377        $input3 = new Sources([new Source('fixture.php', $source3)]);
378        $target1 = new TargetProfile($configuration1->phpVersion, $configuration1->integerBits, $configuration1->floatPrecision);
379        $providers1 = new ProviderExpansion($input3, array_map(Term::fromNative(...), $configuration1->environment), $contributions2);
380        $contributions3 = $providers1->contributions;
381        $evaluators1 = new Evaluators(new TargetProfile($configuration1->phpVersion, $configuration1->integerBits, $configuration1->floatPrecision), new Registrations($contributions3->evaluators, $contributions3->providers, $contributions3->domains, $contributions3->intrinsics, $contributions3->stateSlots), $configuration1->standardEvaluators);
382        $settings1 = new EvaluatorConfig($target1, $providers1->environment, $configuration1->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration1->evaluators));
383        $identity1 = new SnapshotIdentity($providers1->input, $settings1, $evaluators1, $providers1->manifest);
384        $snapshotId2 = $identity1->id;
385        $input4 = $providers1->input;
386        $parser2 = new Parser(new ParserConfig($target1->version));
387        $trees2 = array_map(static fn (Source $source4): File => (new Resolver())->resolve($parser2->parse(new Source(Path::normalize($source4->path), $source4->contents, $source4->declarationsOnly))), iterator_to_array($input4, false));
388        $program3 = new Index($snapshotId2, $trees2);
389        $execution1 = new QueryExecution($program3, new ExecutionEvaluatorConfig($target1, $providers1->environment, $configuration1->standardEvaluators), $evaluators1, $identity1->snapshot(array_map(Frontier::fromDiagnostic(...), $program3->diagnostics())));
390        $snapshotId3 = 'test';
391        $input5 = new Sources([new Source('fixture.php', $source3)]);
392        $profile1 = $execution1->configuration->target;
393        $parser3 = new Parser(new ParserConfig($profile1->version));
394        $trees3 = array_map(static fn (Source $source5): File => (new Resolver())->resolve($parser3->parse(new Source(Path::normalize($source5->path), $source5->contents, $source5->declarationsOnly))), iterator_to_array($input5, false));
395        $program2 = new Index($snapshotId3, $trees3);
396        $signature = (new Signatures((new Context($program2, new ReturnQuery('target', budget: $budget1), $execution1->configuration, $execution1->evaluators))->program))->graph('Exception', '__construct', new SourceRef('s', 'x.php', 0, 1));
397        $actuals = [new PassedArgument(Term::constant(null), name: 'message')];
398        self::assertSame('', $invocation->coercions($signature, $actuals, false)[0]->value->literal);
399        self::assertNull($invocation->coercions($signature, $actuals, true)[0]->value->literal);
400    }
401    public function testInitializeRetainsInheritedNonzeroCodeWhenPassedZero(): void
402    {
403        $source = '<?php class X extends Exception{protected $message="old";protected $code=9;}function target(){$e=new X(code:0);return [$e->getMessage(),$e->getCode()];}';
404        $symbol = 'target';
405        $input = new Sources([new Source('fixture.php', $source)]);
406        $configuration = new DeriverConfig();
407        $contributions = new Contributions();
408        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
409        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
410        $contributions1 = $providers->contributions;
411        $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);
412        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
413        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
414        $snapshotId = $identity->id;
415        $input1 = $providers->input;
416        $parser = new Parser(new ParserConfig($target->version));
417        $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));
418        $program = new Index($snapshotId, $trees);
419        $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
420        self::assertSame(['', 9], $result->normalOutcomes[0]->values['return']->native());
421        self::assertSame([], $result->frontiers);
422    }
423    public function testAssignedPreservesPreviousAndNormalizesLineDefault(): void
424    {
425        $source = '<?php function target(){return 1;}';
426        $budget = new Budget();
427        $configuration = new DeriverConfig();
428        $contributions = new Contributions();
429        $input = new Sources([new Source('fixture.php', $source)]);
430        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
431        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
432        $contributions1 = $providers->contributions;
433        $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);
434        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
435        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
436        $snapshotId = $identity->id;
437        $input1 = $providers->input;
438        $parser = new Parser(new ParserConfig($target->version));
439        $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));
440        $program1 = new Index($snapshotId, $trees);
441        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
442        $snapshotId1 = 'test';
443        $input2 = new Sources([new Source('fixture.php', $source)]);
444        $profile = $execution->configuration->target;
445        $parser1 = new Parser(new ParserConfig($profile->version));
446        $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));
447        $program = new Index($snapshotId1, $trees1);
448        $invocation = new Invocation(new Evaluator(new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators)));
449        $entry = new State();
450        $entry->memory->write($entry->local('filename'), Term::constant('chosen.php'));
451        self::assertNull($invocation->assigned('previous', Term::constant(null), $entry));
452        self::assertSame(0, $invocation->assigned('line', Term::constant(null), $entry)?->literal);
453        self::assertNull($invocation->assigned('code', Term::constant(0), $entry));
454    }
455    #[DataProvider('providerNativeCoercions')]
456    public function testCoercionsUsesParameterPositionAndNameWithoutChangingReferenceMetadata(?string $name, int $position, Term $input, Term $expected): void
457    {
458        $source = '<?php function target(){return 1;}';
459        $budget = new Budget();
460        $configuration = new DeriverConfig();
461        $contributions = new Contributions();
462        $input1 = new Sources([new Source('fixture.php', $source)]);
463        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
464        $providers = new ProviderExpansion($input1, array_map(Term::fromNative(...), $configuration->environment), $contributions);
465        $contributions1 = $providers->contributions;
466        $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);
467        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
468        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
469        $snapshotId = $identity->id;
470        $input2 = $providers->input;
471        $parser = new Parser(new ParserConfig($target->version));
472        $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($input2, false));
473        $program1 = new Index($snapshotId, $trees);
474        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
475        $snapshotId1 = 'test';
476        $input3 = new Sources([new Source('fixture.php', $source)]);
477        $profile = $execution->configuration->target;
478        $parser1 = new Parser(new ParserConfig($profile->version));
479        $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($input3, false));
480        $program = new Index($snapshotId1, $trees1);
481        $context = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
482        $signature = (new Signatures($context->program))->graph('ErrorException', '__construct', new SourceRef('s', 'a.php', 0, 1));
483        $location = new Location('argument', ['key']);
484        $argument = new PassedArgument($input, $name, $location);
485        $arguments = array_fill(0, $position, new PassedArgument(Term::constant(1)));
486        $arguments[] = $argument;
487        $result = (new Invocation(new Evaluator($context)))->coercions($signature, $arguments, false);
488        self::assertSame($expected->kind->value, $result[$position]->value->kind->value);
489        self::assertSame($expected->literal, $result[$position]->value->literal);
490        self::assertSame($name, $result[$position]->name);
491        self::assertSame($location, $result[$position]->location);
492        self::assertCount($position + 1, $result);
493    }
494    /**
495     * @return iterable<string,array{?string,int,Term,Term}>
496     */
497    public static function providerNativeCoercions(): iterable
498    {
499        yield 'positional message' => [null, 0, Term::constant(null), Term::constant('')];
500        yield 'positional code' => [null, 1, Term::constant(null), Term::constant(0)];
501        yield 'positional severity' => [null, 2, Term::constant(null), Term::constant(0)];
502        yield 'nullable filename' => [null, 3, Term::constant(null), Term::constant(null)];
503        yield 'nullable line' => [null, 4, Term::constant(null), Term::constant(null)];
504        yield 'named message' => ['message', 0, Term::constant(null), Term::constant('')];
505        yield 'named code' => ['code', 0, Term::constant(null), Term::constant(0)];
506        yield 'unknown parameter' => ['missing', 0, Term::constant(null), Term::constant(null)];
507        yield 'extra positional' => [null, 6, Term::constant(null), Term::constant(null)];
508        yield 'false unchanged' => ['message', 0, Term::constant(false), Term::constant(false)];
509        yield 'symbolic unchanged' => ['message', 0, Term::parameter('x'), Term::parameter('x')];
510    }
511    #[DataProvider('providerAssignedFields')]
512    public function testAssignedFollowsNativeFieldRetentionAndFilenameRules(string $name, Term $value, Term $filename, ?Term $expected): void
513    {
514        $source = '<?php function target(){return 1;}';
515        $budget = new Budget();
516        $configuration = new DeriverConfig();
517        $contributions = new Contributions();
518        $input = new Sources([new Source('fixture.php', $source)]);
519        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
520        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
521        $contributions1 = $providers->contributions;
522        $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);
523        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
524        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
525        $snapshotId = $identity->id;
526        $input1 = $providers->input;
527        $parser = new Parser(new ParserConfig($target->version));
528        $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));
529        $program1 = new Index($snapshotId, $trees);
530        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
531        $snapshotId1 = 'test';
532        $input2 = new Sources([new Source('fixture.php', $source)]);
533        $profile = $execution->configuration->target;
534        $parser1 = new Parser(new ParserConfig($profile->version));
535        $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));
536        $program = new Index($snapshotId1, $trees1);
537        $context = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
538        $entry = new State();
539        $entry->memory->write($entry->local('filename'), $filename);
540        $result = (new Invocation(new Evaluator($context)))->assigned($name, $value, $entry);
541        self::assertEquals($expected, $result);
542    }
543    /**
544     * @return iterable<string,array{string,Term,Term,?Term}>
545     */
546    public static function providerAssignedFields(): iterable
547    {
548        $null = Term::constant(null);
549        yield 'zero code' => ['code', Term::constant(0), $null, null];
550        yield 'nonzero code' => ['code', Term::constant(7), $null, Term::constant(7)];
551        yield 'symbolic code' => ['code', Term::parameter('n', 'int'), $null, Term::parameter('n', 'int')];
552        yield 'null previous' => ['previous', $null, $null, null];
553        yield 'null filename' => ['filename', $null, $null, null];
554        yield 'null line no file' => ['line', $null, $null, null];
555        yield 'null line chosen file' => ['line', $null, Term::constant('chosen.php'), Term::constant(0)];
556        yield 'null line unknown file' => ['line', $null, Term::parameter('file', 'string|null'), Term::opaque('RUNTIME_STACK', 'int')];
557        yield 'explicit line' => ['line', Term::constant(42), $null, Term::constant(42)];
558        yield 'empty message' => ['message', Term::constant(''), $null, Term::constant('')];
559    }
560    public function testApplyDeclinesUnknownNativeClassesAndMethods(): void
561    {
562        $source = '<?php function target(){return 1;}';
563        $budget = new Budget();
564        $configuration = new DeriverConfig();
565        $contributions = new Contributions();
566        $input = new Sources([new Source('fixture.php', $source)]);
567        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
568        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
569        $contributions1 = $providers->contributions;
570        $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);
571        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
572        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
573        $snapshotId = $identity->id;
574        $input1 = $providers->input;
575        $parser = new Parser(new ParserConfig($target->version));
576        $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));
577        $program1 = new Index($snapshotId, $trees);
578        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
579        $snapshotId1 = 'test';
580        $input2 = new Sources([new Source('fixture.php', $source)]);
581        $profile = $execution->configuration->target;
582        $parser1 = new Parser(new ParserConfig($profile->version));
583        $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));
584        $program = new Index($snapshotId1, $trees1);
585        $context = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
586        $invocation = new Invocation(new Evaluator($context));
587        $instruction = new BoundInstruction('i', 'method', new SourceRef('s', 'a.php', 0, 1), 'result');
588        $receiver = new Term(TermKind::Object, 'e', attributes: ['class' => 'Exception']);
589        self::assertNull($invocation->apply('UnknownClass', 'run', [], new State(), $instruction, null, false));
590        self::assertNull($invocation->apply('Exception', 'missing', [], new State(), $instruction, $receiver, false));
591        self::assertSame([], $context->frontiers);
592    }
593    #[DataProvider('providerInvalidNativeReceivers')]
594    public function testApplyRejectsCloningAndIncompatibleReceivers(string $method, ?Term $receiver): void
595    {
596        $source = '<?php function target(){return 1;}';
597        $budget = new Budget();
598        $configuration = new DeriverConfig();
599        $contributions = new Contributions();
600        $input = new Sources([new Source('fixture.php', $source)]);
601        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
602        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
603        $contributions1 = $providers->contributions;
604        $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);
605        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
606        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
607        $snapshotId = $identity->id;
608        $input1 = $providers->input;
609        $parser = new Parser(new ParserConfig($target->version));
610        $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));
611        $program1 = new Index($snapshotId, $trees);
612        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
613        $snapshotId1 = 'test';
614        $input2 = new Sources([new Source('fixture.php', $source)]);
615        $profile = $execution->configuration->target;
616        $parser1 = new Parser(new ParserConfig($profile->version));
617        $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));
618        $program = new Index($snapshotId1, $trees1);
619        $context = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
620        $instruction = new BoundInstruction('i', 'method', new SourceRef('s', 'a.php', 0, 1), 'result');
621        $paths = (new Invocation(new Evaluator($context)))->apply('Exception', $method, [], new State(), $instruction, $receiver, false);
622        self::assertNotNull($paths);
623        self::assertCount(1, $paths);
624        self::assertSame(CompletionKind::Throw, $paths[0]->completion->kind);
625        self::assertSame('Error', $paths[0]->completion->value?->literal);
626        self::assertArrayNotHasKey('result', $paths[0]->registers);
627    }
628    /**
629     * @return iterable<string,array{string,?Term}>
630     */
631    public static function providerInvalidNativeReceivers(): iterable
632    {
633        yield 'clone' => ['__clone', new Term(TermKind::Object, 'e', attributes: ['class' => 'Exception'])];
634        yield 'missing receiver' => ['getMessage', null];
635        yield 'wrong class' => ['getMessage', new Term(TermKind::Object, 'e', attributes: ['class' => 'stdClass'])];
636    }
637    #[DataProvider('providerNativeResidualMethods')]
638    public function testApplyKeepsRuntimeStackAndSerializationMethodsBehindABoundary(string $method): void
639    {
640        $source = '<?php function target(){return 1;}';
641        $budget = new Budget();
642        $configuration = new DeriverConfig();
643        $contributions = new Contributions();
644        $input = new Sources([new Source('fixture.php', $source)]);
645        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
646        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
647        $contributions1 = $providers->contributions;
648        $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);
649        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
650        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
651        $snapshotId = $identity->id;
652        $input1 = $providers->input;
653        $parser = new Parser(new ParserConfig($target->version));
654        $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));
655        $program1 = new Index($snapshotId, $trees);
656        $execution = new QueryExecution($program1, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program1->diagnostics())));
657        $snapshotId1 = 'test';
658        $input2 = new Sources([new Source('fixture.php', $source)]);
659        $profile = $execution->configuration->target;
660        $parser1 = new Parser(new ParserConfig($profile->version));
661        $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));
662        $program = new Index($snapshotId1, $trees1);
663        $context = new Context($program, new ReturnQuery('target', budget: $budget), $execution->configuration, $execution->evaluators);
664        $instruction = new BoundInstruction('i', 'method', new SourceRef('s', 'a.php', 0, 1), 'result');
665        $receiver = new Term(TermKind::Object, 'e', attributes: ['class' => 'Exception']);
666        $paths = (new Invocation(new Evaluator($context)))->apply('Exception', $method, [], new State(), $instruction, $receiver, false);
667        self::assertNotNull($paths);
668        self::assertSame(['normal', 'throw'], array_map(static fn (State $path): string => $path->completion->kind->value, $paths));
669        self::assertSame('MISSING_CALL_MODEL', array_values($context->frontiers)[0]->code);
670    }
671    /**
672     * @return iterable<string,array{string}>
673     */
674    public static function providerNativeResidualMethods(): iterable
675    {
676        yield 'trace' => ['getTrace'];
677        yield 'trace string' => ['getTraceAsString'];
678        yield 'string conversion' => ['__toString'];
679        yield 'wake up' => ['__wakeup'];
680    }
681    /**
682     * @throws JsonException If fixture metadata cannot be encoded
683     */
684    #[DataProvider('providerNativePrograms')]
685    public function testApplyPreservesOracleCheckedNativeConstructorsAndGetters(string $source, string $expected): void
686    {
687        $symbol = 'target';
688        $input = new Sources([new Source('fixture.php', $source)]);
689        $configuration = new DeriverConfig();
690        $contributions = new Contributions();
691        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
692        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
693        $contributions1 = $providers->contributions;
694        $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);
695        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
696        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
697        $snapshotId = $identity->id;
698        $input1 = $providers->input;
699        $parser = new Parser(new ParserConfig($target->version));
700        $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));
701        $program = new Index($snapshotId, $trees);
702        $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
703        self::assertSame([], $result->frontiers);
704        self::assertSame([], $result->exceptionalOutcomes);
705        self::assertCount(1, $result->normalOutcomes);
706        self::assertSame(json_decode($expected, true, flags: JSON_THROW_ON_ERROR), $result->normalOutcomes[0]->values['return']->native());
707    }
708    /**
709     * @return iterable<string,array{string,string}>
710     */
711    public static function providerNativePrograms(): iterable
712    {
713        return ['native:messageCode' => ['<?php function target(){$e=new Exception("hello",7);return [$e->getMessage(),$e->getCode(),$e->getPrevious()];}', '["hello",7,null]'], 'native:named' => ['<?php function target(){$e=new RuntimeException(code:7,message:"hello");return [$e->getMessage(),$e->getCode()];}', '["hello",7]'], 'native:inherited' => ['<?php class X extends Exception{}function target(){$e=new X(code:7,message:"hello");return [$e->getMessage(),$e->getCode()];}', '["hello",7]'], 'native:codeZero' => ['<?php class X extends Exception{protected $message="x";protected $code=9;}function target(){$a=new X;$b=new X(code:0);$c=new X(message:"a");return [$a->getMessage(),$a->getCode(),$b->getMessage(),$b->getCode(),$c->getMessage(),$c->getCode()];}', '["x",9,"",9,"a",9]'], 'native:previous' => ['<?php function target(){$p=new Exception("first");$e=new Exception(previous:$p);$previous=$e->getPrevious();$equal=$previous===$p;return [$equal,$previous->getMessage()];}', '[true,"first"]'], 'native:parent' => ['<?php class X extends Exception{function __construct(){parent::__construct("a",2);}}function target(){$e=new X;return [$e->getMessage(),$e->getCode()];}', '["a",2]'], 'native:clone' => ['<?php function target(){try{$x=clone new Exception;}catch(Error $e){return "error";}return 999;}', '"error"'], 'native:arrayMessage' => ['<?php function target(){try{new Exception([]);}catch(TypeError $e){return "type";}return 999;}', '"type"'], 'native:badCode' => ['<?php function target(){try{new Exception(code:"no");}catch(TypeError $e){return "type";}return 999;}', '"type"'], 'native:badPrevious' => ['<?php function target(){try{new Exception(previous:new stdClass);}catch(TypeError $e){return "type";}return 999;}', '"type"'], 'native:unknownNamed' => ['<?php function target(){try{new Exception(other:1);}catch(Error $e){return "name";}return 999;}', '"name"'], 'native:extra' => ['<?php function target(){try{new Exception("",0,null,1);}catch(ArgumentCountError $e){return "count";}return 999;}', '"count"'], 'native:strict' => ['<?php declare(strict_types=1);function target(){try{new Exception(1);}catch(TypeError $e){return "type";}return 999;}', '"type"'], 'native:weak' => ['<?php function target(){$e=new Exception(1,"2");return [$e->getMessage(),$e->getCode()];}', '["1",2]'], 'native:errorDefaults' => ['<?php class X extends ErrorException{protected $message="x";protected $code=9;protected int $severity=2;}function target(){$x=new X;return [$x->getMessage(),$x->getCode(),$x->getSeverity()];}', '["x",9,1]'], 'native:repeatPrevious' => ['<?php class X extends Exception{function clear(){parent::__construct();}function reset(){parent::__construct(previous:null);}}function target(){$p=new Exception;$x=new X("x",9,$p);$x->clear();$previous=$x->getPrevious();$a=[$x->getMessage(),$x->getCode(),$previous===$p];$x->reset();$previous=$x->getPrevious();return [$a,$x->getMessage(),$x->getCode(),$previous===$p];}', '[["x",9,true],"",9,true]'], 'native:severity' => ['<?php function target(){$x=new ErrorException(severity:8);return [$x->getMessage(),$x->getCode(),$x->getSeverity()];}', '["",0,8]'], 'native:getterArity' => ['<?php function target(){try{(new Exception)->getMessage(1);}catch(ArgumentCountError $e){return "count";}return 999;}', '"count"'], 'native:protected' => ['<?php function target(){try{return (new Exception("a"))->message;}catch(Error $e){return "access";}}', '"access"'], 'native:sourceProperty' => ['<?php class X extends Exception{function change(){$this->message=42;$this->code="custom";}}function target(){$e=new X;$e->change();return [$e->getMessage(),$e->getCode()];}', '["42","custom"]'], 'native:caseInsensitive' => ['<?php function target(){try{throw new runtimeexception;}catch(EXCEPTION $e){return "caught";}}', '"caught"'], 'native:errorHierarchy' => ['<?php function target(){$e=new DivisionByZeroError("zero");return [$e instanceof ArithmeticError,$e instanceof Throwable,$e->getMessage()];}', '[true,true,"zero"]'], 'native:missingMethod' => ['<?php function target(){try{(new Exception)->absent();}catch(Error $e){return "missing";}return 999;}', '"missing"'], 'native:filename' => ['<?php function target(){$e=new ErrorException(filename:"chosen.php");return [$e->getFile(),$e->getLine()];}', '["chosen.php",0]'], 'native:line' => ['<?php function target(){$e=new ErrorException(filename:"chosen.php",line:42);return [$e->getFile(),$e->getLine()];}', '["chosen.php",42]']];
714    }
715}
716