private void InferOperator(OperatorExpression oe, TypeInferenceCache cache)
        {
            var preview = cache.Clone();
            oe.Operands.ForEach(operand => InferTypes(operand, preview));
            var types = oe.Operands.Select(operand => preview[operand]);

            if (types.Any(type => type is Variant))
            {
                cache.Add(oe, new Variant());
                cache.Upgrade(preview);
            }
            else
            {
                var alts = oe.Type.LookupOperators(types.ToArray());

                // logical not can also be used to express ones complement
                // since they both correspond to a single LINQ expression type
                if (oe.Type == OperatorType.LogicalNot)
                {
                    var addendum = OperatorType.OnesComplement.LookupOperators(types.ToArray());
                    if (addendum != null)
                    {
                        var original = alts == null ? new MethodInfo[0] : alts.Alts;
                        alts = new MethodGroup(original.Concat(addendum.Alts), oe.Type.GetOpCode());
                    }
                }

                if (alts == null)
                {
                    throw new NoSuchOperatorException(Root, oe, types);
                }

                InferMethodGroup(alts, oe, cache);
            }
        }
 public NoSuchOperatorException(RelinqScriptExpression root, OperatorExpression oe, IEnumerable<RelinqScriptType> operandTypes)
     : base(JSToCSharpExceptionType.NoSuchIndexer, root, oe)
 {
     InferredOperandTypes = operandTypes.ToArray();
     OperatorName = oe.Type.GetOpCode();
 }
        private LinqExpression CompileOperator(OperatorExpression oe, CompilationContext ctx)
        {
            // not checking anything here. see comment in CompileConditional method's body

            // do not rely on oe.Type to detect the LINQ expression type, since
            // lookup/resolution might yield an operator with a different type
            // todo. validate this (LogicalNot -> OnesComplement, but not others)

            var sig = ctx.Invocations[oe].Signature;
            var sigTypes = sig.GetOperatorTypes();
            var actualOpType = sigTypes.Count() > 1 ? oe.Type : sigTypes.Single();

            if (!sig.IsRedirected())
            {
                var compiledOperands = CompileCallArguments(ctx.Invocations[oe], oe.Operands, ctx);

                var ctorArgs = compiledOperands.Cast<Object>();
                if (sig.IsUserDefinedOperator()) ctorArgs = ctorArgs.Concat(sig.AsArray());
                return actualOpType.LinqExpressionFactory()(ctorArgs.ToArray());
            }
            else
            {
                if (sig.IsLifted())
                {
                    // todo. implement this
                    throw new NotImplementedException(String.Format(
                        "Don't know how to compile the lifted operator: '{0}'", sig));
                }
                else
                {
                    var rebuiltSig = sig.RedirectionRoot();
                    var rebuiltCasts = ctx.Invocations[oe].Casts.Zip(
                        sig.RedirectionRoot().ToXArgs(oe.XArgsCount()), 
                        (cast, param) => Cast.Lookup(cast.Source, param));
                    // todo. the stuff above sucks since there's no cast from string to object

                    var compiledOperands = CompileCallArguments(
                        rebuiltSig, rebuiltCasts, oe.Operands, ctx);

                    var ctorArgs = compiledOperands.Cast<Object>();
                    ctorArgs = ctorArgs.Concat(rebuiltSig.AsArray());
                    return actualOpType.LinqExpressionFactory()(ctorArgs.ToArray());
                }
            }
        }