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;
 }
        private ExpressionNode parseBinaryExpression(int precedence, ExpressionNode leftExpression) {
            for (;;) {
                var prec = 0;
                var doParseType = false;
                var op = BinaryOperator.Add;
                var restorePoint = this.createRestorePoint();
                switch (lexicalUnit) {
                case Multiply:
                    prec = 1;
                    op = BinaryOperator.Multiply;
                    break;

                case Divide:
                    prec = 1;
                    op = BinaryOperator.Divide;
                    break;

                case Percent:
                    prec = 1;
                    op = BinaryOperator.Modulo;
                    break;

                case Plus:
                    prec = 2;
                    op = BinaryOperator.Add;
                    break;

                case Minus:
                    prec = 2;
                    op = BinaryOperator.Subtract;
                    break;

                case LeftShift:
                    prec = 3;
                    op = BinaryOperator.LeftShift;
                    break;

                case GreaterThan:
                    switch (scanner.nextLexicalUnit()) {
                    case GreaterThan:
                        restorePoint = createRestorePoint();
                        switch (scanner.nextLexicalUnit()) {
                        case GreaterThan:
                            prec = 3;
                            op = BinaryOperator.UnsignedRightShift;
                            break;
                        default:
                            this.restore(restorePoint);
                            prec = 3;
                            op = BinaryOperator.RightShift;
                            break;
                        case GreaterThanOrEqual:
                            this.restore(restorePoint);
                            return leftExpression;
                        }
                        break;
                    default:
                        this.restore(restorePoint);
                        prec = 4;
                        op = BinaryOperator.GreaterThan;
                        break;
                    case GreaterThanOrEqual:
                        this.restore(restorePoint);
                        return leftExpression;
                    }
                    break;

                case LessThan:
                    prec = 4;
                    op = BinaryOperator.LessThan;
                    break;

                case LessThanOrEqual:
                    prec = 4;
                    op = BinaryOperator.LessThanOrEqual;
                    break;

                case GreaterThanOrEqual:
                    prec = 4;
                    op = BinaryOperator.GreaterThanOrEqual;
                    break;

                case Keyword:
                    switch (scanner.Keyword) {
                    case As:
                        prec = 4;
                        doParseType = true;
                        op = BinaryOperator.As;
                        break;

                    case Instanceof:
                        prec = 4;
                        doParseType = true;
                        op = BinaryOperator.Instanceof;
                        break;

                    default:
                        return leftExpression;
                    }
                    break;

                case Equal:
                    prec = 5;
                    op = BinaryOperator.Equal;
                    break;

                case NotEqual:
                    prec = 5;
                    op = BinaryOperator.NotEqual;
                    break;

                case LogicalAnd:
                    prec = 6;
                    op = BinaryOperator.LogicalAnd;
                    break;

                case Xor:
                    prec = 7;
                    op = BinaryOperator.Xor;
                    break;

                case LogicalOr:
                    prec = 8;
                    op = BinaryOperator.LogicalOr;
                    break;

                case And:
                    prec = 9;
                    op = BinaryOperator.And;
                    break;

                case Or:
                    prec = 10;
                    op = BinaryOperator.Or;
                    break;

                case NullCoalescing:
                    prec = 11;
                    op = BinaryOperator.NullCoalescing;
                    break;

                default:
                    return leftExpression;
                }
                if (prec > precedence) {
                    if (op == BinaryOperator.RightShift) {
                        this.restore(restorePoint);
                    }
                    return leftExpression;
                }
                nextLexicalUnit(true);
                var binary = new BinaryExpressionNode { Operator = op, LeftOperand = leftExpression };
                copyScannerState(leftExpression, binary);
                if (doParseType) {
                    var type = new TypeExpressionNode { TypeReference = parseType(true) };
                    copyScannerState(type.TypeReference, type);
                    type.EndPosition = type.TypeReference.EndPosition;
                    binary.RightOperand = type;
                } else {
                    binary.RightOperand = parseBinaryExpression(prec - 1, parseUnaryExpression());
                }
                binary.EndPosition = binary.RightOperand.EndPosition;
                leftExpression = binary;
            }
        }
        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 String expressionToString(ExpressionNode expression) {
			var sb = new StringBuilder();
			var first = false;
			switch (expression.ExpressionKind) {
			case Literal:
				var literal = (LiteralExpressionNode)expression;
				sb.append("Literal(");
				sb.append(literal.LiteralKind);
				sb.append(", [");
				sb.append(new String(text, literal.ValueOffset, literal.ValueLength));
				sb.append("])");
				break;
				
			case MemberAccess:
				var member = (MemberAccessExpressionNode)expression;
				sb.append("(");
				sb.append(expressionToString(member.TargetObject));
				sb.append(").");
				sb.append(new String(text, member.Member.NameOffset, member.Member.NameLength));
				break;
				
			case NullSafeMemberAccess:
				var nsmember = (NullSafeMemberAccessExpressionNode)expression;
				sb.append("(");
				sb.append(expressionToString(nsmember.TargetObject));
				sb.append(")?.");
				sb.append(new String(text, nsmember.Member.NameOffset, nsmember.Member.NameLength));
				break;
				
			case Type:
				var type = (TypeExpressionNode)expression;
				sb.append("Type(");
				sb.append(typeReferenceToString(type.TypeReference));
				sb.append(")");
				break;

			case SimpleName:
				var name = (SimpleNameExpressionNode)expression;
				sb.append("Name(");
				sb.append(new String(text, name.NameOffset, name.NameLength));
				formatTypeArguments(name.TypeArguments, sb);
				sb.append(")");
				break;

			case ThisAccess:
				sb.append("this");
				break;

			case SuperAccess:
				sb.append("base");
				break;

			case ObjectCreation:
				var objectCreation = (ObjectCreationExpressionNode)expression;
				sb.append("new ");
				sb.append(typeReferenceToString(objectCreation.Type));
				if (objectCreation.Arguments.size() > 0 || objectCreation.Initializer == null) {
					sb.append("(");
					first = true;
					foreach (var arg in objectCreation.Arguments) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						sb.append(expressionToString(arg));
					}
					sb.append(")");
				}
				if (objectCreation.Initializer != null) {
					sb.append(expressionToString(objectCreation.Initializer));
				}
				break;

			case ObjectInitializer:
				var objectInit = (ObjectInitializerExpressionNode)expression;
				sb.append("{");
				first = true;
				foreach (var mi in objectInit.MemberInitializers) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(new String(text, mi.NameOffset, mi.NameLength));
					sb.append("=");
					sb.append(expressionToString(mi.Value));
				}
				sb.append("}");
				break;

			case CollectionInitializer:
				var collectionInit = (CollectionInitializerExpressionNode)expression;
				sb.append("{");
				first = true;
				foreach (var v in collectionInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append("{");
					var f = true;
					foreach (var exp in v) {
						if (f) {
							f = false;
						} else {
							sb.append(", ");
						}
						sb.append(expressionToString(exp));
					}
					sb.append("}");
				}
				sb.append("}");
				break;

			case AnonymousObjectCreation:
				var anonymousCreation = (AnonymousObjectCreationExpressionNode)expression;
				sb.append("new{");
				first = true;
				foreach (var decl in anonymousCreation.MemberDeclarators) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					if (decl.NameLength > 0) {
						sb.append(new String(text, decl.NameOffset, decl.NameLength));
						sb.append("=");
					}
					sb.append(expressionToString(decl.Value));
				}
				sb.append("}");
				break;

			case ArrayCreation:
				var arrayCreation = (ArrayCreationExpressionNode)expression;
				sb.append("new");
				if (arrayCreation.Type != null) {
					sb.append(" ");
					sb.append(typeReferenceToString(arrayCreation.Type));
				}
				if (arrayCreation.DimensionExpressions.size() > 0) {
					sb.append("[");
					first = true;
					foreach (var exp in arrayCreation.DimensionExpressions) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						sb.append(expressionToString(exp));
					}
					sb.append("]");
				}
				if (arrayCreation.Dimensions > 0) {
					sb.append("[");
					for (int i = 1; i < arrayCreation.Dimensions; i++) {
						sb.append(",");
					}
					sb.append("]");
				}
				if (arrayCreation.Initializer != null) {
					sb.append(expressionToString(arrayCreation.Initializer));
				}
				break;

			case ArrayInitializer:
				var arrayInit = (ArrayInitializerExpressionNode)expression;
				sb.append("{");
				first = true;
				foreach (var v in arrayInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(expressionToString(v));
				}
				sb.append("}");
				break;

			case ElementAccess:
				var elementAccess = (ElementAccessExpressionNode)expression;
				sb.append("(");
				sb.append(expressionToString(elementAccess.TargetObject));
				sb.append(")[");
				first = true;
				foreach (var index in elementAccess.Indexes) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(expressionToString(index));
				}
				sb.append("]");
				break;

			case Invocation:
				var invocation = (InvocationExpressionNode)expression;
				sb.append(expressionToString(invocation.TargetObject));
				sb.append("(");
				first = true;
				foreach (var arg in invocation.Arguments) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(expressionToString(arg));
				}
				sb.append(")");
				break;

			case Unary:
				var unary = (UnaryExpressionNode)expression;
				sb.append("(");
				sb.append(unary.Operator.toString());
				sb.append(" ");
				sb.append(expressionToString(unary.Operand));
				sb.append(")");
				break;
				
			case Binary:
				var binary = (BinaryExpressionNode)expression;
				sb.append("(");
				sb.append(expressionToString(binary.LeftOperand));
				sb.append(" ");
				sb.append(binary.Operator.toString());
				sb.append(" ");
				sb.append(expressionToString(binary.RightOperand));
				sb.append(")");
				break;
				
			case Cast:
				var cast = (CastExpressionNode)expression;
				sb.append("Cast<");
				sb.append(typeReferenceToString(cast.TargetType));
				sb.append(">(");
				sb.append(expressionToString(cast.Expression));
				sb.append(")");
				break;
				
			case Assign:
				var assign = (AssignExpressionNode)expression;
				sb.append("Assign(");
				sb.append(expressionToString(assign.Left));
				sb.append(" ");
				sb.append(assign.Operator.toString());
				sb.append(" ");
				sb.append(expressionToString(assign.Right));
				sb.append(")");
				break;

			case Lambda:
				var lambda = (LambdaExpressionNode)expression;
				sb.append("Lambda(");
				first = true;
				foreach (var par in lambda.Parameters) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					if (par.Modifier != ParameterModifier.None) {
						sb.append(par.Modifier.toString().toLowerCase());
						sb.append(" ");
					}
					if (par.Type != null) {
						sb.append(typeReferenceToString(par.Type));
						sb.append(" ");
					}
					sb.append(new String(text, par.NameOffset, par.NameLength));
				}
				sb.append(" => ");
				sb.append(statementToString(lambda.Body));
				sb.append(")");
				break;

			case Conditional:
				var conditional = (ConditionalExpressionNode)expression;
				sb.append(expressionToString(conditional.Condition));
				sb.append("?");
				sb.append(expressionToString(conditional.IfTrue));
				sb.append(":");
				sb.append(expressionToString(conditional.IfFalse));
				break;

			case Typeof:
				var tpof = (TypeofExpressionNode)expression;
				sb.append("typeof(");
				sb.append(typeReferenceToString(tpof.Type));
				sb.append(")");
				break;

			case Query:
				var query = (QueryExpressionNode)expression;
				sb.append("from ");
				if (query.From.Type != null) {
					sb.append(typeReferenceToString(query.From.Type));
					sb.append(" ");
				}
				sb.append(new String(text, query.From.NameOffset, query.From.NameLength));
				sb.append(" in ");
				sb.append(expressionToString(query.From.Origin));
				sb.append("\r\n");
				formatQueryBody(query.Body, sb);
				break;

			default:
				throw new RuntimeException("Unhandled expression type: " + expression.ExpressionKind);
			}
			return sb.toString();
		}
 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 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 void print(ExpressionNode expression, StringBuilder sb) {
			if (expression.Parenthesized) {
				sb.append("(");
			}
			switch (expression.ExpressionKind) {
			case Literal:
				var literal = (LiteralExpressionNode)expression;
				sb.append(new String(text, literal.ValueOffset, literal.ValueLength));
				break;

			case SimpleName:
				var name = (SimpleNameExpressionNode)expression;
				sb.append(name.Name ?? new String(text, name.NameOffset, name.NameLength));
				if (name.TypeArguments.size() > 0) {
					print(name.TypeArguments, sb);
				}
				break;

			case Invocation:
				var invocation = (InvocationExpressionNode)expression;
				print(invocation.TargetObject, sb);
				sb.append("(");
				var first = true;
				foreach (var arg in invocation.getArguments()) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(arg, sb);
				}
				sb.append(")");
				break;

			case MemberAccess:
				var access = (MemberAccessExpressionNode)expression;
				print(access.TargetObject, sb);
				sb.append(".");
				sb.append(access.Member.Name ?? new String(text, access.Member.NameOffset, access.Member.NameLength));
				if (access.Member.TypeArguments.size() > 0) {
					print(access.Member.TypeArguments, sb);
				}
				break;

			case NullSafeMemberAccess:
				var nsaccess = (NullSafeMemberAccessExpressionNode)expression;
				print(nsaccess.TargetObject, sb);
				sb.append("?.");
				sb.append(nsaccess.Member.Name ?? new String(text, nsaccess.Member.NameOffset, nsaccess.Member.NameLength));
				if (nsaccess.Member.TypeArguments.size() > 0) {
					print(nsaccess.Member.TypeArguments, sb);
				}
				break;

			case Assign:
				var assign = (AssignExpressionNode)expression;
				print(assign.Left, sb);
				switch (assign.Operator) {
				case Assign:
					sb.append(" = ");
					break;

				case Or:
					sb.append(" |= ");
					break;

				case Add:
					sb.append(" += ");
					break;

				case Multiply:
					sb.append(" *= ");
					break;

				default:
					throw new RuntimeException("Assignment not supported: " + assign.getOperator());
				}
				print(assign.Right, sb);
				break;

			case ElementAccess:
				var elementAccess = (ElementAccessExpressionNode)expression;
				print(elementAccess.TargetObject, sb);
				sb.append("[");
				first = true;
				foreach (var i in elementAccess.Indexes) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(i, sb);
				}
				sb.append("]");
				break;

			case Unary:
				var unary = (UnaryExpressionNode)expression;
				switch (unary.Operator) {
				case PostIncrement:
				case PostDecrement:
					break;

				case Plus:
					sb.append("+");
					break;

				case Minus:
					sb.append("-");
					break;

				case Not:
					sb.append("!");
					break;

				case Complement:
					sb.append("~");
					break;

				case PreIncrement:
					sb.append("++");
					break;

				case PreDecrement:
					sb.append("--");
					break;

				default:
					throw new RuntimeException("Unary operator not supported: " + unary.getOperator());
				}
				print(unary.Operand, sb);
				switch (unary.Operator) {
				case PostIncrement:
					sb.append("++");
					break;

				case PostDecrement:
					sb.append("--");
					break;
				}
				break;

			case Binary:
				var binary = (BinaryExpressionNode)expression;
				print(binary.LeftOperand, sb);
				switch (binary.Operator) {
				case Add:
					sb.append(" + ");
					break;

				case Subtract:
					sb.append(" - ");
					break;

				case Multiply:
					sb.append(" * ");
					break;

				case Modulo:
					sb.append(" % ");
					break;

				case Divide:
					sb.append(" / ");
					break;

				case Equal:
					sb.append(" == ");
					break;

				case NotEqual:
					sb.append(" != ");
					break;

				case LessThan:
					sb.append(" < ");
					break;

				case LessThanOrEqual:
					sb.append(" <= ");
					break;

				case GreaterThan:
					sb.append(" > ");
					break;

				case GreaterThanOrEqual:
					sb.append(" >= ");
					break;

				case LeftShift:
					sb.append(" << ");
					break;

				case RightShift:
					sb.append(" >> ");
					break;

				case UnsignedRightShift:
					sb.append(" >>> ");
					break;

				case LogicalAnd:
					sb.append(" && ");
					break;

				case LogicalOr:
					sb.append(" || ");
					break;

				case And:
					sb.append(" & ");
					break;

				case Or:
					sb.append(" | ");
					break;

				case NullCoalescing:
					sb.append(" ?? ");
					break;

				case Instanceof:
					sb.append(" is ");
					break;

				case As:
					sb.append(" as ");
					break;

				default:
					throw new RuntimeException("Binary operator not supported: " + binary.getOperator());
				}
				print(binary.RightOperand, sb);
				break;

			case ObjectCreation:
				var objectCreation = (ObjectCreationExpressionNode)expression;
				sb.append("new ");
				print(objectCreation.Type, sb);
				if (objectCreation.Arguments.size() > 0 || objectCreation.Initializer == null) {
					sb.append("(");
					first = true;
					foreach (var arg in objectCreation.Arguments) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						print(arg, sb);
					}
					sb.append(")");
				}
				if (objectCreation.Initializer != null) {
					print(objectCreation.Initializer, sb);
				}
				break;

			case ObjectInitializer:
				var objectInit = (ObjectInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var mi in objectInit.getMemberInitializers()) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(new String(text, mi.NameOffset, mi.NameLength));
					sb.append(" = ");
					print(mi.Value, sb);
				}
				sb.append(" }");
				break;

			case ArrayCreation:
				var arrayCreation = (ArrayCreationExpressionNode)expression;
				sb.append("new");
				if (arrayCreation.Type != null) {
					sb.append(" ");
					print(arrayCreation.Type, sb);
				}
				if (arrayCreation.DimensionExpressions.size() > 0) {
					sb.append("[");
					first = true;
					foreach (var exp in arrayCreation.DimensionExpressions) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						print(exp, sb);
					}
					sb.append("]");
				}
				if (arrayCreation.Dimensions > 0) {
					sb.append("[");
					for (int i = 1; i < arrayCreation.Dimensions; i++) {
						sb.append(",");
					}
					sb.append("]");
				}
				if (arrayCreation.Initializer != null) {
					print(arrayCreation.Initializer, sb);
				}
				break;

			case ArrayInitializer:
				var arrayInit = (ArrayInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var v in arrayInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(v, sb);
				}
				sb.append(" }");
				break;

			case CollectionInitializer:
				var collInit = (CollectionInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var v in collInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append("{ ");
					var firstExp = true;
					foreach (var exp in v) {
						if (firstExp) {
							firstExp = false;
						} else {
							sb.append(", ");
						}
						print(exp, sb);
					}
					sb.append(" }");
				}
				sb.append(" }");
				break;

			case Lambda:
				var lambda = (LambdaExpressionNode)expression;
				if (lambda.Parameters.size() == 1 && lambda.Parameters[0].Type == null) {
					sb.append(lambda.Parameters[0].Name ?? new String(text, lambda.Parameters[0].NameOffset, lambda.Parameters[0].NameLength));
				} else {
					sb.append("(");
					first = true;
					foreach (var p in lambda.Parameters) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						if (p.Type != null) {
							print(p.Type, sb);
							sb.append(" ");
						}
						sb.append(p.Name ?? new String(text, p.NameOffset, p.NameLength));
					}
					sb.append(")");
				}
				sb.append(" => ");
				print(lambda.Body, 0, false, sb);
				break;
				
			case Typeof:
				var typeofExp = (TypeofExpressionNode)expression;
				sb.append("typeof(");
				print(typeofExp.Type, sb);
				sb.append(")");
				break;
				
			case AnonymousObjectCreation:
				var anonymous = (AnonymousObjectCreationExpressionNode)expression;
				sb.append("new { ");
				first = true;
				foreach (var decl in anonymous.MemberDeclarators) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					if (decl.NameLength > 0) {
						sb.append(new String(text, decl.NameOffset, decl.NameLength));
						sb.append(" = ");
					}
					print(decl.Value, sb);
				}
				sb.append(" }");
				break;
				
			default:
				throw new RuntimeException("Expression not supported: " + expression.getExpressionKind());
			}
			if (expression.Parenthesized) {
				sb.append(")");
			}
		}
        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));
            }
        }