private function resolveArgs(array $defaultArgs, array $args, $instance = null) {
        // First resolve all passed arguments so their types are known.
        $args = array_map(
            function ($arg) use ($instance) {
                return $arg instanceof ReferenceInterface ? $arg->resolve($this, $instance) : $arg;
            },
            array_change_key_case($args)
        );

        $pos = 0;
        foreach ($defaultArgs as $name => &$default) {
            if (array_key_exists($name, $args)) {
                // This is a named arg and should be used.
                $value = $args[$name];
            } elseif (isset($args[$pos]) && (!($default instanceof DefaultReference) || empty($default->getClass()) || is_a($args[$pos], $default->getClass()))) {
                // There is an arg at this position and it's the same type as the default arg or the default arg is typeless.
                $value = $args[$pos];
                $pos++;
            } else {
                // There is no passed arg, so use the default arg.
                $value = $default;
            }

            if ($value instanceof ReferenceInterface) {
                $value = $value->resolve($this, $instance);
            }

            $default = $value;
        }

        return $defaultArgs;
    }