Beispiel #1
0
        private int betterConversionTarget(Type t1, Type t2)
        {
            // 7.5.3.5 Better conversion target
            // Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
            // • An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
            var conv1 = Conversion.Implicit(t1, t2);
            var conv2 = Conversion.Implicit(t2, t1);

            if ((conv1 == null) != (conv2 == null))
            {
                return((conv1 == null) ? 1 : -1);
            }

            // • T1 is a signed integral type and T2 is an unsigned integral type. Specifically:
            //     o T1 is sbyte and T2 is byte, ushort, uint, or ulong
            //     o T1 is short and T2 is ushort, uint, or ulong
            //     o T1 is int and T2 is uint, or ulong
            //     o T1 is long and T2 is ulong
            if ((t1 == typeof(sbyte) && (t2 == typeof(byte) || t2 == typeof(ushort) || t2 == typeof(uint) || t2 == typeof(ulong))) ||
                (t1 == typeof(short) && (t2 == typeof(ushort) || t2 == typeof(uint) || t2 == typeof(ulong))) ||
                (t1 == typeof(int) && (t2 == typeof(uint) || t2 == typeof(ulong))) ||
                (t1 == typeof(long) && t2 == typeof(ulong)))
            {
                return(-1);
            }
            if ((t2 == typeof(sbyte) && (t1 == typeof(byte) || t1 == typeof(ushort) || t1 == typeof(uint) || t1 == typeof(ulong))) ||
                (t2 == typeof(short) && (t1 == typeof(ushort) || t1 == typeof(uint) || t1 == typeof(ulong))) ||
                (t2 == typeof(int) && (t1 == typeof(uint) || t1 == typeof(ulong))) ||
                (t2 == typeof(long) && t1 == typeof(ulong)))
            {
                return(1);
            }

            return(0);
        }
Beispiel #2
0
        public static Conversion Implicit(Type from, Type to)
        {
            // 6.1.1 Identity conversion
            if (from == to)
            {
                return(new IdentityConversion(to, true));
            }

            // 6.1.2 Implicit numeric conversions
            if (implicitNumericConversions.ContainsKey(from) && implicitNumericConversions[from].Contains(to))
            {
                return(new NumericConversion(to, true));
            }

            // 6.1.4 Implicit nullable conversions
            var fromNullable = from.IsGenericType && from.GetGenericTypeDefinition() == typeof(Nullable <>);
            var toNullable   = to.IsGenericType && to.GetGenericTypeDefinition() == typeof(Nullable <>);

            if (toNullable)
            {
                var underlying = Conversion.Implicit(fromNullable ? from.GetGenericArguments()[0] : from, to.GetGenericArguments()[0]);
                return(underlying == null ? null : new NullableConversion(to, true, underlying));
            }
            if (fromNullable && !to.IsValueType)
            {
                var underlying = Conversion.Implicit(from.GetGenericArguments()[0], to);
                return(underlying == null ? null : new NullableConversion(to, true, underlying));
            }

            // 6.1.6 Implicit reference conversions + 6.1.7 Boxing conversions
            if (to.IsAssignableFrom(from))
            {
                return(from.IsValueType ? (Conversion) new BoxingConversion(to, true) : new ReferenceConversion(to, true));
            }
            if (fromNullable && to.IsAssignableFrom(from.GetGenericArguments()[0]))
            {
                return(new BoxingConversion(to, true));
            }

            // 6.1.10 Implicit conversions involving type parameters
            if (from.IsGenericParameter)
            {
                throw new NotImplementedException();
            }

            return(null);
        }
Beispiel #3
0
        public int Better(CandidateInfo <T> other)
        {
            // §7.5.3.2 Better function member
            // First check whether all the applicable parameter types are equivalent, in which case the tie-breaking rules apply
            if (EquivalentSpecifiedParameterTypes(other))
            {
                // • If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
                var mgen = Member.IsGenericMethod();
                if (mgen != other.Member.IsGenericMethod())
                {
                    return(mgen ? 1 : -1);
                }

                // • If MP is applicable in its normal form and MQ has a params array and is applicable only in its expanded form, then MP is better than MQ.
                if (IsExpandedForm != other.IsExpandedForm)
                {
                    return(IsExpandedForm ? 1 : -1);
                }

                // • If MP has more declared parameters than MQ, then MP is better than MQ. This can occur if both methods have params arrays and are applicable only in their expanded forms.
                if (OriginalNumberOfParameters != other.OriginalNumberOfParameters)
                {
                    return(OriginalNumberOfParameters < other.OriginalNumberOfParameters ? 1 : -1);
                }

                // • If all parameters of MP have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in MQ then MP is better than MQ.
                var any1 = Parameters.Any(p => p.ArgumentIndex == -1);
                var any2 = other.Parameters.Any(p => p.ArgumentIndex == -1);
                if (any1 != any2)
                {
                    return(any1 ? 1 : -1);
                }

                // • If MP has more specific parameter types than MQ, then MP is better than MQ.
                int isMoreSpecific = ParserUtil.Better(Parameters.Select(p => p.UninstantiatedParameterType), other.Parameters.Select(p => p.UninstantiatedParameterType), ParserUtil.MoreSpecific);
                if (isMoreSpecific != 0)
                {
                    return(isMoreSpecific);
                }

                // • If one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
                if (IsLiftedOperator != other.IsLiftedOperator)
                {
                    return(IsLiftedOperator ? 1 : -1);
                }

                // • Otherwise, neither function member is better.
                return(0);
            }

            return(ParserUtil.Better(ParametersInSpecifiedOrder(), other.ParametersInSpecifiedOrder(), (p1, p2) =>
            {
                var c1 = Conversion.Implicit(p1.Argument, p1.ParameterType);
                var c2 = Conversion.Implicit(p2.Argument, p2.ParameterType);

                // Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that
                // converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
                // • E has a type S and an identity conversion exists from S to T1 but not from S to T2
                if (c1 is IdentityConversion != c2 is IdentityConversion)
                {
                    return c1 is IdentityConversion ? -1 : 1;
                }

                // • E is not an anonymous function and T1 is a better conversion target than T2 (§7.5.3.5)
                var isAnonymousFunction = p1.Argument is ResolveContextExpression && ((ResolveContextExpression)p1.Argument).WasAnonymousFunction;
                if (!isAnonymousFunction)
                {
                    return betterConversionTarget(p1.ParameterType, p2.ParameterType);
                }

                // • E is an anonymous function, T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2> and one of the following holds:
                //     o D1 is a better conversion target than D2
                //     o D1 and D2 have identical parameter lists, and one of the following holds:
                //          • D1 has a return type Y1, and D2 has a return type Y2, an inferred return type X exists for E in the context of that parameter list (§7.5.2.12), and the conversion from X to Y1 is better than the conversion from X to Y2
                //          • D1 has a return type Y, and D2 is void returning
                else
                {
                    var del1 = ParserUtil.GetDelegateType(p1.ParameterType);
                    var del2 = ParserUtil.GetDelegateType(p2.ParameterType);
                    if (del1 == null || del2 == null)
                    {
                        throw new InternalErrorException("Internal error 23087");
                    }
                    var del1param = ParserUtil.GetDelegateParameterTypes(p1.ParameterType);
                    var del2param = ParserUtil.GetDelegateParameterTypes(p2.ParameterType);
                    if (del1param.SequenceEqual(del2param))
                    {
                        var ret1 = ParserUtil.GetDelegateReturnType(p1.ParameterType);
                        var ret2 = ParserUtil.GetDelegateReturnType(p2.ParameterType);
                        if ((ret1 == typeof(void)) != (ret2 == typeof(void)))
                        {
                            return (ret1 == typeof(void)) ? 1 : -1;
                        }
                        var realRet = ParserUtil.GetDelegateReturnType(((ResolveContextExpression)p1.Argument).ExpressionType);
                        var rc1 = Conversion.Implicit(realRet, ret1);
                        var rc2 = Conversion.Implicit(realRet, ret2);
                        if (rc1 is IdentityConversion != rc2 is IdentityConversion)
                        {
                            return rc1 is IdentityConversion ? -1 : 1;
                        }
                        return betterConversionTarget(ret1, ret2);
                    }
                    return betterConversionTarget(del1, del2);
                }
            }));
        }
Beispiel #4
0
        public static CandidateInfo <T> ResolveOverloads <T>(List <Tuple <T, ParameterInfo[]> > overloads, IEnumerable <ArgumentInfo> arguments, NameResolver resolver) where T : MemberInfo
        {
            var candidates = overloads.SelectMany(ov => ParserUtil.EvaluateArgumentList(ov.Item1, ov.Item2, arguments, resolver)).ToList();

            // Type inference
            for (int i = 0; i < candidates.Count; i++)
            {
                if (candidates[i].Member is MethodInfo && ((MethodInfo)(MemberInfo)candidates[i].Member).IsGenericMethodDefinition)
                {
                    candidates[i] = TypeInferer.TypeInference(candidates[i], resolver);
                }
            }

            // Remove nulls (entries where type inference failed) and entries that are not applicable (§7.5.3.1 Applicable function member)
            candidates = candidates.Where(c => c != null && c.Parameters.All(p => p.Mode == ArgumentMode.In
                ? Conversion.Implicit(p.Argument, p.ParameterType) != null
                : p.ParameterType == p.Argument.ExpressionType)).ToList();

            if (candidates.Count == 0)
            {
                return(null);
            }
            if (candidates.Count == 1)
            {
                return(candidates[0]);
            }

            // We have more than one candidate, so need to find the “best” one
            bool[] cannot = new bool[candidates.Count];
            for (int i = 0; i < cannot.Length; i++)
            {
                for (int j = i + 1; j < cannot.Length; j++)
                {
                    int compare = candidates[i].Better(candidates[j]);
                    if (compare != 1) // j is not better
                    {
                        cannot[j] = true;
                    }
                    if (compare != -1) // i is not better
                    {
                        cannot[i] = true;
                    }
                }
            }

            CandidateInfo <T> candidate = null;

            for (int i = 0; i < cannot.Length; i++)
            {
                if (!cannot[i])
                {
                    if (candidate == null)
                    {
                        candidate = candidates[i];
                    }
                    else
                    {
                        // There is more than one applicable candidate — method call is ambiguous
                        return(null);
                    }
                }
            }

            // Either candidate == null, in which case no candidate was better than all others, or this is the successful candidate
            return(candidate);
        }
Beispiel #5
0
        private bool fix(int index)
        {
            // The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
            if (_bounds[index] == null)
            {
                throw new InternalErrorException("Bounds shouldn’t be null");
            }
            if (_bounds[index].Count == 1)
            {
                _inferred[index] = _bounds[index][0].Type;
                _fixed[index]    = true;
                return(true);
            }

            var bounds = _bounds[index].Select(b => b.Type).Distinct().ToList();   // sift out duplicates, then create a copy of the list

            // Examine the three types of bounds in turn
            foreach (var bound in _bounds[index])
            {
                for (int i = bounds.Count - 1; i >= 0; i--)
                {
                    if ((bound.Kind == boundKind.Exact && bounds[i] != bound.Type) ||
                        (bound.Kind == boundKind.Lower && !bounds[i].IsAssignableFrom(bound.Type)) ||
                        (bound.Kind == boundKind.Upper && !bound.Type.IsAssignableFrom(bounds[i])))
                    {
                        bounds.RemoveAt(i);
                    }
                }
            }

            Type candidate = null;

            for (int i = 0; i < bounds.Count; i++)
            {
                bool good = true;
                for (int j = i + 1; good && j < bounds.Count; j++)
                {
                    if (Conversion.Implicit(bounds[i], bounds[j]) == null)
                    {
                        good = false;
                    }
                }

                if (good)
                {
                    if (candidate == null)
                    {
                        candidate = bounds[i];
                    }
                    else
                    {
                        // There is more than one candidate type ⇒ type inference fails
                        return(false);
                    }
                }
            }

            if (candidate == null)
            {
                // There is no viable candidate ⇒ type inference fails
                return(false);
            }

            _inferred[index] = candidate;
            _fixed[index]    = true;
            return(true);
        }