static void setBoxing(CompilerContext context, TypeInfo targetType, ExpressionNode expression) {
     var info = expression.getUserData(typeof(ExpressionInfo));
     if (info == null || targetType == null) {
         return;
     }
     var type = getType(context, expression);
     if (type == targetType) {
         return;
     }
     if (isAssignable(context, targetType, expression)) {
         if (targetType.IsPrimitive) {
             if (!type.IsPrimitive) {
                 info.BoxingKind = BoxingKind.Unbox;
                 var unboxinMethod = context.TypeSystem.getUnboxingMethod(type);
                 info.BoxingMethod = unboxinMethod;
                 info.OriginalType = info.Type;
                 info.Type = unboxinMethod.ReturnType;
             }
         } else if (type.IsPrimitive) {
             info.BoxingKind = BoxingKind.Box;
             var boxingMethod = context.TypeSystem.getBoxingMethod((targetType.IsObject) ? type : targetType);
             info.BoxingMethod = boxingMethod;
             info.OriginalType = info.Type;
             info.Type = boxingMethod.ReturnType;
         } else if (targetType.IsNumeric && type.IsNumeric) {
             info.BoxingKind = BoxingKind.Unbox;
             info.BoxingMethod = context.TypeSystem.getUnboxingMethod(type);
         }
     }
 }
 static bool isMethod(ExpressionNode argNode) {
     var info = argNode.getUserData(typeof(ExpressionInfo));
     if (info == null || info.Type != null) {
         return false;
     } else if (info.IsConstant) {
         return false;
     } else if (info.Members != null) {
         foreach (var member in info.Members) {
             if (member.MemberKind != MemberKind.Method) {
                 return false;
             }
         }
     }
     return true;
 }
        static TypeInfo getType(CompilerContext context, ExpressionNode expression) {
            if (ValidationHelper.isMethod(expression)) {
                throw context.error(CompileErrorId.UnexpectedMethodReference, expression);
            }
            var info = expression.getUserData(typeof(ExpressionInfo));
            if (info.Type != null) {
                return info.Type;
            } else if (info.IsConstant) {
                context.ConstantBuilder.buildConstant(expression);
                return info.Type;
            } else if (info.Members != null) {
                foreach (var member in info.Members) {
                    switch (member.MemberKind) {
                    case Field:
                        var field = member.Field;
                        if (field.Value != null) {
                            info.IsConstant = true;
                            info.Value = field.Value;
                        }
                        info.Member = member;
                        info.Type = member.Type;
                        if (!isInDeprecatedContext(context)) {
							if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, field)) {
								context.addWarning(CompileErrorId.DeprecatedField, expression,
										BytecodeHelper.getDisplayName(field.DeclaringType), field.Name);
							}
                        }
						if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) {
	                    	if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) {
				                var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod];
				                if (typeBuilder.getField("this$0") == null) {
				                    typeBuilder.defineField("this$0", context.CurrentType);
				                }
	                    	}
                    	}
                        return member.Type;
                        
                    case Type:
                        info.Member = member;
                        info.Type = member.Type;
                        if (!isInDeprecatedContext(context)) {
							if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, info.Type)) {
								context.addWarning(CompileErrorId.DeprecatedType, expression,
										BytecodeHelper.getDisplayName(info.Type));
							}
						}
                        return member.Type;
						
                    case Indexer:
                    case Property:
                        info.Member = member;
                        info.Type = member.Type;
                        if (!isInDeprecatedContext(context)) {
							if (member.GetAccessor != null) {
								if (member.SetAccessor == null) {
									if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor)) {
										context.addWarning(CompileErrorId.DeprecatedProperty, expression,
												BytecodeHelper.getDisplayName(member.DeclaringType), member.Name);
									}
								} else {
									if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor) &&
											BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) {
										context.addWarning(CompileErrorId.DeprecatedProperty, expression,
												BytecodeHelper.getDisplayName(member.DeclaringType), member.Name);
									}
								}
							} else if (member.SetAccessor != null) {
								if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) {
									context.addWarning(CompileErrorId.DeprecatedProperty, expression,
											BytecodeHelper.getDisplayName(member.DeclaringType), member.Name);
								}
							}
						}
						if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) {
	                    	if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) {
				                var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod];
				                if (typeBuilder.getField("this$0") == null) {
				                    typeBuilder.defineField("this$0", context.CurrentType);
				                }
	                    	}
                    	}
                        return member.Type;
                        
                    case Local:
						if (context.CodeValidationContext.IsInMethod) {
	                        var currentMethod = context.CodeValidationContext.CurrentMethod;
	                      	var currentType = (TypeBuilder)currentMethod.DeclaringType;
	                        if (currentType.FullName.indexOf('#') == -1 && context.CodeValidationContext.IsInLambda) {
		                        if (currentMethod != member.Method) {
		                            member.IsUsedFromLambda = true;
					                var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod];
					                context.getLocalField(typeBuilder, (LocalMemberInfo)member);
		                        }
	                        }
                        }
                        info.Member = member;
                        info.Type = member.Type;
                        return member.Type;
                        
                    default:
                        break;
                    }
                }
                if (info.ExtensionMethods != null && info.ExtensionMethods.any()) {
                    return info.Type = info.ExtensionMethods.first().Parameters.first().Type;
                }
            }
            throw new Exception("Internal error line " + (expression.getLine() + 1));
        }
        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);
            }
        }
 static bool isAssignable(CompilerContext context, TypeInfo type, ExpressionNode expression) {
     var info = expression.getUserData(typeof(ExpressionInfo));
     if (info == null) {
         return !type.IsPrimitive;
     }
     var right = getType(context, expression);
     if (type.isAssignableFrom(right)) {
         return true;
     }
     if (expression.ExpressionKind == ExpressionKind.ArrayInitializer) {
         if (!type.IsArray) {
             return false;
         }
         foreach (var e in ((ArrayInitializerExpressionNode)expression).Values) {
             if (!isAssignable(context, type.ElementType, e)) {
                 return false;
             }
         }
         return true;
     }
     if (type.IsNumeric && info.IsConstant) {
         switch (type.NumericTypeKind) {
         case Byte: {
             long value;
             switch (right.TypeKind) {
             case Char:
                 value = ((Character)info.Value).charValue();
                 break;
             case Int:
             case Long:
             case Short:
                 value = ((Number)info.Value).longValue();
                 break;
             default:
                 return false;
             }
             return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE;
         }
         case Char: {
             long value;
             switch (right.TypeKind) {
             case Byte:
             case Int:
             case Long:
             case Short:
                 value = ((Number)info.Value).longValue();
                 break;
             default:
                 return false;
             }
             return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE;
         }
         case Short: {
             long value;
             switch (right.TypeKind) {
             case Byte:
                 return true;
             case Char:
                 value = ((Character)info.Value).charValue();
                 break;
             case Int:
             case Long:
                 value = ((Number)info.Value).longValue();
                 break;
             default:
                 return false;
             }
             return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE;
         }
         case Int: {
             long value;
             switch (right.getTypeKind()) {
             case Char:
                 value = ((Character)info.Value).charValue();
                 break;
             case Byte:
             case Short:
                 return true;
             case Long:
                 value = ((Number)info.getValue()).longValue();
                 break;
             default:
                 return false;
             }
             return Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE;
         }
         }
     }
     return false;
 }
        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 VarargCompatible isVarargCompatible(ExpressionNode argNode, TypeInfo paramType, bool first) {
     var ainfo = argNode.getUserData(typeof(ExpressionInfo));
     if (ainfo == null) {
         if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) {
             return VarargCompatible.False;
         }
         ainfo = argNode.getUserData(typeof(ExpressionInfo));
     }
     if (ainfo == null) {
         if (paramType.IsPrimitive) {
             return VarargCompatible.False;
         }
     } else if (BytecodeHelper.isDelegateType(paramType)) {
         if (!resolveDelegate(paramType, argNode, null, null)) {
             return VarargCompatible.False;
         }
     } else if (ValidationHelper.isMethod(argNode)) {
         return VarargCompatible.False;
     } else if (paramType != ValidationHelper.getType(context, argNode)) {
         if (!ValidationHelper.isAssignable(context, paramType, argNode)) {
             if (first) {
                 if (ValidationHelper.isAssignable(context, paramType.ArrayType, argNode)) {
                     return VarargCompatible.True;
                 }
             }
             return VarargCompatible.False;
         }
     }
     return VarargCompatible.TrueExpanded;
 }
 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;
 }
 bool resolveDelegate(TypeInfo type, ExpressionNode arg, ExpressionInfo targetInfo, SyntaxNode node) {
     var invokeMethod = getInvokeMethod(type);
     int nparams = invokeMethod.Parameters.count();
     var ainfo = arg.getUserData(typeof(ExpressionInfo));
     if (ainfo.Members == null) {
         return true;
     }
     MemberInfo foundMember = null;
     foreach (var member in ainfo.Members) {
         switch (member.MemberKind) {
         case Method:
             var meth = member.Method;
             if (meth.Parameters.count() != nparams || meth.IsVarargs != invokeMethod.IsVarargs) {
                 continue;
             }
             if (nparams == 0) {
                 if (foundMember != null) {
                     if (node != null) {
                         throw context.error(CompileErrorId.AmbiguousMembers, node,
                             BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method),
                             BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "."
                             + BytecodeHelper.getDisplayName(foundMember.Method));
                     } else {
                         return false;
                     }
                 }
                 foundMember = member;
                 ainfo.Member = member;
                 if (meth.IsExcludedFromCompilation || CompilerHelper.shouldIgnoreCalls(context, meth)) {
                     if (node != null) {
                         throw context.error(CompileErrorId.NotGeneratedMethodUsage, node,
                             BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method));
                     } else {
                         return false;
                     }
                 }
                 if (targetInfo != null) {
                     targetInfo.Type = type;
                     targetInfo.Method = meth;
                 }
                 continue;
             }
             var it1 = meth.Parameters.iterator();
             var it2 = invokeMethod.Parameters.iterator();
             var sameParams = true;
             while (it1.hasNext()) {
                 if (it1.next().Type != it2.next().Type) {
                     sameParams = false;
                     break;
                 }
             }
             if (sameParams) {
                 if (foundMember != null) {
                     if (node != null) {
                         throw context.error(CompileErrorId.AmbiguousMembers, node,
                             BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method),
                             BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "." + foundMember.Name);
                     } else {
                         return false;
                     }
                 }
                 foundMember = member;
                 ainfo.Member = member;
                 if (targetInfo != null) {
                     targetInfo.Type = type;
                     targetInfo.Method = meth;
                 }
                 continue;
             }
             break;
         case Local:
             ainfo.Member = member;
             return true;
         case Field:
         case Property:
             foundMember = member;
             ainfo.Member = member;
             break;
         }
     }
     if (foundMember != null) {
         return true;
     }
     if (node != null) {
         throw context.error(CompileErrorId.NoEligibleOverload, node, ainfo.Members.first().Name);
     } else {
         return false;
     }
 }
        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));
            }
        }