packages/deriver/tests/Integration/ExtensionFailureTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Integration;
6
7use Deriver\Deriver\Candidate\Snapshot;
8use Deriver\Deriver\Contributions;
9use Deriver\Deriver\DeriverConfig;
10use Deriver\Deriver\EvaluationOperation;
11use Deriver\Deriver\Evaluator\Call\CallDescriptor;
12use Deriver\Deriver\Evaluator\Call\CallEvaluator;
13use Deriver\Deriver\Evaluator\Call\Evaluators;
14use Deriver\Deriver\Evaluator\Call\Provider\DispatchProvider;
15use Deriver\Deriver\Evaluator\Call\Provider\Provider;
16use Deriver\Deriver\Evaluator\Call\Provider\RefinementEvaluator;
17use Deriver\Deriver\Evaluator\Call\Registrations;
18use Deriver\Deriver\Evaluator\Domain\AbstractDomain;
19use Deriver\Deriver\Evaluator\EvaluatorConfig;
20use Deriver\Deriver\Evaluator\Evidence\Frontier;
21use Deriver\Deriver\Evaluator\Execution\EvaluatorConfig as ExecutionEvaluatorConfig;
22use Deriver\Deriver\Evaluator\Index\DefinitionIndex;
23use Deriver\Deriver\Evaluator\Intrinsic\PureIntrinsic;
24use Deriver\Deriver\Evaluator\Request\ReturnQuery;
25use Deriver\Deriver\Evaluator\TargetProfile;
26use Deriver\Deriver\Evaluator\Term;
27use Deriver\Deriver\Execution\QueryExecution;
28use Deriver\Deriver\Lowerer\Declaration\Index;
29use Deriver\Deriver\MicroEvaluator;
30use Deriver\Deriver\MicroEvaluatorConversion;
31use Deriver\Deriver\Parser\Node\File;
32use Deriver\Deriver\Parser\Parser;
33use Deriver\Deriver\Parser\ParserConfig;
34use Deriver\Deriver\Providers\DeclarationProvider;
35use Deriver\Deriver\Providers\DomainProvider;
36use Deriver\Deriver\Providers\EntryPointProvider;
37use Deriver\Deriver\Providers\EnvironmentProvider;
38use Deriver\Deriver\Providers\ProviderExpansion;
39use Deriver\Deriver\Publication\CandidateQuery;
40use Deriver\Deriver\Resolver\Resolver;
41use Deriver\Deriver\SnapshotIdentity;
42use Deriver\Deriver\Sources\Path;
43use Deriver\Deriver\Sources\Source;
44use Deriver\Deriver\Sources\Sources;
45use Deriver\Exception\EvaluationContractException;
46use Deriver\Exception\EvaluationException;
47use PHPUnit\Framework\Attributes\CoversNothing;
48use PHPUnit\Framework\Attributes\Small;
49use PHPUnit\Framework\TestCase;
50use RuntimeException;
51
52#[CoversNothing]
53#[Small]
54final class ExtensionFailureTest extends TestCase
55{
56    public function testOpenPropagatesDeclarationProviderFailures(): void
57    {
58        $provider = self::createStub(DeclarationProvider::class);
59        $provider->method('id')->willReturn('broken');
60        $provider->method('version')->willReturn('1');
61        $failure = new EvaluationException('Provider export failed');
62        $provider->method('declarations')->willThrowException($failure);
63        $this->expectExceptionObject($failure);
64        $prepared1Input = new Sources([]);
65        $prepared1Configuration = new DeriverConfig();
66        $prepared1Contributions = new Contributions(providers: [$provider]);
67        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
68        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
69        $contributions = $prepared1Providers->contributions;
70        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared1Configuration->standardEvaluators);
71        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
72        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
73        $snapshotId = $prepared1Identity->id;
74        $input = $prepared1Providers->input;
75        $parser = new Parser(new ParserConfig($prepared1Target->version));
76        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
77        $prepared1Program = new Index($snapshotId, $trees);
78        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
79    }
80    public function testOpenPropagatesEnvironmentProviderFailures(): void
81    {
82        $provider = self::createStub(EnvironmentProvider::class);
83        $provider->method('id')->willReturn('broken');
84        $provider->method('version')->willReturn('1');
85        $failure = new EvaluationException('Provider export failed');
86        $provider->method('environment')->willThrowException($failure);
87        $this->expectExceptionObject($failure);
88        $prepared2Input = new Sources([]);
89        $prepared2Configuration = new DeriverConfig();
90        $prepared2Contributions = new Contributions(providers: [$provider]);
91        $prepared2Target = new TargetProfile($prepared2Configuration->phpVersion, $prepared2Configuration->integerBits, $prepared2Configuration->floatPrecision);
92        $prepared2Providers = new ProviderExpansion($prepared2Input, array_map(Term::fromNative(...), $prepared2Configuration->environment), $prepared2Contributions);
93        $contributions = $prepared2Providers->contributions;
94        $prepared2Evaluators = new Evaluators(new TargetProfile($prepared2Configuration->phpVersion, $prepared2Configuration->integerBits, $prepared2Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared2Configuration->standardEvaluators);
95        $prepared2Settings = new EvaluatorConfig($prepared2Target, $prepared2Providers->environment, $prepared2Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared2Configuration->evaluators));
96        $prepared2Identity = new SnapshotIdentity($prepared2Providers->input, $prepared2Settings, $prepared2Evaluators, $prepared2Providers->manifest);
97        $snapshotId = $prepared2Identity->id;
98        $input = $prepared2Providers->input;
99        $parser = new Parser(new ParserConfig($prepared2Target->version));
100        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
101        $prepared2Program = new Index($snapshotId, $trees);
102        $prepared2Snapshot = $prepared2Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared2Program->diagnostics()));
103    }
104    public function testOpenPropagatesEntryPointProviderFailures(): void
105    {
106        $provider = self::createStub(EntryPointProvider::class);
107        $provider->method('id')->willReturn('broken');
108        $provider->method('version')->willReturn('1');
109        $failure = new EvaluationException('Provider export failed');
110        $provider->method('entries')->willThrowException($failure);
111        $this->expectExceptionObject($failure);
112        $prepared3Input = new Sources([]);
113        $prepared3Configuration = new DeriverConfig();
114        $prepared3Contributions = new Contributions(providers: [$provider]);
115        $prepared3Target = new TargetProfile($prepared3Configuration->phpVersion, $prepared3Configuration->integerBits, $prepared3Configuration->floatPrecision);
116        $prepared3Providers = new ProviderExpansion($prepared3Input, array_map(Term::fromNative(...), $prepared3Configuration->environment), $prepared3Contributions);
117        $contributions = $prepared3Providers->contributions;
118        $prepared3Evaluators = new Evaluators(new TargetProfile($prepared3Configuration->phpVersion, $prepared3Configuration->integerBits, $prepared3Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared3Configuration->standardEvaluators);
119        $prepared3Settings = new EvaluatorConfig($prepared3Target, $prepared3Providers->environment, $prepared3Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared3Configuration->evaluators));
120        $prepared3Identity = new SnapshotIdentity($prepared3Providers->input, $prepared3Settings, $prepared3Evaluators, $prepared3Providers->manifest);
121        $snapshotId = $prepared3Identity->id;
122        $input = $prepared3Providers->input;
123        $parser = new Parser(new ParserConfig($prepared3Target->version));
124        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
125        $prepared3Program = new Index($snapshotId, $trees);
126        $prepared3Snapshot = $prepared3Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared3Program->diagnostics()));
127    }
128    public function testOpenPropagatesDomainProviderFailures(): void
129    {
130        $provider = self::createStub(DomainProvider::class);
131        $provider->method('id')->willReturn('broken');
132        $provider->method('version')->willReturn('1');
133        $failure = new EvaluationException('Provider export failed');
134        $provider->method('domains')->willThrowException($failure);
135        $this->expectExceptionObject($failure);
136        $prepared4Input = new Sources([]);
137        $prepared4Configuration = new DeriverConfig();
138        $prepared4Contributions = new Contributions(providers: [$provider]);
139        $prepared4Target = new TargetProfile($prepared4Configuration->phpVersion, $prepared4Configuration->integerBits, $prepared4Configuration->floatPrecision);
140        $prepared4Providers = new ProviderExpansion($prepared4Input, array_map(Term::fromNative(...), $prepared4Configuration->environment), $prepared4Contributions);
141        $contributions = $prepared4Providers->contributions;
142        $prepared4Evaluators = new Evaluators(new TargetProfile($prepared4Configuration->phpVersion, $prepared4Configuration->integerBits, $prepared4Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared4Configuration->standardEvaluators);
143        $prepared4Settings = new EvaluatorConfig($prepared4Target, $prepared4Providers->environment, $prepared4Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared4Configuration->evaluators));
144        $prepared4Identity = new SnapshotIdentity($prepared4Providers->input, $prepared4Settings, $prepared4Evaluators, $prepared4Providers->manifest);
145        $snapshotId = $prepared4Identity->id;
146        $input = $prepared4Providers->input;
147        $parser = new Parser(new ParserConfig($prepared4Target->version));
148        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
149        $prepared4Program = new Index($snapshotId, $trees);
150        $prepared4Snapshot = $prepared4Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared4Program->diagnostics()));
151    }
152    public function testOpenPropagatesProviderIdentityFailures(): void
153    {
154        $provider = self::createStub(Provider::class);
155        $failure = new EvaluationException('Provider implementation error');
156        $provider->method('id')->willThrowException($failure);
157        $this->expectExceptionObject($failure);
158        $prepared5Input = new Sources([]);
159        $prepared5Configuration = new DeriverConfig();
160        $prepared5Contributions = new Contributions(providers: [$provider]);
161        $prepared5Target = new TargetProfile($prepared5Configuration->phpVersion, $prepared5Configuration->integerBits, $prepared5Configuration->floatPrecision);
162        $prepared5Providers = new ProviderExpansion($prepared5Input, array_map(Term::fromNative(...), $prepared5Configuration->environment), $prepared5Contributions);
163        $contributions = $prepared5Providers->contributions;
164        $prepared5Evaluators = new Evaluators(new TargetProfile($prepared5Configuration->phpVersion, $prepared5Configuration->integerBits, $prepared5Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared5Configuration->standardEvaluators);
165        $prepared5Settings = new EvaluatorConfig($prepared5Target, $prepared5Providers->environment, $prepared5Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared5Configuration->evaluators));
166        $prepared5Identity = new SnapshotIdentity($prepared5Providers->input, $prepared5Settings, $prepared5Evaluators, $prepared5Providers->manifest);
167        $snapshotId = $prepared5Identity->id;
168        $input = $prepared5Providers->input;
169        $parser = new Parser(new ParserConfig($prepared5Target->version));
170        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
171        $prepared5Program = new Index($snapshotId, $trees);
172        $prepared5Snapshot = $prepared5Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared5Program->diagnostics()));
173    }
174    public function testOpenPropagatesModelDescriptorFailures(): void
175    {
176        $evaluator = self::createStub(CallEvaluator::class);
177        $failure = new EvaluationException('Evaluator descriptor implementation error');
178        $evaluator->method('descriptor')->willThrowException($failure);
179        $this->expectExceptionObject($failure);
180        $prepared6Input = new Sources([]);
181        $prepared6Configuration = new DeriverConfig();
182        $prepared6Contributions = new Contributions(evaluators: [$evaluator]);
183        $prepared6Target = new TargetProfile($prepared6Configuration->phpVersion, $prepared6Configuration->integerBits, $prepared6Configuration->floatPrecision);
184        $prepared6Providers = new ProviderExpansion($prepared6Input, array_map(Term::fromNative(...), $prepared6Configuration->environment), $prepared6Contributions);
185        $contributions = $prepared6Providers->contributions;
186        $prepared6Evaluators = new Evaluators(new TargetProfile($prepared6Configuration->phpVersion, $prepared6Configuration->integerBits, $prepared6Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared6Configuration->standardEvaluators);
187        $prepared6Settings = new EvaluatorConfig($prepared6Target, $prepared6Providers->environment, $prepared6Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared6Configuration->evaluators));
188        $prepared6Identity = new SnapshotIdentity($prepared6Providers->input, $prepared6Settings, $prepared6Evaluators, $prepared6Providers->manifest);
189        $snapshotId = $prepared6Identity->id;
190        $input = $prepared6Providers->input;
191        $parser = new Parser(new ParserConfig($prepared6Target->version));
192        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
193        $prepared6Program = new Index($snapshotId, $trees);
194        $prepared6Snapshot = $prepared6Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared6Program->diagnostics()));
195    }
196    public function testOpenPropagatesIntrinsicDescriptorFailures(): void
197    {
198        $intrinsic = self::createStub(PureIntrinsic::class);
199        $failure = new EvaluationException('Intrinsic descriptor implementation error');
200        $intrinsic->method('descriptor')->willThrowException($failure);
201        $this->expectExceptionObject($failure);
202        $prepared7Input = new Sources([]);
203        $prepared7Configuration = new DeriverConfig();
204        $prepared7Contributions = new Contributions(intrinsics: [$intrinsic]);
205        $prepared7Target = new TargetProfile($prepared7Configuration->phpVersion, $prepared7Configuration->integerBits, $prepared7Configuration->floatPrecision);
206        $prepared7Providers = new ProviderExpansion($prepared7Input, array_map(Term::fromNative(...), $prepared7Configuration->environment), $prepared7Contributions);
207        $contributions = $prepared7Providers->contributions;
208        $prepared7Evaluators = new Evaluators(new TargetProfile($prepared7Configuration->phpVersion, $prepared7Configuration->integerBits, $prepared7Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared7Configuration->standardEvaluators);
209        $prepared7Settings = new EvaluatorConfig($prepared7Target, $prepared7Providers->environment, $prepared7Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared7Configuration->evaluators));
210        $prepared7Identity = new SnapshotIdentity($prepared7Providers->input, $prepared7Settings, $prepared7Evaluators, $prepared7Providers->manifest);
211        $snapshotId = $prepared7Identity->id;
212        $input = $prepared7Providers->input;
213        $parser = new Parser(new ParserConfig($prepared7Target->version));
214        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
215        $prepared7Program = new Index($snapshotId, $trees);
216        $prepared7Snapshot = $prepared7Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared7Program->diagnostics()));
217    }
218    public function testOpenPropagatesDomainFailures(): void
219    {
220        $domain = self::createStub(AbstractDomain::class);
221        $failure = new EvaluationException('Domain implementation error');
222        $domain->method('bottom')->willThrowException($failure);
223        $this->expectExceptionObject($failure);
224        $prepared8Input = new Sources([]);
225        $prepared8Configuration = new DeriverConfig();
226        $prepared8Contributions = new Contributions(domains: [$domain]);
227        $prepared8Target = new TargetProfile($prepared8Configuration->phpVersion, $prepared8Configuration->integerBits, $prepared8Configuration->floatPrecision);
228        $prepared8Providers = new ProviderExpansion($prepared8Input, array_map(Term::fromNative(...), $prepared8Configuration->environment), $prepared8Contributions);
229        $contributions = $prepared8Providers->contributions;
230        $prepared8Evaluators = new Evaluators(new TargetProfile($prepared8Configuration->phpVersion, $prepared8Configuration->integerBits, $prepared8Configuration->floatPrecision), new Registrations($contributions->evaluators, $contributions->providers, $contributions->domains, $contributions->intrinsics, $contributions->stateSlots), $prepared8Configuration->standardEvaluators);
231        $prepared8Settings = new EvaluatorConfig($prepared8Target, $prepared8Providers->environment, $prepared8Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared8Configuration->evaluators));
232        $prepared8Identity = new SnapshotIdentity($prepared8Providers->input, $prepared8Settings, $prepared8Evaluators, $prepared8Providers->manifest);
233        $snapshotId = $prepared8Identity->id;
234        $input = $prepared8Providers->input;
235        $parser = new Parser(new ParserConfig($prepared8Target->version));
236        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
237        $prepared8Program = new Index($snapshotId, $trees);
238        $prepared8Snapshot = $prepared8Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared8Program->diagnostics()));
239    }
240    public function testDeriveCannotTurnAModelFailureIntoAnApplicationException(): void
241    {
242        $evaluator = self::createStub(CallEvaluator::class);
243        $evaluator->method('descriptor')->willReturn(new CallDescriptor('broken', '1', 'external'));
244        $failure = new EvaluationException('Evaluator implementation error');
245        $evaluator->method('evaluate')->willThrowException($failure);
246        $input = new Sources([new Source('fixture.php', '<?php function target(){try{return external();}catch(Throwable $e){return "hidden";}}')]);
247        $configuration = new DeriverConfig();
248        $contributions = new Contributions(evaluators: [$evaluator]);
249        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
250        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
251        $contributions1 = $providers->contributions;
252        $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);
253        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
254        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
255        $snapshotId = $identity->id;
256        $input1 = $providers->input;
257        $parser = new Parser(new ParserConfig($target->version));
258        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input1, false));
259        $program = new Index($snapshotId, $trees);
260        $session = new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics())));
261        $this->expectExceptionObject($failure);
262        $session->derive(new ReturnQuery('target'));
263    }
264    public function testMicroEvaluatorFailuresPropagateWithTheirIdentity(): void
265    {
266        $failure = new RuntimeException('Extension failed');
267        $micro = (new MicroEvaluatorConversion())->convert(new MicroEvaluator('broken', '1', EvaluationOperation::Function, 'provided', static fn () => throw $failure));
268        $target = new TargetProfile();
269        $snapshotId = 'test';
270        $input = new Sources([new Source('app.php', '<?php function target(){return provided();}')]);
271        $parser = new Parser(new ParserConfig($target->version));
272        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input, false));
273        $program = new Index($snapshotId, $trees);
274        $query = new CandidateQuery(new DefinitionIndex($program), new EvaluatorConfig($target, evaluators: [$micro]), new Evaluators($target), new Snapshot('test', [], [], $target, ''));
275        $this->expectException(EvaluationContractException::class);
276        $this->expectExceptionMessage('broken: Extension failed');
277        $query->derive(new ReturnQuery('target'));
278    }
279    public function testDerivePropagatesDispatchFailures(): void
280    {
281        $provider = self::createStub(DispatchProvider::class);
282        $provider->method('id')->willReturn('broken');
283        $provider->method('version')->willReturn('1');
284        $failure = new EvaluationException('Dispatch implementation error');
285        $provider->method('resolve')->willThrowException($failure);
286        $input = new Sources([new Source('fixture.php', '<?php interface Service {function value();} function target(Service $service){return $service->value();}')]);
287        $configuration = new DeriverConfig();
288        $contributions = new Contributions(providers: [$provider]);
289        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
290        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
291        $contributions1 = $providers->contributions;
292        $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);
293        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
294        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
295        $snapshotId = $identity->id;
296        $input1 = $providers->input;
297        $parser = new Parser(new ParserConfig($target->version));
298        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input1, false));
299        $program = new Index($snapshotId, $trees);
300        $session = new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics())));
301        $this->expectExceptionObject($failure);
302        $session->derive(new ReturnQuery('target'));
303    }
304    public function testDerivePropagatesRefinementFailures(): void
305    {
306        $provider = self::createStub(RefinementEvaluator::class);
307        $provider->method('id')->willReturn('broken');
308        $provider->method('version')->willReturn('1');
309        $failure = new EvaluationException('Refinement implementation error');
310        $provider->method('refine')->willThrowException($failure);
311        $input = new Sources([new Source('fixture.php', '<?php function target(bool $flag){return $flag ? 1 : 2;}')]);
312        $configuration = new DeriverConfig();
313        $contributions = new Contributions(providers: [$provider]);
314        $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
315        $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
316        $contributions1 = $providers->contributions;
317        $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);
318        $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
319        $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
320        $snapshotId = $identity->id;
321        $input1 = $providers->input;
322        $parser = new Parser(new ParserConfig($target->version));
323        $trees = array_map(static fn (Source $source): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source->path), $source->contents, $source->declarationsOnly))), iterator_to_array($input1, false));
324        $program = new Index($snapshotId, $trees);
325        $session = new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics())));
326        $this->expectExceptionObject($failure);
327        $session->derive(new ReturnQuery('target'));
328    }
329}
330