bool TransformArrayInitializers(List<ILNode> body, ILExpression expr, int pos)
		{
			ILVariable v, v3;
			ILExpression newarrExpr;
			TypeReference elementType;
			ILExpression lengthExpr;
			int arrayLength;
			if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
			    newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) &&
			    lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
			    arrayLength > 0) {
				ILExpression[] newArr;
				int initArrayPos;

				if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) {
                    var arrayType = new ArrayType(
                        elementType,
                        new[] { new ArrayDimension(0, arrayLength) });

					body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
					body.RemoveAt(initArrayPos);
				}

				// Put in a limit so that we don't consume too much memory if the code allocates a huge array
				// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
				const int maxConsecutiveDefaultValueExpressions = 300;
				List<ILExpression> operands = new List<ILExpression>();
				int numberOfInstructionsToRemove = 0;
				for (int j = pos + 1; j < body.Count; j++) {
					ILExpression nextExpr = body[j] as ILExpression;
					int arrayPos;
					if (nextExpr != null &&
					    nextExpr.Code.IsStoreToArray() &&
					    nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
					    v == v3 &&
					    nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
					    arrayPos >= operands.Count &&
					    arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) {
						while (operands.Count < arrayPos)
							operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
						operands.Add(nextExpr.Arguments[2]);
						numberOfInstructionsToRemove++;
					} else {
						break;
					}
				}
				if (operands.Count == arrayLength) {
                    var arrayType = new ArrayType(
                        elementType,
                        new[] { new ArrayDimension(0, arrayLength) });

					expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands);
					body.RemoveRange(pos + 1, numberOfInstructionsToRemove);

					new ILInlining(method).InlineIfPossible(body, ref pos);
					return true;
				}
			}
			return false;
		}
		bool TransformMultidimensionalArrayInitializers(List<ILNode> body, ILExpression expr, int pos)
		{
			ILVariable v;
			ILExpression newarrExpr;
			MethodReference ctor;
			List<ILExpression> ctorArgs;
			ArrayType arrayType;
			if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
			    newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
			    (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
			    arrayType.Rank == ctorArgs.Count) {
				// Clone the type, so we can muck about with the Dimensions
				
                int[] arrayLengths = new int[arrayType.Rank];
				for (int i = 0; i < arrayType.Rank; i++) {
					if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i])) return false;
					if (arrayLengths[i] <= 0) return false;
				}

                arrayType = new ArrayType(
                    arrayType.ElementType,
                    from l in arrayLengths
                    select new ArrayDimension(0, l));

				var totalElements = arrayLengths.Aggregate(1, (t, l) => t * l);
				ILExpression[] newArr;
				int initArrayPos;
				if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos)) {
					var mdArr = Array.CreateInstance(typeof(ILExpression), arrayLengths);
					body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
					body.RemoveAt(initArrayPos);
					return true;
				}
			}
			return false;
		}
		static bool AreSame (ArrayType a, ArrayType b)
		{
			if (a.Rank != b.Rank)
				return false;

			// TODO: dimensions

			return true;
		}