private function generateMatchMethod(bool $supportsRedirections): string
    {
        // Group hosts by same-suffix, re-order when possible
        $matchHost = false;
        $routes = new StaticPrefixCollection();
        foreach ($this->getRoutes()->all() as $name => $route) {
            if ($host = $route->getHost()) {
                $matchHost = true;
                $host = '/' . strtr(strrev($host), '}.{', '(/)');
            }

            $routes->addRoute($host ?: '/(.*)', [$name, $route]);
        }
        $routes = $matchHost ? $routes->populateCollection(new RouteCollection()) : $this->getRoutes();

        $code = rtrim($this->compileRoutes($routes, $matchHost), "\n");
        $fetchHost = $matchHost ? "        \$host = strtolower(\$context->getHost());\n" : '';

        $code = <<<EOF
    {
        \$allow = \$allowSchemes = array();
        \$pathinfo = rawurldecode(\$rawPathinfo);
        \$context = \$this->context;
        \$requestMethod = \$canonicalMethod = \$context->getMethod();
{$fetchHost}
        if ('HEAD' === \$requestMethod) {
            \$canonicalMethod = 'GET';
        }

$code

EOF;

        if ($supportsRedirections) {
            return <<<'EOF'
    public function match($pathinfo)
    {
        $allow = $allowSchemes = array();
        if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
            return $ret;
        }
        if ($allow) {
            throw new MethodNotAllowedException(array_keys($allow));
        }
        if (!in_array($this->context->getMethod(), array('HEAD', 'GET'), true)) {
            // no-op
        } elseif ($allowSchemes) {
            redirect_scheme:
            $scheme = $this->context->getScheme();
            $this->context->setScheme(key($allowSchemes));
            try {
                if ($ret = $this->doMatch($pathinfo)) {
                    return $this->redirect($pathinfo, $ret['_route'], $this->context->getScheme()) + $ret;
                }
            } finally {
                $this->context->setScheme($scheme);
            }
        } elseif ('/' !== $pathinfo) {
            $pathinfo = '/' !== $pathinfo[-1] ? $pathinfo.'/' : substr($pathinfo, 0, -1);
            if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
                return $this->redirect($pathinfo, $ret['_route']) + $ret;
            }
            if ($allowSchemes) {
                goto redirect_scheme;
            }
        }

        throw new ResourceNotFoundException();
    }

    private function doMatch(string $rawPathinfo, array &$allow = array(), array &$allowSchemes = array()): ?array

EOF
                . $code . "\n        return null;\n    }";
        }

        return "    public function match(\$rawPathinfo)\n" . $code . "\n        throw \$allow ? new MethodNotAllowedException(array_keys(\$allow)) : new ResourceNotFoundException();\n    }";
    }