private void makeOutputTypeInference(ExpressionNode expression, TypeInfo toType, HashMap<TypeInfo, TypeVariableInfo> typeVariables) {
            if (expression.ExpressionKind == ExpressionKind.Lambda
                    || BytecodeHelper.isDelegateType(toType)
                    || BytecodeHelper.isExpressionTreeType(toType)) {
                MethodInfo method = getInvokeMethod(toType);
                if (method == null) {
                    return;
                }
                if (expression.ExpressionKind == ExpressionKind.Lambda) {
	                var lambda = (LambdaExpressionNode)expression;
	                if (lambda.Parameters.size() != method.Parameters.count()) {
	                	return;
	                }
	            }
                var paramTypes = new ArrayList<TypeInfo>();
                foreach (var p in method.Parameters) {
                    TypeVariableInfo pinfo = typeVariables[p.Type];
                    if (pinfo != null) {
                        if (pinfo.fixedType != null) {
                            paramTypes.add(pinfo.fixedType);
                        } else {
                            return;
                        }
                    } else {
                        var t = bindGenericParameters(typeVariables, p.Type);
                        if (t == null) {
                            return;
                        } else {
                            paramTypes.add(t);
                        }
                    }
                }
                if (expression.ExpressionKind == ExpressionKind.Lambda) {
                    context.CodeValidationContext.pushLambdaParameters(paramTypes);
                    var success = expressionValidator.handleExpressionNoError(expression, null, true);
                    context.CodeValidationContext.popLambdaParameters();
                    var info = expression.getUserData(typeof(ExpressionInfo));
                    if (info == null) {
                        return;
                    }
                    expression.removeUserData(typeof(ExpressionInfo));
                    if (success) {
                        makeLowerBoundInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariables);
                    }
                } else {
                    var info = expression.getUserData(typeof(ExpressionInfo));
                    if (info == null) {
                        return;
                    }
                    var meth = resolveMethodGroup(info, method, paramTypes);
                    if (meth == null) {
                        makeLowerBoundInference(ValidationHelper.getType(context, expression), toType, typeVariables);
                    } else {
                        makeLowerBoundInference(meth.ReturnType, method.ReturnType, typeVariables);
                    }
                }
            } else {
                var info = expression.getUserData(typeof(ExpressionInfo));
                if (info == null) {
                    return;
                }
                makeLowerBoundInference(info.Type, toType, typeVariables);
            }
        }
 private bool isArgumentCompatible(ExpressionNode argNode, TypeInfo paramType) {
     var ainfo = argNode.getUserData(typeof(ExpressionInfo));
     var cleanInfo = false;
     if (ainfo == null && argNode.ExpressionKind == ExpressionKind.Lambda) {
         if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) {
             argNode.removeUserData(typeof(ExpressionInfo));
             return false;
         }
         ainfo = argNode.getUserData(typeof(ExpressionInfo));
         cleanInfo = true;
     }
     if (ainfo == null) {
         return !paramType.IsPrimitive;
     }
     if (BytecodeHelper.isDelegateType(paramType)) {
         if (!resolveDelegate(paramType, argNode, null, null)) {
             if (cleanInfo) {
                 argNode.removeUserData(typeof(ExpressionInfo));
             }
             return false;
         }
     } else if (ValidationHelper.isMethod(argNode)) {
         return false;
     } else if (paramType != ValidationHelper.getType(context, argNode)) {
         if (!ValidationHelper.isAssignable(context, paramType, argNode)) {
             if (cleanInfo) {
                 argNode.removeUserData(typeof(ExpressionInfo));
             }
             return false;
         }
     }
     if (cleanInfo) {
         argNode.removeUserData(typeof(ExpressionInfo));
     }
     return true;
 }
        private void makeExplicitParameterTypeInference(ExpressionNode expression, TypeInfo toType,
                HashMap<TypeInfo, TypeVariableInfo> typeVariableInfos) {
            var method = getInvokeMethod(toType);
            if (method == null) {
                return;
            }
            if (expression.ExpressionKind == ExpressionKind.Lambda) {
                var lambda = (LambdaExpressionNode)expression;
                if (lambda.Parameters.size() != method.Parameters.count()) {
                	return;
                }
            }
            var rinfo = typeVariableInfos[method.ReturnType];
            if (rinfo != null) {
                foreach (var p in method.Parameters) {
                    if (p.Type == method.ReturnType) {
                        continue;
                    }
                    var pinfo = typeVariableInfos[p.Type];
                    if (pinfo != null) {
                        rinfo.dependencies.add(pinfo.genericParameterType);
                    }
                }
            }

            if (expression.ExpressionKind == ExpressionKind.Lambda) {
                var lambda = (LambdaExpressionNode)expression;
                var fromTypes = new ArrayList<TypeInfo>();
                var pit = method.Parameters.iterator();
                foreach (var p in lambda.Parameters) {
                    var ptype = pit.next().Type;
                    if (p.Type == null) {
                        if (ptype.IsClosed) {
                            fromTypes.add(ptype);
                        } else {
                            return;
                        }
                    } else {
                        fromTypes.add(CompilerHelper.resolveTypeReference(context, context.CurrentType.PackageName, p.Type));
                    }
                }
                context.CodeValidationContext.pushLambdaParameters(fromTypes);
                bool success = expressionValidator.handleExpressionNoError(expression, null, true);
                context.CodeValidationContext.popLambdaParameters();
                var info = expression.getUserData(typeof(ExpressionInfo));
                if (info == null) {
                    return;
                }
                expression.removeUserData(typeof(ExpressionInfo));
                if (!success) {
                    return;
                }
                var mit = method.Parameters.iterator();
                var fit = fromTypes.iterator();
                while (mit.hasNext()) {
                    makeExactInference(fit.next(), mit.next().Type, typeVariableInfos);
                }
                makeExactInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariableInfos);
            } else {
                var info = expression.getUserData(typeof(ExpressionInfo));
                if (info == null) {
                    return;
                }
                var paramTypes = new ArrayList<TypeInfo>();
                foreach (var p in method.Parameters) {
                    paramTypes.add(p.Type);
                }
                var meth = resolveMethodGroup(info, method, paramTypes);
                if (meth == null) {
                    return;
                }
                var mit = method.Parameters.iterator();
                var cit = meth.Parameters.iterator();
                while (mit.hasNext()) {
                    makeExactInference(cit.next().Type, mit.next().Type, typeVariableInfos);
                }
                makeExactInference(meth.ReturnType, method.ReturnType, typeVariableInfos);
            }
        }
        private BetterConversionResult getBetterConversionFromExpression(TypeInfo leftType, TypeInfo rightType, ExpressionNode expression) {
            if (leftType == rightType) {
                return BetterConversionResult.Neither;
            }
            if (expression.ExpressionKind == ExpressionKind.Lambda) {
                var leftMethod = getInvokeMethod(leftType);
                var rightMethod = getInvokeMethod(rightType);
                var leftReturnType = leftMethod.ReturnType;
                var rightReturnType = rightMethod.ReturnType;

                var lit = leftMethod.Parameters.iterator();
                var rit = rightMethod.Parameters.iterator();
                List<TypeInfo> paramTypes = null;
                while (lit.hasNext()) {
                    var lt = lit.next().Type;
                    var rt = rit.next().Type;
                    if (lt != rt) {
                        return BetterConversionResult.Neither;
                    }
                    if (paramTypes == null) {
                        paramTypes = new ArrayList<TypeInfo>();
                    }
                    paramTypes.add(lt);
                }
                if (paramTypes != null) {
                    context.CodeValidationContext.pushLambdaParameters(paramTypes);
                } else {
                    context.CodeValidationContext.pushLambdaParameters(Collections.emptyList<TypeInfo>());
                }
                expressionValidator.handleExpressionNoError(expression, null, true);
                context.CodeValidationContext.popLambdaParameters();
                
                var info = expression.getUserData(typeof(ExpressionInfo));
                expression.removeUserData(typeof(ExpressionInfo));
                if (info != null) {
                    if (leftReturnType == context.TypeSystem.VoidType) {
                        return BetterConversionResult.RightIsBetter;
                    }
                    if (rightReturnType == context.TypeSystem.VoidType) {
                        return BetterConversionResult.LeftIsBetter;
                    }
                    return getBetterConversionFromType(leftReturnType, rightReturnType, context.CodeValidationContext.LambdaReturnType);
                }
                return BetterConversionResult.Neither;
            } else {
                var info = expression.getUserData(typeof(ExpressionInfo));
                if (info == null) {
                    return BetterConversionResult.Neither;
                }
                return getBetterConversionFromType(leftType, rightType, ValidationHelper.getType(context, expression));
            }
        }