type instanceof InterfaceType || $shell->type instanceof NativeClassType); $function = $this->interfaceInferringContainer->inferFunctionFor($shell->type->className()); $arguments = Arguments::fromParameters($function->parameters); $argumentsValues = ArgumentsValues::forInterface($shell, $arguments); $valuesNode = $argumentsValues->shell->build(); if (! $valuesNode->isValid()) { $messages = $valuesNode->messages(); if ($messages[0]->path() === '*root*') { return $shell->error($valuesNode->messages()[0]); } return $valuesNode; } try { $values = $argumentsValues->transform($valuesNode->value()); $classType = $this->interfaceInferringContainer->inferClassFor($shell->type->className(), $values); } catch (ObjectImplementationCallbackError $exception) { $exception = ($this->exceptionFilter)($exception->original()); return $shell->error($exception); } return $shell ->withType($classType) ->withAllowedSuperfluousKeys($arguments->names()) ->shouldNotApplyConverters() ->build(); } public function canInferImplementation(ClassDefinition $class): bool { $hasImplementation = $this->interfaceInferringContainer->has($class->name); $hasConstructor = Polyfill::array_any( $this->constructors->toArray(), static fn (FunctionObject $constructor) => $class->type->matches($constructor->definition->returnType), ); if ($hasConstructor && $hasImplementation) { throw new InterfaceHasBothConstructorAndInfer($class->name); } if ($hasConstructor) { return false; } if ($hasImplementation) { if ($class->isFinal) { $function = $this->interfaceInferringContainer->inferFunctionFor($class->name); throw new CannotInferFinalClass($class->name, $function); } return true; } if ($class->type instanceof InterfaceType || $class->isAbstract) { throw new CannotResolveObjectType($class->name); } return false; } }