Exemplo n.º 1
0
 void MakeOutputTypeInference(ResolveResult e, IType t)
 {
     Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t);
     // If E is an anonymous function with inferred return type  U (§7.5.2.12) and T is a delegate type or expression
     // tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb.
     LambdaResolveResult lrr = e as LambdaResolveResult;
     if (lrr != null) {
         IMethod m = GetDelegateOrExpressionTreeSignature(t);
         if (m != null) {
             IType inferredReturnType;
             if (lrr.IsImplicitlyTyped) {
                 if (m.Parameters.Count != lrr.Parameters.Count)
                     return; // cannot infer due to mismatched parameter lists
                 TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
                 IType[] inferredParameterTypes = new IType[m.Parameters.Count];
                 for (int i = 0; i < inferredParameterTypes.Length; i++) {
                     IType parameterType = m.Parameters[i].Type;
                     inferredParameterTypes[i] = parameterType.AcceptVisitor(substitution);
                 }
                 inferredReturnType = lrr.GetInferredReturnType(inferredParameterTypes);
             } else {
                 inferredReturnType = lrr.GetInferredReturnType(null);
             }
             MakeLowerBoundInference(inferredReturnType, m.ReturnType);
             return;
         }
     }
     // Otherwise, if E is a method group and T is a delegate type or expression tree type
     // with parameter types T1…Tk and return type Tb, and overload resolution
     // of E with the types T1…Tk yields a single method with return type U, then a lower­-bound
     // inference is made from U to Tb.
     MethodGroupResolveResult mgrr = e as MethodGroupResolveResult;
     if (mgrr != null) {
         IMethod m = GetDelegateOrExpressionTreeSignature(t);
         if (m != null) {
             ResolveResult[] args = new ResolveResult[m.Parameters.Count];
             TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
             for (int i = 0; i < args.Length; i++) {
                 IParameter param = m.Parameters[i];
                 IType parameterType = param.Type.AcceptVisitor(substitution);
                 if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) {
                     parameterType = ((ByReferenceType)parameterType).ElementType;
                     args[i] = new ByReferenceResolveResult(parameterType, param.IsOut);
                 } else {
                     args[i] = new ResolveResult(parameterType);
                 }
             }
             var or = mgrr.PerformOverloadResolution(compilation,
                                                     args,
                                                     allowExpandingParams: false, allowOptionalParameters: false);
             if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) {
                 IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
                 MakeLowerBoundInference(returnType, m.ReturnType);
             }
         }
         return;
     }
     // Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
     if (IsValidType(e.Type)) {
         MakeLowerBoundInference(e.Type, t);
     }
 }
Exemplo n.º 2
0
 public JsNode VisitByReferenceResolveResult(ByReferenceResolveResult res)
 {
     return(Visit(res.ElementResult));
 }
Exemplo n.º 3
0
        void MakeOutputTypeInference(ResolveResult e, IType t)
        {
            Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t);
            // If E is an anonymous function with inferred return type  U (§7.5.2.12) and T is a delegate type or expression
            // tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb.
            LambdaResolveResult lrr = e as LambdaResolveResult;

            if (lrr != null)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    IType inferredReturnType;
                    if (lrr.IsImplicitlyTyped)
                    {
                        if (m.Parameters.Count != lrr.Parameters.Count)
                        {
                            return;                             // cannot infer due to mismatched parameter lists
                        }
                        TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
                        IType[] inferredParameterTypes         = new IType[m.Parameters.Count];
                        for (int i = 0; i < inferredParameterTypes.Length; i++)
                        {
                            IType parameterType = m.Parameters[i].Type;
                            inferredParameterTypes[i] = parameterType.AcceptVisitor(substitution);
                        }
                        inferredReturnType = lrr.GetInferredReturnType(inferredParameterTypes);
                    }
                    else
                    {
                        inferredReturnType = lrr.GetInferredReturnType(null);
                    }
                    MakeLowerBoundInference(inferredReturnType, m.ReturnType);
                    return;
                }
            }
            // Otherwise, if E is a method group and T is a delegate type or expression tree type
            // with parameter types T1…Tk and return type Tb, and overload resolution
            // of E with the types T1…Tk yields a single method with return type U, then a lower­-bound
            // inference is made from U to Tb.
            MethodGroupResolveResult mgrr = e as MethodGroupResolveResult;

            if (mgrr != null)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    ResolveResult[]           args         = new ResolveResult[m.Parameters.Count];
                    TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
                    for (int i = 0; i < args.Length; i++)
                    {
                        IParameter param         = m.Parameters[i];
                        IType      parameterType = param.Type.AcceptVisitor(substitution);
                        if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference)
                        {
                            parameterType = ((ByReferenceType)parameterType).ElementType;
                            args[i]       = new ByReferenceResolveResult(parameterType, param.IsOut);
                        }
                        else
                        {
                            args[i] = new ResolveResult(parameterType);
                        }
                    }
                    var or = mgrr.PerformOverloadResolution(compilation,
                                                            args,
                                                            allowExpandingParams: false, allowOptionalParameters: false);
                    if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null)
                    {
                        IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
                        MakeLowerBoundInference(returnType, m.ReturnType);
                    }
                }
                return;
            }
            // Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
            if (IsValidType(e.Type))
            {
                MakeLowerBoundInference(e.Type, t);
            }
        }
Exemplo n.º 4
0
 public virtual object VisitByReferenceResolveResult(ByReferenceResolveResult rr, object data)
 {
     VisitChildResolveResults(rr, data);
     return(null);
 }
Exemplo n.º 5
0
        void CheckApplicability(Candidate candidate)
        {
            // C# 4.0 spec: §7.5.3.1 Applicable function member

            // Test whether parameters were mapped the correct number of arguments:
            int[] argumentCountPerParameter = new int[candidate.ParameterTypes.Length];
            foreach (int parameterIndex in candidate.ArgumentToParameterMap)
            {
                if (parameterIndex >= 0)
                {
                    argumentCountPerParameter[parameterIndex]++;
                }
            }
            for (int i = 0; i < argumentCountPerParameter.Length; i++)
            {
                if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1)
                {
                    continue;                     // any number of arguments is fine for the params-array
                }
                if (argumentCountPerParameter[i] == 0)
                {
                    if (this.AllowOptionalParameters && candidate.Parameters[i].IsOptional)
                    {
                        candidate.HasUnmappedOptionalParameters = true;
                    }
                    else
                    {
                        candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter);
                    }
                }
                else if (argumentCountPerParameter[i] > 1)
                {
                    candidate.AddError(OverloadResolutionErrors.MultipleArgumentsForSingleParameter);
                }
            }

            candidate.ArgumentConversions = new Conversion[arguments.Length];
            // Test whether argument passing mode matches the parameter passing mode
            for (int i = 0; i < arguments.Length; i++)
            {
                int parameterIndex = candidate.ArgumentToParameterMap[i];
                if (parameterIndex < 0)
                {
                    candidate.ArgumentConversions[i] = Conversion.None;
                    continue;
                }

                ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
                if (brrr != null)
                {
                    if ((brrr.IsOut && !candidate.Parameters[parameterIndex].IsOut) || (brrr.IsRef && !candidate.Parameters[parameterIndex].IsRef))
                    {
                        candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
                    }
                }
                else
                {
                    if (candidate.Parameters[parameterIndex].IsOut || candidate.Parameters[parameterIndex].IsRef)
                    {
                        candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
                    }
                }
                IType      parameterType = candidate.ParameterTypes[parameterIndex];
                Conversion c             = conversions.ImplicitConversion(arguments[i], parameterType);
                candidate.ArgumentConversions[i] = c;
                if (IsExtensionMethodInvocation && parameterIndex == 0)
                {
                    // First parameter to extension method must be an identity, reference or boxing conversion
                    if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
                    {
                        candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
                    }
                }
                else
                {
                    if ((!c.IsValid && !c.IsUserDefined && !c.IsMethodGroupConversion) && parameterType.Kind != TypeKind.Unknown)
                    {
                        candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
                    }
                }
            }
        }
 public virtual TResult VisitByReferenceResolveResult(ByReferenceResolveResult rr, TData data)
 {
     VisitChildResolveResults(rr, data);
     return(default(TResult));
 }
Exemplo n.º 7
0
        public ExpressionWithResolveResult Build(OpCode callOpCode, IMethod method, IReadOnlyList <ILInstruction> callArguments,
                                                 IType constrainedTo = null)
        {
            // Used for Call, CallVirt and NewObj
            var expectedTargetDetails = new ExpectedTargetDetails {
                CallOpCode = callOpCode
            };
            TranslatedExpression target;

            if (callOpCode == OpCode.NewObj)
            {
                target = default(TranslatedExpression);                 // no target
            }
            else
            {
                target = expressionBuilder.TranslateTarget(method, callArguments.FirstOrDefault(), callOpCode == OpCode.Call, constrainedTo);
                if (callOpCode == OpCode.CallVirt &&
                    constrainedTo == null &&
                    target.Expression is CastExpression cast &&
                    target.ResolveResult is ConversionResolveResult conversion &&
                    target.Type.IsKnownType(KnownTypeCode.Object) &&
                    conversion.Conversion.IsBoxingConversion)
                {
                    // boxing conversion on call target?
                    // let's see if we can make that implicit:
                    target = target.UnwrapChild(cast.Expression);
                    // we'll need to make sure the boxing effect is preserved
                    expectedTargetDetails.NeedsBoxingConversion = true;
                }
            }

            int firstParamIndex = (method.IsStatic || callOpCode == OpCode.NewObj) ? 0 : 1;

            // Translate arguments to the expected parameter types
            var arguments = new List <TranslatedExpression>(method.Parameters.Count);

            Debug.Assert(callArguments.Count == firstParamIndex + method.Parameters.Count);
            var  expectedParameters = method.Parameters.ToList();
            bool isExpandedForm     = false;

            for (int i = 0; i < method.Parameters.Count; i++)
            {
                var parameter = expectedParameters[i];
                var arg       = expressionBuilder.Translate(callArguments[firstParamIndex + i], parameter.Type);
                if (parameter.IsParams && i + 1 == method.Parameters.Count)
                {
                    // Parameter is marked params
                    // If the argument is an array creation, inline all elements into the call and add missing default values.
                    // Otherwise handle it normally.
                    if (arg.ResolveResult is ArrayCreateResolveResult acrr &&
                        acrr.SizeArguments.Count == 1 &&
                        acrr.SizeArguments[0].IsCompileTimeConstant &&
                        acrr.SizeArguments[0].ConstantValue is int length)
                    {
                        var expandedParameters = expectedParameters.Take(expectedParameters.Count - 1).ToList();
                        var expandedArguments  = new List <TranslatedExpression>(arguments);
                        if (length > 0)
                        {
                            var arrayElements = ((ArrayCreateExpression)arg.Expression).Initializer.Elements.ToArray();
                            var elementType   = ((ArrayType)acrr.Type).ElementType;
                            for (int j = 0; j < length; j++)
                            {
                                expandedParameters.Add(new DefaultParameter(elementType, parameter.Name + j));
                                if (j < arrayElements.Length)
                                {
                                    expandedArguments.Add(new TranslatedExpression(arrayElements[j]));
                                }
                                else
                                {
                                    expandedArguments.Add(expressionBuilder.GetDefaultValueExpression(elementType).WithoutILInstruction());
                                }
                            }
                        }
                        if (IsUnambiguousCall(expectedTargetDetails, method, target.ResolveResult, Empty <IType> .Array, expandedArguments) == OverloadResolutionErrors.None)
                        {
                            isExpandedForm     = true;
                            expectedParameters = expandedParameters;
                            arguments          = expandedArguments.SelectList(a => new TranslatedExpression(a.Expression.Detach()));
                            continue;
                        }
                    }
                }

                arguments.Add(arg.ConvertTo(parameter.Type, expressionBuilder, allowImplicitConversion: true));

                if (parameter.IsOut && arguments[i].Expression is DirectionExpression dirExpr && arguments[i].ResolveResult is ByReferenceResolveResult brrr)
                {
                    dirExpr.FieldDirection = FieldDirection.Out;
                    dirExpr.RemoveAnnotations <ByReferenceResolveResult>();
                    if (brrr.ElementResult == null)
                    {
                        brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
                    }
                    else
                    {
                        brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
                    }
                    dirExpr.AddAnnotation(brrr);
                    arguments[i] = new TranslatedExpression(dirExpr);
                }
            }

            if (method is VarArgInstanceMethod)
            {
                int regularParameterCount = ((VarArgInstanceMethod)method).RegularParameterCount;
                var argListArg            = new UndocumentedExpression();
                argListArg.UndocumentedExpressionType = UndocumentedExpressionType.ArgList;
                int paramIndex = regularParameterCount;
                var builder    = expressionBuilder;
                argListArg.Arguments.AddRange(arguments.Skip(regularParameterCount).Select(arg => arg.ConvertTo(expectedParameters[paramIndex++].Type, builder).Expression));
                var argListRR = new ResolveResult(SpecialType.ArgList);
                arguments = arguments.Take(regularParameterCount)
                            .Concat(new[] { argListArg.WithoutILInstruction().WithRR(argListRR) }).ToList();
                method             = (IMethod)method.MemberDefinition;
                expectedParameters = method.Parameters.ToList();
            }

            var argumentResolveResults = arguments.Select(arg => arg.ResolveResult).ToList();

            ResolveResult rr = new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm);

            if (callOpCode == OpCode.NewObj)
            {
                if (settings.AnonymousTypes && method.DeclaringType.IsAnonymousType())
                {
                    var argumentExpressions            = arguments.SelectArray(arg => arg.Expression);
                    AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
                    if (CanInferAnonymousTypePropertyNamesFromArguments(argumentExpressions, expectedParameters))
                    {
                        atce.Initializers.AddRange(argumentExpressions);
                    }
                    else
                    {
                        for (int i = 0; i < argumentExpressions.Length; i++)
                        {
                            atce.Initializers.Add(
                                new NamedExpression {
                                Name       = expectedParameters[i].Name,
                                Expression = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder)
                            });
                        }
                    }
                    return(atce
                           .WithRR(rr));
                }
                else
                {
                    if (IsUnambiguousCall(expectedTargetDetails, method, null, Empty <IType> .Array, arguments) != OverloadResolutionErrors.None)
                    {
                        for (int i = 0; i < arguments.Count; i++)
                        {
                            if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType())
                            {
                                if (arguments[i].Expression is LambdaExpression lambda)
                                {
                                    ModifyReturnTypeOfLambda(lambda);
                                }
                            }
                            else
                            {
                                arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
                            }
                        }
                    }
                    return(new ObjectCreateExpression(expressionBuilder.ConvertType(method.DeclaringType), arguments.SelectArray(arg => arg.Expression))
                           .WithRR(rr));
                }
            }
            else
            {
                int allowedParamCount = (method.ReturnType.IsKnownType(KnownTypeCode.Void) ? 1 : 0);
                if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || expectedParameters.Count == allowedParamCount))
                {
                    return(HandleAccessorCall(expectedTargetDetails, method, target, arguments.ToList()));
                }
                else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate && !IsNullConditional(target))
                {
                    return(new InvocationExpression(target, arguments.Select(arg => arg.Expression)).WithRR(rr));
                }
                else if (IsDelegateEqualityComparison(method, arguments))
                {
                    return(HandleDelegateEqualityComparison(method, arguments)
                           .WithRR(rr));
                }
                else if (method.IsOperator && method.Name == "op_Implicit" && arguments.Count == 1)
                {
                    return(HandleImplicitConversion(method, arguments[0]));
                }
                else
                {
                    bool requireTypeArguments = false;
                    bool requireTarget;
                    if (expressionBuilder.HidesVariableWithName(method.Name))
                    {
                        requireTarget = true;
                    }
                    else
                    {
                        if (method.IsStatic)
                        {
                            requireTarget = !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) || method.Name == ".cctor";
                        }
                        else
                        {
                            requireTarget = !(target.Expression is ThisReferenceExpression || target.Expression is BaseReferenceExpression) || method.Name == ".ctor";
                        }
                    }
                    bool    targetCasted        = false;
                    bool    argumentsCasted     = false;
                    IType[] typeArguments       = Empty <IType> .Array;
                    var     targetResolveResult = requireTarget ? target.ResolveResult : null;
                    OverloadResolutionErrors errors;
                    while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, arguments)) != OverloadResolutionErrors.None)
                    {
                        switch (errors)
                        {
                        case OverloadResolutionErrors.TypeInferenceFailed:
                        case OverloadResolutionErrors.WrongNumberOfTypeArguments:
                            if (requireTypeArguments)
                            {
                                goto default;
                            }
                            requireTypeArguments = true;
                            typeArguments        = method.TypeArguments.ToArray();
                            continue;

                        default:
                            // TODO : implement some more intelligent algorithm that decides which of these fixes (cast args, add target, cast target, add type args)
                            // is best in this case. Additionally we should not cast all arguments at once, but step-by-step try to add only a minimal number of casts.
                            if (!argumentsCasted)
                            {
                                argumentsCasted = true;
                                for (int i = 0; i < arguments.Count; i++)
                                {
                                    if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType())
                                    {
                                        if (arguments[i].Expression is LambdaExpression lambda)
                                        {
                                            ModifyReturnTypeOfLambda(lambda);
                                        }
                                    }
                                    else
                                    {
                                        arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
                                    }
                                }
                            }
                            else if (!requireTarget)
                            {
                                requireTarget       = true;
                                targetResolveResult = target.ResolveResult;
                            }
                            else if (!targetCasted)
                            {
                                targetCasted        = true;
                                target              = target.ConvertTo(method.DeclaringType, expressionBuilder);
                                targetResolveResult = target.ResolveResult;
                            }
                            else if (!requireTypeArguments)
                            {
                                requireTypeArguments = true;
                                typeArguments        = method.TypeArguments.ToArray();
                            }
                            else
                            {
                                break;
                            }
                            continue;
                        }
                        break;
                    }

                    Expression targetExpr;
                    string     methodName = method.Name;
                    AstNodeCollection <AstType> typeArgumentList;
                    if (requireTarget)
                    {
                        targetExpr       = new MemberReferenceExpression(target.Expression, methodName);
                        typeArgumentList = ((MemberReferenceExpression)targetExpr).TypeArguments;

                        // HACK : convert this.Dispose() to ((IDisposable)this).Dispose(), if Dispose is an explicitly implemented interface method.
                        if (method.IsExplicitInterfaceImplementation && target.Expression is ThisReferenceExpression)
                        {
                            var castExpression = new CastExpression(expressionBuilder.ConvertType(method.ImplementedInterfaceMembers[0].DeclaringType), target.Expression);
                            methodName       = method.ImplementedInterfaceMembers[0].Name;
                            targetExpr       = new MemberReferenceExpression(castExpression, methodName);
                            typeArgumentList = ((MemberReferenceExpression)targetExpr).TypeArguments;
                        }
                    }
                    else
                    {
                        targetExpr       = new IdentifierExpression(methodName);
                        typeArgumentList = ((IdentifierExpression)targetExpr).TypeArguments;
                    }

                    if (requireTypeArguments && (!settings.AnonymousTypes || !method.TypeArguments.Any(a => a.ContainsAnonymousType())))
                    {
                        typeArgumentList.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
                    }
                    var argumentExpressions = arguments.Select(arg => arg.Expression);
                    return(new InvocationExpression(targetExpr, argumentExpressions).WithRR(rr));
                }
            }
        }
Exemplo n.º 8
0
 public object VisitByReferenceResolveResult(ByReferenceResolveResult res)
 {
     throw new NotImplementedException();
 }