Ejemplo n.º 1
0
        private TypeInferer(CandidateParameterInfo[] parameters, MethodInfo method, NameResolver resolver)
        {
            if (!method.IsGenericMethodDefinition)
            {
                throw new ArgumentException("The specified method must be a generic method definition.");
            }

            _parameters = parameters;
            _method     = method;

            // take a copy of this because it may be modified to change implicitly-typed lambdas into “translated” LINQ expressions with the right explicit types
            _arguments = parameters.Select(p => p.Argument).ToArray();

            _genericParameters = method.GetGenericArguments();
            _fixed             = new bool[_genericParameters.Length];
            _inferred          = new Type[_genericParameters.Length];
            _bounds            = new List <boundInfo> [_genericParameters.Length];
            _resolver          = resolver;
        }
Ejemplo n.º 2
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     return Expression.Constant(Literal);
 }
Ejemplo n.º 3
0
 internal override ResolveContext ToResolveContext(NameResolver resolver, bool isChecked)
 {
     // If parameter types are not specified, cannot turn into expression yet
     if (isImplicit())
         return new ResolveContextLambda(this);
     return new ResolveContextExpression(ToLinqExpression(resolver, isChecked), wasAnonymousFunction: true);
 }
Ejemplo n.º 4
0
        /// <summary>
        ///     See <see cref="CsExpression.ToLinqExpression"/>.</summary>
        /// <param name="resolver">
        ///     See <see cref="CsExpression.ToLinqExpression"/>.</param>
        /// <param name="parameterTypes">
        ///     The types of the parameters of the lambda expression.</param>
        /// <param name="isChecked">
        ///     See <see cref="CsExpression.ToLinqExpression"/>.</param>
        /// <returns>
        ///     An expression deriving from <see cref="System.Linq.Expressions.Expression"/>.</returns>
        public Expression ToLinqExpression(NameResolver resolver, Type[] parameterTypes, bool isChecked)
        {
            if (parameterTypes.Length != Parameters.Count)
                throw new ArgumentException("Number of supplied parameter types does not match number of parameters on the lambda.");

            var prmExprs = new ParameterExpression[Parameters.Count];
            for (int i = 0; i < Parameters.Count; i++)
            {
                prmExprs[i] = Expression.Parameter(parameterTypes[i], Parameters[i].Name);
                resolver.AddLocalName(Parameters[i].Name, prmExprs[i]);
            }

            var body = Body.ToLinqExpression(resolver, isChecked);
            var lambda = Expression.Lambda(body, prmExprs);

            for (int i = 0; i < Parameters.Count; i++)
                resolver.ForgetLocalName(Parameters[i].Name);

            return lambda;
        }
Ejemplo n.º 5
0
        /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
        public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
        {
            if (isImplicit())
                throw new InvalidOperationException("The implicitly-typed lambda expression “{0}” cannot be translated to a LINQ expression without knowing the types of its parameters. Use the ToLinqExpression(NameResolver,Type[]) overload to specify the parameter types.".Fmt(ToString()));

            var prmTypes = new Type[Parameters.Count];
            for (int i = 0; i < Parameters.Count; i++)
                prmTypes[i] = resolver.ResolveType(Parameters[i].Type);
            return ToLinqExpression(resolver, prmTypes, isChecked);
        }
Ejemplo n.º 6
0
        public static IEnumerable <CandidateInfo <T> > EvaluateArgumentList <T>(T member, ParameterInfo[] parameterInfo, IEnumerable <ArgumentInfo> args, NameResolver resolver) where T : MemberInfo
        {
            var i = 0;
            var seenNamedArgument       = false;
            var inParamsArray           = false;
            var evaluatedParameterTypes = new AutoList <Type>();
            var evaluatedArgumentIndex  = new AutoList <int>();
            var evaluatedArguments      = new AutoList <ResolveContext>();
            var modes            = new AutoList <ArgumentMode>(parameterInfo.Select(pi => pi.IsOut ? ArgumentMode.Out : pi.ParameterType.IsByRef ? ArgumentMode.Ref : ArgumentMode.In));
            var paramsArray      = new List <ResolveContext>();
            var paramsArrayIndex = parameterInfo.IndexOf(p => p.IsDefined(typeof(ParamArrayAttribute), false));

            foreach (var argument in args)
            {
                if (argument.Name != null)
                {
                    // Named argument
                    seenNamedArgument = true;
                    var index = parameterInfo.IndexOf(pi => pi.Name == argument.Name);
                    if (index == -1)
                    {
                        // There is no parameter by this name ⇒ resolution fails
                        yield break;
                    }
                    if (evaluatedArguments[index] != null)
                    {
                        throw new InvalidOperationException("The named parameter “{0}” has been specified multiple times.".Fmt(argument.Name));
                    }
                    if (argument.Mode != modes[index])
                    {
                        // in/out/ref doesn’t match parameter ⇒ resolution fails
                        yield break;
                    }
                    evaluatedArguments[index]      = argument.Argument;
                    evaluatedParameterTypes[index] = parameterInfo[index].ParameterType;
                    evaluatedArgumentIndex[index]  = i;
                }
                else
                {
                    // Positional argument
                    if (seenNamedArgument)
                    {
                        throw new InvalidOperationException("Cannot use a positional argument after a named argument.");
                    }

                    if (i >= parameterInfo.Length && !inParamsArray)
                    {
                        yield break;    // too many positional arguments: candidate is inapplicable
                    }
                    if (paramsArrayIndex != -1 && i >= paramsArrayIndex)
                    {
                        if (argument.Mode != ArgumentMode.In)
                        {
                            // Can’t use out/ref in a params array
                            yield break;
                        }
                        paramsArray.Add(argument.Argument);
                    }
                    else
                    {
                        if (argument.Mode != modes[i])
                        {
                            // in/out/ref doesn’t match parameter ⇒ resolution fails
                            yield break;
                        }
                        evaluatedArguments[i]      = argument.Argument;
                        evaluatedParameterTypes[i] = parameterInfo[i].ParameterType;
                        evaluatedArgumentIndex[i]  = i;
                    }
                }

                i++;
            }

            // Fill in the default values for the unspecified optional parameters
            for (int j = 0; j < parameterInfo.Length; j++)
            {
                if (j != paramsArrayIndex && evaluatedArguments[j] == null)
                {
                    if ((parameterInfo[j].Attributes & ParameterAttributes.HasDefault) != 0)
                    {
                        evaluatedArguments[j]      = new ResolveContextConstant(parameterInfo[j].DefaultValue, parameterInfo[j].ParameterType);
                        evaluatedParameterTypes[j] = parameterInfo[j].ParameterType;
                        evaluatedArgumentIndex[j]  = -1;
                    }
                    else
                    {
                        yield break;    // a non-optional parameter has no argument specified ⇒ not a candidate
                    }
                }
            }

            Func <int, CandidateParameterInfo[]> getParameters = count =>
                                                                 Enumerable.Range(0, count).Select(p => new CandidateParameterInfo
            {
                ParameterType = evaluatedParameterTypes[p],
                Mode          = modes[p],
                Argument      = evaluatedArguments[p],
                ArgumentIndex = evaluatedArgumentIndex[p],
                UninstantiatedParameterType = evaluatedParameterTypes[p],
            }).ToArray();

            if (paramsArrayIndex == -1 || paramsArray.Count == 1)
            {
                if (paramsArrayIndex != -1)
                {
                    // Emit the normal form
                    evaluatedArguments[paramsArrayIndex]      = paramsArray[0];
                    evaluatedParameterTypes[paramsArrayIndex] = parameterInfo[paramsArrayIndex].ParameterType;
                }
                yield return(new CandidateInfo <T>(member, getParameters(evaluatedParameterTypes.Count), parameterInfo.Length, isLiftedOperator: false, isExpandedForm: false));
            }

            if (paramsArrayIndex != -1)
            {
                // Emit the expanded form
                var arrayElementType = parameterInfo[paramsArrayIndex].ParameterType.GetElementType();
                for (int k = 0; k < paramsArray.Count; k++)
                {
                    evaluatedArguments[paramsArrayIndex + k]      = paramsArray[k];
                    evaluatedParameterTypes[paramsArrayIndex + k] = arrayElementType;
                    evaluatedArgumentIndex[paramsArrayIndex + k]  = paramsArrayIndex + k;
                    modes[paramsArrayIndex + k] = ArgumentMode.In;
                }
                // If paramsArray.Count == 0, then the expanded form is *shorter* than the normal form
                yield return(new CandidateInfo <T>(member, getParameters(paramsArrayIndex + paramsArray.Count), parameterInfo.Length, isLiftedOperator: false, isExpandedForm: true));
            }
        }
Ejemplo n.º 7
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     return ToResolveContext(resolver, isChecked).ToExpression();
 }
Ejemplo n.º 8
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     var operand = ToResolveContext(Operand, resolver, isChecked);
     var type = resolver.ResolveType(Type);
     if (operand is ResolveContextLambda)
         throw new NotImplementedException();
     return Expression.Convert(operand.ToExpression(), type);
 }
Ejemplo n.º 9
0
        internal override ResolveContext ToResolveContext(NameResolver resolver, bool isChecked)
        {
            if (Arguments.Any(a => a.Mode != ArgumentMode.In))
                throw new NotImplementedException("out and ref parameters are not implemented.");

            var left = ToResolveContext(Left, resolver, isChecked);
            var resolvedArguments = Arguments.Select(a => new ArgumentInfo(a.Name, ToResolveContext(a.Expression, resolver, isChecked), a.Mode));

            if (IsIndexer)
            {
                var property = ParserUtil.ResolveOverloads(
                    left.ExpressionType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                        .Select(p => Tuple.Create(p, p.GetIndexParameters()))
                        .ToList(),
                    resolvedArguments,
                    resolver);
                throw new NotImplementedException();
            }

            var leftMg = left as ResolveContextMethodGroup;
            if (leftMg != null)
            {
                // Try non-extension methods first, then extension methods
                for (int i = 0; i < 2; i++)
                {
                    var method = ParserUtil.ResolveOverloads(
                        leftMg.MethodGroup.Where(mg => mg.IsExtensionMethod == (i == 1)).Select(mg => Tuple.Create(mg.Method, mg.Method.GetParameters())).ToList(),
                        // For extension methods, add the expression that pretends to be the “this” instance as the first argument
                        i == 0 ? resolvedArguments : new[] { new ArgumentInfo(null, leftMg.Parent, ArgumentMode.In) }.Concat(resolvedArguments),
                        resolver);
                    if (method != null)
                        return new ResolveContextExpression(Expression.Call(method.Member.IsStatic ? null : leftMg.Parent.ToExpression(), method.Member, method.Parameters.Select(arg =>
                        {
                            var argExpr = arg.Argument.ToExpression();
                            return (argExpr.Type != arg.ParameterType) ? Expression.Convert(argExpr, arg.ParameterType) : argExpr;
                        })), wasAnonymousFunction: false);
                }
                throw new InvalidOperationException("Cannot determine which method overload to use for “{0}”. Either type inference failed or the call is ambiguous.".Fmt(leftMg.MethodName));
            }

            throw new NotImplementedException();
        }
Ejemplo n.º 10
0
 internal override ResolveContext ToResolveContext(NameResolver resolver, bool isChecked)
 {
     return resolver.ResolveSimpleName(Identifier);
 }
Ejemplo n.º 11
0
 internal virtual ResolveContext ToResolveContext(NameResolver resolver, bool isChecked)
 {
     return new ResolveContextExpression(ToLinqExpression(resolver, isChecked));
 }
Ejemplo n.º 12
0
 internal static ResolveContext ToResolveContext(CsExpression expr, NameResolver resolver, bool isChecked)
 {
     return expr.ToResolveContext(resolver, isChecked);
 }
Ejemplo n.º 13
0
 /// <summary>
 ///     Converts this expression parse tree into an expression using the <c>System.Linq.Expressions</c> namespace. The
 ///     expression thus returned can be used in scenarios surrounding <see cref="IQueryable"/>, such as LINQ-to-SQL,
 ///     EntityFramework and many others.</summary>
 /// <param name="resolver">
 ///     Defines the rules of how to resolve names. Use this both to define which assemblies the code should be allowed
 ///     to access as well as to declare variables and constants.</param>
 /// <param name="isChecked">
 ///     Specifies whether arithmetic operations (such as addition) should assume checked arithmetic or unchecked. The
 ///     <c>checked()</c> and <c>unchecked()</c> expressions override this, so this only applies to expressions outside
 ///     of those.</param>
 /// <returns>
 ///     An expression deriving from <see cref="System.Linq.Expressions.Expression"/>.</returns>
 public abstract Expression ToLinqExpression(NameResolver resolver, bool isChecked);
Ejemplo n.º 14
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     // Special case: if this is a unary minus operator that operates on a CsNumberLiteralExpression,
     // simply add the "-" and parse the number directly
     if (Operator == UnaryOperator.Minus && Operand is CsNumberLiteralExpression)
         return Expression.Constant(ParserUtil.ParseNumericLiteral("-" + ((CsNumberLiteralExpression) Operand).Literal));
     throw new NotImplementedException();
 }
Ejemplo n.º 15
0
 internal override ResolveContext ToResolveContext(NameResolver resolver, bool isChecked)
 {
     if (AccessType == MemberAccessType.PointerDeref)
         throw new InvalidOperationException("Pointer dereference is not supported in LINQ expressions.");
     return resolver.ResolveSimpleName(Right, ToResolveContext(Left, resolver, isChecked));
 }
Ejemplo n.º 16
0
        /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
        public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
        {
            var left = Left.ToLinqExpression(resolver, isChecked);
            var right = Right.ToLinqExpression(resolver, isChecked);
            if (left.Type != right.Type)
            {
                var conv = Conversion.Implicit(left.Type, right.Type);
                if (conv != null)
                    left = Expression.Convert(left, right.Type);
                else if ((conv = Conversion.Implicit(right.Type, left.Type)) != null)
                    right = Expression.Convert(right, left.Type);
            }

            switch (Operator)
            {
                case BinaryOperator.Times:
                    return isChecked ? Expression.MultiplyChecked(left, right) : Expression.Multiply(left, right);
                case BinaryOperator.Div:
                    return Expression.Divide(left, right);
                case BinaryOperator.Mod:
                    return Expression.Modulo(left, right);
                case BinaryOperator.Plus:
                    return isChecked ? Expression.AddChecked(left, right) : Expression.Add(left, right);
                case BinaryOperator.Minus:
                    return isChecked ? Expression.SubtractChecked(left, right) : Expression.Subtract(left, right);
                case BinaryOperator.Shl:
                    return Expression.LeftShift(left, right);
                case BinaryOperator.Shr:
                    return Expression.RightShift(left, right);
                case BinaryOperator.Less:
                    return Expression.LessThan(left, right);
                case BinaryOperator.Greater:
                    return Expression.GreaterThan(left, right);
                case BinaryOperator.LessEq:
                    return Expression.LessThanOrEqual(left, right);
                case BinaryOperator.GreaterEq:
                    return Expression.GreaterThanOrEqual(left, right);
                case BinaryOperator.Eq:
                    return Expression.Equal(left, right);
                case BinaryOperator.NotEq:
                    return Expression.NotEqual(left, right);
                case BinaryOperator.And:
                    return Expression.And(left, right);
                case BinaryOperator.Xor:
                    return Expression.ExclusiveOr(left, right);
                case BinaryOperator.Or:
                    return Expression.Or(left, right);
                case BinaryOperator.AndAnd:
                    return Expression.AndAlso(left, right);
                case BinaryOperator.OrOr:
                    return Expression.OrElse(left, right);
                case BinaryOperator.Coalesce:
                    return Expression.Coalesce(left, right);
                default:
                    throw new InvalidOperationException("Unexpected binary operator: " + Operator);
            }
        }
Ejemplo n.º 17
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     return Expression.Constant(ParserUtil.ParseNumericLiteral(Literal));
 }
Ejemplo n.º 18
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     throw new NotImplementedException();
 }
Ejemplo n.º 19
0
 /// <summary>See <see cref="CsExpression.ToLinqExpression"/>.</summary>
 public override Expression ToLinqExpression(NameResolver resolver, bool isChecked)
 {
     return Subexpression.ToLinqExpression(resolver, isChecked);
 }
Ejemplo n.º 20
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);
        }
Ejemplo n.º 21
0
        public static CandidateInfo <T> TypeInference <T>(CandidateInfo <T> candidateInfo, NameResolver resolver) where T : MemberInfo
        {
            var method = candidateInfo.Member as MethodInfo;

            if (method == null || !method.IsGenericMethodDefinition)
            {
                throw new InvalidOperationException("Type inference can only be performed on a generic method definition.");
            }

            var inferer = new TypeInferer(candidateInfo.Parameters, method, resolver);

            if (!inferer.infer())
            {
                return(null);
            }

            var inferredMethod = method.MakeGenericMethod(inferer._inferred);
            // Return the list of parameter types with the generic type parameters substituted
            var parameterTypes = inferredMethod.GetParameters().Select(p => p.ParameterType).ToArray();

            // The inferer may have changed an implicit lambda to a LINQ expression, so return the new version of _arguments
            return(new CandidateInfo <T>((T)(MemberInfo)inferredMethod,
                                         candidateInfo.Parameters.Select((p, i) => new CandidateParameterInfo
            {
                ParameterType = parameterTypes[i],
                Mode = p.Mode,
                Argument = inferer._arguments[i],
                ArgumentIndex = p.ArgumentIndex,
                UninstantiatedParameterType = p.ParameterType
            }).ToArray(), inferredMethod.GetParameters().Length, isLiftedOperator: false, isExpandedForm: candidateInfo.IsExpandedForm));
        }