示例#1
0
        // todo. resolve the method group -> delegate cast
        // and also provide generic arg inference altogether
        public static ResolvedInvocation Resolve(this MethodGroup mg, TypeInferenceContext ctx)
        {
            var failboats = new Dictionary<MethodInfo, MethodResolutionException>();
            var infToOrig = new Dictionary<MethodInfo, MethodInfo>();
            var origToInf = new Dictionary<MethodInfo, MethodInfo>();

            try
            {
                // Step 1. Get rid of alternatives that don't have a form that suits arg count.
                var suitableAlts = new List<MethodInfo>();
                foreach (var alt in mg.Alts)
                {
                    if (alt.XArgsCount().Contains(ctx.Root.XArgsCount()))
                    {
                        suitableAlts.Add(alt);
                    }
                    else
                    {
                        failboats.Add(alt, new MethodMatchingException(
                            MethodMatchingExceptionType.ArgcMismatch, alt, null, ctx));
                    }
                }

                // Step 2. Infer generic arguments of all open generic alternatives and get rid of those who fail to be inferred.
                var inferredAlts = new List<MethodInfo>();
                foreach (var salt in suitableAlts)
                {
                    try
                    {
                        var infAlt = salt.InferGenericTypeParams(ctx);

                        inferredAlts.Add(infAlt);
                        origToInf.Add(salt, infAlt);
                        infToOrig.Add(infAlt, salt);
                    }
                    catch (GenericArgumentsInferenceException gex)
                    {
                        if (gex.IsUnexpected)
                        {
                            throw;
                        }
                        else
                        {
                            failboats.Add(salt, new MethodMatchingException(
                                MethodMatchingExceptionType.GenericArgInferenceFailed, salt, null, ctx, gex));
                        }
                    }
                }

                // Step 3. Store type inference context of all alternatives that had made it so far
                var sigs = new List<ResolvedSignature>();
                foreach (var infAlt in inferredAlts)
                {
                    var infAlt1 = infAlt;
                    var resolvedCtx = new TypeInferenceEngine(ctx);

                    ctx.Root.CallArgs().ForEach((callArg, i) =>
                    {
                        if (callArg is LambdaExpression)
                        {
                            var inferredFormal = infAlt1.IsExtension()
                                ? infAlt1.GetParameters()[i + 1].ParameterType
                                : infAlt1.GetParameters()[i].ParameterType;

                            var inferredLambda = new Lambda(
                                (LambdaExpression)callArg, inferredFormal.NormalizeFunctionType());
                            resolvedCtx.Ctx.Inferences.Add(callArg, inferredLambda);
                        }

                        resolvedCtx.InferTypes(callArg);
                    });

                    sigs.Add(new ResolvedSignature(resolvedCtx.Ctx, infAlt));
                }

                // Step 4. Now get rid of alternatives that do not match Relinq-specific validation
                var validSigs = new List<ResolvedSignature>();
                foreach (var sig in sigs)
                {
                    var args = ctx.Root.ToXArgs(sig.Inferences);
                    if (sig.Signature.IsValid(sig.Signature.IsExtension() ? args : args.Skip(1)))
                    {
                        validSigs.Add(sig);
                    }
                    else
                    {
                        failboats.Add(infToOrig[sig.Signature], new MethodMatchingException(
                            MethodMatchingExceptionType.SignatureFailsMetaConstrains, infToOrig[sig.Signature], sig.Signature, ctx));
                    }
                }

                // Step 5. Eliminate signatures that do not satisfy actual argument conversions
                var invs = new List<ResolvedInvocation>();
                foreach (var validSig in validSigs)
                {
                    var args = ctx.Root.ToXArgs(validSig.Inferences);
                    var @params = validSig.Signature.ToXArgs(ctx.Root.XArgsCount());
                    var inv = new ResolvedInvocation(validSig, args.Zip(@params, (arg, param) => Cast.Lookup(arg, param)));

                    var fail = Array.FindIndex(inv.Casts.ToArray(), c => c == null);
                    if (fail == -1)
                    {
                        invs.Add(inv);
                    }
                    else
                    {
                        failboats.Add(infToOrig[validSig.Signature], new MethodMatchingException(
                            MethodMatchingExceptionType.ActualArgCannotBeCastToFormalArg, infToOrig[validSig.Signature], validSig.Signature, ctx, fail));
                    }
                }

                // Step 6. Remove sub-par signatures from the all-satisfying survivors
                var res = new List<ResolvedInvocation>();
                foreach (var inv in invs)
                {
                    var subpar = false;
                    foreach (var anotherInv in invs)
                    {
                        subpar |= anotherInv > inv;
                    }

                    if (!subpar)
                    {
                        res.Add(inv);
                    }
                    else
                    {
                        failboats.Add(infToOrig[inv.Signature], new MethodMatchingException(
                            MethodMatchingExceptionType.SignatureIsSubPar, infToOrig[inv.Signature], inv.Signature, ctx));
                    }
                }

                // Step 7. Finalize the death race (and evade the final trap)
                switch (res.Count())
                {
                    case 0:
                        throw new MethodGroupResolutionFailedException(
                            JSToCSharpExceptionType.FruitlessMethodGroupResolution, mg, failboats, ctx);

                    case 1:
                        var winrar = res.Single();
                        if (winrar.Signature.IsTrap())
                        {
                            failboats.Add(infToOrig[winrar.Signature], new MethodMatchingException(
                                MethodMatchingExceptionType.SignatureIsEntrapped, infToOrig[winrar.Signature], winrar.Signature, ctx));

                            throw new MethodGroupResolutionFailedException(
                                JSToCSharpExceptionType.FruitlessMethodGroupResolution, mg, failboats, ctx);
                        }

                        // my sincere congratulations
                        return winrar;

                    default:
                        foreach (var winrar2 in res)
                        {
                            failboats.Add(infToOrig[winrar2.Signature], new MethodMatchingException(
                                MethodMatchingExceptionType.SignatureIsOkButAmbiguous, infToOrig[winrar2.Signature], winrar2.Signature, ctx));
                        }

                        throw new MethodGroupResolutionFailedException(
                            JSToCSharpExceptionType.AmbiguousMethodGroupResolution, mg, failboats, ctx);
                }
            }
            catch (MethodGroupResolutionFailedException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new MethodGroupResolutionFailedException(
                    JSToCSharpExceptionType.Unexpected, mg, failboats, ctx, ex);
            }
        }
 private IEnumerable<LinqExpression> CompileCallArguments(
     ResolvedInvocation invocation, IEnumerable<RelinqScriptExpression> args, CompilationContext ctx)
 {
     return CompileCallArguments(invocation.Signature, invocation.Casts, args, ctx);
 }