// Rewrite Calls

        private static Identifier GetConcreteIdentifier(
            Dictionary <ConcreteCallGraphNode, QsQualifiedName> concreteNames,
            Identifier.GlobalCallable globalCallable,
            TypeParameterResolutions types)
        {
            if (types.IsEmpty)
            {
                return(globalCallable);
            }

            var node = new ConcreteCallGraphNode(globalCallable.Item, QsSpecializationKind.QsBody, types);

            if (concreteNames.TryGetValue(node, out var name))
            {
                return(Identifier.NewGlobalCallable(name));
            }
            else
            {
                return(globalCallable);
            }
        }
            /// <summary>
            /// Returns the specialization that the request is referring to.
            /// </summary>
            private static QsSpecialization GetSpecializationFromRequest(ConcreteCallGraphNode request, QsCallable callable)
            {
                var relevantSpecs = callable.Specializations.Where(s => s.Kind == request.Kind);
                var typeArgs      = QsNullable <ImmutableArray <ResolvedType> > .Null;

                if (callable.Signature.TypeParameters.Any())
                {
                    // Convert ParamResolutions from a dictionary to a type argument list
                    typeArgs = QsNullable <ImmutableArray <ResolvedType> > .NewValue(callable.Signature.TypeParameters.Select(typeParam =>
                    {
                        if (typeParam is QsLocalSymbol.ValidName name)
                        {
                            if (request.ParamResolutions.TryGetValue(Tuple.Create(callable.FullName, name.Item), out var res))
                            {
                                return(res);
                            }
                            else
                            {
                                throw new ArgumentException($"Couldn't resolve all type parameters for {callable.FullName}");
                            }
                        }
                        else
                        {
                            throw new ArgumentException("Encountered invalid type parameter name during call graph construction");
                        }
                    }).ToImmutableArray());

                    typeArgs = SpecializationBundleProperties.BundleId(typeArgs);
                }
                else if (relevantSpecs.Count() != 1)
                {
                    throw new ArgumentException($"Missing specialization {request.Kind} for {request.CallableName}");
                }

                if (!typeArgs.IsNull)
                {
                    // Finds the correct type specialization for the type arguments of the currentRequest.
                    // The assumption is that upon resolution, these type arguments have been cast to
                    // the type of any explicitly defined ones in the closest matching specialization.
                    var specArgMatches = relevantSpecs.Select(spec =>
                    {
                        if (spec.TypeArguments.IsNull)
                        {
                            return(0, spec);
                        }
                        if (spec.TypeArguments.Item.Count() != typeArgs.Item.Count())
                        {
                            throw new ArgumentException($"Incorrect number of type arguments in request for {request.CallableName}");
                        }
                        var specTypeArgs = spec.TypeArguments.Item.Select(StripPositionInfo.Apply).ToImmutableArray();
                        var mismatch     = specTypeArgs.Where((tArg, idx) => !tArg.Resolution.IsMissingType && !tArg.Resolution.Equals(typeArgs.Item[idx])).Any();
                        if (mismatch)
                        {
                            return(-1, spec);
                        }
                        var matches = specTypeArgs.Where((tArg, idx) => !tArg.Resolution.IsMissingType && tArg.Resolution.Equals(typeArgs.Item[idx])).Count();
                        return(matches, spec);
                    });

                    if (!specArgMatches.Any(m => m.Item1 >= 0))
                    {
                        throw new ArgumentException($"Could not find a suitable {request.Kind} specialization for {request.CallableName}");
                    }

                    relevantSpecs = specArgMatches
                                    .OrderByDescending(match => match.Item1)
                                    .Select(match => match.spec);
                }

                return(relevantSpecs.First());
            }