public T Get(object target)
    {
        T value;

        while (!mCachedTryGet(target, out value))
        {
            mCachedType   = target.GetType();
            mCachedTryGet = BuildCachedTryGet(MethodName, mCachedType);
        }
        return(value);
    }
    public T Get(object target)
    {
        T value;

        while (!TryGet(target, out value))
        {
            mCachedTypes.RemoveAt(mCachedTypes.Count - 1);
            mCachedTypes.Insert(0, target.GetType());
            mCachedTryGet = BuildCachedTryGet(MethodName, mCachedTypes);
        }
        return(value);
    }
 public bool TryGet(object target, out T result)
 {
     while (true)
     {
         if (mCachedTryGet(target, out result))
         {
             return(true);
         }
         if (mCachedTypes.Count >= kMaxCachedTypes)
         {
             return(false);
         }
         mCachedTypes.Add(target.GetType());
         mCachedTryGet = BuildCachedTryGet(MethodName, mCachedTypes);
     }
 }
 public MonomorphicCache(string methodName, Type targetType)
 {
     MethodName    = methodName;
     mCachedType   = targetType;
     mCachedTryGet = BuildCachedTryGet(MethodName, mCachedType);
 }
 public PolymorphicCache(string methodName, IEnumerable <Type> targetTypes)
 {
     MethodName = methodName;
     mCachedTypes.AddRange(targetTypes);
     mCachedTryGet = BuildCachedTryGet(MethodName, mCachedTypes);
 }
        private static IReadOnlyList <T> GetPossibleTs <T>(
            SourceSymbolContext context,
            QualifiedName name,
            ImmutableArray <IType> typeArguments,
            TryGetT <T> tryGetT,
            GetLocalTs <T> getLocalTs,
            GetFullyQualifiedName <T> getFullyQualifiedName,
            GetTypeParameters <T> getTypeParameters) where T : class
        {
            List <T> possibleTs;

            if (name.Parent is null)
            {
                // local ts have priority over top level ts,
                // and an inner local t hides an outer local t

                // local ts can only have simple names, so we can skip this check if the name is not simple

                var scope = context.Scope;
                while (scope != null)
                {
                    possibleTs = getLocalTs(scope)
                                 .Where(
                        x => getFullyQualifiedName(x) == name &&
                        getTypeParameters(x).Length == typeArguments.Length)
                                 .ToList();
                    if (possibleTs.Count > 0)
                    {
                        return(possibleTs);
                    }

                    scope = scope.DeclaringMethod;
                }
            }

            var assemblies = context.Assembly.ReferencedAssembliesAndSelf;

            // types in the innermost namespace have priority over types in its parent namespace,
            // which have priority over types in its parent etc.
            var @namespace = context.NameSpace;

            while (@namespace != null)
            {
                var possibleName = name.Prepend(@namespace);

                possibleTs = LookupPossibleName(possibleName).ToList();

                if (possibleTs.Count > 0)
                {
                    return(possibleTs);
                }

                @namespace = @namespace?.Parent;
            }

            // Types in the global namespace have priority over types defined in imports
            possibleTs = LookupPossibleName(name).ToList();

            if (possibleTs.Count > 0)
            {
                return(possibleTs);
            }

            // look for types in imports
            if (name.Parent is null)
            {
                // imports only bring the top level types into scope, so they are only relevant if the name is simple;

                var possibleNames = context.Imports.Select(x => x.Append(name)).ToList();

                return
                    (possibleNames
                     .SelectMany(LookupPossibleName)
                     .ToList());
            }

            return(Array.Empty <T>());

            IEnumerable <T> LookupPossibleName(QualifiedName possibleName)
            {
                return(assemblies.Select(x =>
                {
                    tryGetT(x, possibleName, out var t);
                    return t;
                }).Where(x => x != null && getTypeParameters(x).Length == typeArguments.Length) !);
            }
        }