Пример #1
0
        public static Tuple <Type, string> Generate <TOuterKey, TSource, TInnerKey>(
            Expression <Func <TInnerKey, int> > hashComparer,
            Expression <Func <TSource, TInnerKey> > keySelector,
            bool nested)
        {
            var             typeOfTOuterKey = typeof(TOuterKey);
            var             typeOfTSource   = typeof(TSource);
            var             typeOfTInnerKey = typeof(TInnerKey);
            string          expandedCode;
            List <Assembly> assemblyReferences;
            string          errorMessages = null;

            try
            {
                string generatedClassName = $"GeneratedGroupStreamable_{GroupStreamableSequenceNumber++}";

                string      transformedKeySelectorAsString;
                MyFieldInfo swingingField = default;
                if (typeOfTInnerKey.IsAnonymousTypeName())
                {
                    Contract.Assume(keySelector.Body is NewExpression);
                    var transformedFunction = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector);
                    var newBody             = (NewExpression)transformedFunction.Body;
                    transformedKeySelectorAsString = string.Join(",", newBody.Arguments.Select(arg => arg.ExpressionToCSharp()));
                }
                else
                {
                    var body = keySelector.Body;

                    if (!nested && body is MemberExpression singleFieldProjection)
                    {
                        if (singleFieldProjection.Expression is ParameterExpression dereferencedObject)
                        {
                            // then can just swing a pointer to set the key of the result message
                            Contract.Assume(dereferencedObject == keySelector.Parameters.ElementAt(0));
                            var f = singleFieldProjection.Member;
                            var sourceMessageRepresentation = new ColumnarRepresentation(typeOfTSource);
                            var fieldToSwingFrom            = sourceMessageRepresentation.Fields[f.Name];
                            swingingField = fieldToSwingFrom;
                            transformedKeySelectorAsString = swingingField.Name + "_col[i]";
                        }
                        else
                        {
                            var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body;
                            if (transformedPredicate == null)
                            {
                                return(Tuple.Create((Type)null, errorMessages));
                            }
                            transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp();
                        }
                    }
                    else
                    {
                        var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body;

                        if (transformedPredicate == null)
                        {
                            return(Tuple.Create((Type)null, errorMessages));
                        }
                        transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp();
                    }
                }

                var inlinedHashCodeComputation = hashComparer.Inline("key");

                var template = new GroupTemplate(
                    generatedClassName,
                    typeOfTOuterKey,
                    typeOfTSource,
                    typeOfTInnerKey,
                    transformedKeySelectorAsString,
                    inlinedHashCodeComputation,
                    nested)
                {
                    swingingField      = swingingField,
                    payloadMightBeNull = typeOfTSource.CanContainNull()
                };

                if (!nested && Config.UseMultiString &&
                    typeOfTInnerKey.Equals(typeof(string)) &&
                    keySelector.IsSimpleFieldOrPropertyAccess())
                {
                    var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body;
                    template.transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp();
                    template.inlinedHashCodeComputation     = "hashCodeVector.col[i]";
                    var fieldName = ((MemberExpression)keySelector.Body).Member.Name;
                    template.vectorHashCodeInitialization = $"resultBatch.hash = {Transformer.ColumnFieldPrefix}{fieldName}_col.GetHashCode(batch.bitvector);";
                    template.swingingHashColumn           = true;
                }

                template.fields = new ColumnarRepresentation(typeOfTSource).AllFields;

                expandedCode = template.TransformText();

                assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey);
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TOuterKey, TSource>());
                if (nested)
                {
                    assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>());
                    assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>());
                }
                else
                {
                    assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TInnerKey, TSource>());
                    assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TInnerKey, TSource>());
                }
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keySelector));

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                if (typeOfTInnerKey.IsAnonymousTypeName())
                {
                    if (errorMessages == null)
                    {
                        errorMessages = string.Empty;
                    }
                    errorMessages += "\nCodegen Warning: The inner key type for Group is anonymous, causing the use of Activator.CreateInstance in an inner loop. This will lead to poor performance.\n";
                }

                generatedClassName = generatedClassName.AddNumberOfNecessaryGenericArguments(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey);
                var t = a.GetType(generatedClassName);
                t = t.InstantiateAsNecessary(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey);

                return(Tuple.Create(t, errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
Пример #2
0
        internal static Tuple <Type, string> Generate <TKey, TPayload>(WhereStreamable <TKey, TPayload> stream)
        {
            string generatedClassName;
            string expandedCode;
            var    assemblyReferences = new List <Assembly>();
            string errorMessages      = null;

            try
            {
                var keyType = typeof(TKey);
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keyType));

                var sourceType = typeof(TPayload);
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(sourceType));
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(stream.Predicate));

                generatedClassName = string.Format("WhereUnaryPipeGeneratedFrom_{0}_{1}_{2}", keyType.GetValidIdentifier(), sourceType.GetValidIdentifier(), sequenceNumber++);

                var noTransformation = false;

                var p = stream.Predicate.Body;

                var    transformedPredicate   = p;
                var    multiStringInit        = string.Empty;
                var    multiStringReturns     = string.Empty;
                var    multiStringWrapperInit = string.Empty;
                string vectorOperations       = null;

                if (Config.UseMultiString && Config.MultiStringTransforms != Config.CodegenOptions.MultiStringFlags.None)
                {
                    var result = MultiStringTransformer.Transform(sourceType, transformedPredicate);
                    if (result.transformedExpression != null)
                    {
                        transformedPredicate = result.transformedExpression;
                    }

                    multiStringInit = string.Join("\n", result.wrapperTable.Select(e => string.Format(
                                                                                       "var {0} = new MultiString.MultiStringWrapper({1}{2}_col);",
                                                                                       e.Value.Name, Transformer.ColumnFieldPrefix, e.Key.Name)));
                    multiStringWrapperInit = string.Join("\n", result.wrapperTable.Select(e => string.Format("{0}.rowIndex = i;", e.Value.Name)));

                    vectorOperations = result.vectorOperation;
                }

                Contract.Assume(stream.Predicate.Parameters.Count() == 1);
                var parameter = stream.Predicate.Parameters.First();

                var x = Extensions.TransformUnaryFunction <TKey, TPayload>(Expression.Lambda(transformedPredicate, parameter));
                noTransformation     = x == null;
                transformedPredicate = noTransformation ? p : x.Body;

                var template = new WhereTemplate(
                    generatedClassName,
                    keyType,
                    sourceType,
                    transformedPredicate.ExpressionToCSharp(),
                    noTransformation,
                    stream.Predicate.Parameters[0].ToString(),
                    multiStringInit,
                    multiStringReturns)
                {
                    multiStringWrapperInit = multiStringWrapperInit,
                    vectorOperations       = vectorOperations
                };

                generatedClassName = generatedClassName.AddNumberOfNecessaryGenericArguments(keyType, sourceType);
                expandedCode       = template.TransformText();

                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>());
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var t = a.GetType(generatedClassName);
                t = t.InstantiateAsNecessary(typeof(TKey), typeof(TPayload));
                return(Tuple.Create(t, errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
Пример #3
0
        /// <summary>
        /// Generate a batch class definition to be used as an aggreate definition.
        /// Compile the definition, dynamically load the assembly containing it, and return the Type representing the
        /// aggregate class.
        /// </summary>
        /// <typeparam name="TKey">The key type for the aggregate.</typeparam>
        /// <typeparam name="TInput">The input type for the aggregate.</typeparam>
        /// <typeparam name="TOutput">The output type for the aggregate.</typeparam>
        /// <typeparam name="TState">The type for the accumulated state held by the aggregate.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <returns>
        /// A type that is defined to be a subtype of UnaryPipe&lt;<typeparamref name="TKey"/>,<typeparamref name="TInput"/>&gt;.
        /// </returns>
        internal static Tuple <Type, string> Generate <TKey, TInput, TState, TOutput, TResult>(
            GroupedWindowStreamable <TKey, TInput, TState, TOutput, TResult> stream)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(IStreamObserver <Empty, TInput>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string errorMessages = null;

            try
            {
                string expandedCode;

                var template = new GroupedWindowTemplate();

                var keyType    = template.keyType = typeof(TKey);
                var inputType  = template.inputType = typeof(TInput);
                var stateType  = template.stateType = typeof(TState);
                var outputType = template.outputType = typeof(TOutput);
                var resultType = template.resultType = typeof(TResult);

                template.TResult     = resultType.GetCSharpSourceSyntax(); // BUGBUG: need to get any generic parameters needed
                template.isUngrouped = (keyType == typeof(Empty));
                template.className   = string.Format("GeneratedGroupedAggregate_{0}", GroupedAggregateSequenceNumber++);

                var inputMessageRepresentation = new ColumnarRepresentation(inputType);

                var resultRepresentation = new ColumnarRepresentation(resultType);

                var assemblyReferences = new List <Assembly>();

                #region Key Selector
                var    keySelector = stream.KeySelector;
                string transformedKeySelectorAsString;
                if (keyType.IsAnonymousTypeName())
                {
                    Contract.Assume(keySelector.Body is NewExpression);
                    var transformedFunction = Extensions.TransformUnaryFunction <TKey, TInput>(keySelector);
                    var newBody             = (NewExpression)transformedFunction.Body;
                    transformedKeySelectorAsString = string.Join(",", newBody.Arguments);
                }
                else
                {
                    var transformedFunction = Extensions.TransformUnaryFunction <Empty, TInput>(keySelector).Body;
                    if (transformedFunction == null)
                    {
                        return(null);
                    }
                    transformedKeySelectorAsString = transformedFunction.ExpressionToCSharp();
                }
                template.keySelector = transformedKeySelectorAsString;
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keySelector));
                #endregion

                #region Key Comparer and HashCode
                var keyComparer = EqualityComparerExpression <TKey> .Default;
                template.keyComparerEquals =
                    (left, right) =>
                    keyComparer.GetEqualsExpr().Inline(left, right);
                template.keyComparerGetHashCode =
                    (x) =>
                    keyComparer.GetGetHashCodeExpr().Inline(x);
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keyComparer.GetEqualsExpr()));
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keyComparer.GetGetHashCodeExpr()));
                #endregion

                #region Aggregate functions
                var initialStateLambda = stream.Aggregate.InitialState();
                if (ConstantExpressionFinder.IsClosedExpression(initialStateLambda))
                {
                    template.initialState = initialStateLambda.Body.ExpressionToCSharp();
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(initialStateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for GroupedWindow: couldn't inline the initial state lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledInitialState = true;
                        template.initialState            = "initialState()";
                    }
                }

                var accumulateLambda = stream.Aggregate.Accumulate();
                if (ConstantExpressionFinder.IsClosedExpression(accumulateLambda))
                {
                    var accTransformedLambda = Extensions.TransformFunction <TKey, TInput>(accumulateLambda, 2);
                    template.accumulate = (stateArg, longArg) => accTransformedLambda.Inline(stateArg, longArg);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(accumulateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for GroupedWindow: couldn't inline the accumulate lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledAccumulate = true;
                        template.accumulate            = (s1, s2) => string.Format("accumulate({0}, {1}, batch[i]);", s1, s2);
                    }
                }

                var deaccumulateLambda = stream.Aggregate.Deaccumulate();
                if (ConstantExpressionFinder.IsClosedExpression(deaccumulateLambda))
                {
                    var deaccumulateTransformedLambda = Extensions.TransformFunction <TKey, TInput>(deaccumulateLambda, 2);
                    template.deaccumulate = (stateArg, longArg) => deaccumulateTransformedLambda.Inline(stateArg, longArg);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(deaccumulateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        throw new InvalidOperationException("Code Generation couldn't inline a lambda!");
                    }
                    else
                    {
                        template.useCompiledDeaccumulate = true;
                        template.deaccumulate            = (s1, s2) => string.Format("deaccumulate({0}, {1}, batch[i]);", s1, s2);
                    }
                }

                var differenceLambda = stream.Aggregate.Difference();
                if (ConstantExpressionFinder.IsClosedExpression(differenceLambda))
                {
                    template.difference = (stateArg1, stateArg2) => differenceLambda.Inline(stateArg1, stateArg2);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(differenceLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for GroupedWindow: couldn't inline the deaccumulate lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledDifference = true;
                        template.deaccumulate          = (s1, s2) => string.Format("difference({0}, {1});", s1, s2);
                    }
                }

                var computeResultLambda = stream.Aggregate.ComputeResult();
                if (ConstantExpressionFinder.IsClosedExpression(computeResultLambda))
                {
                    if (outputType.IsAnonymousType())
                    {
                        if (computeResultLambda.Body is NewExpression newExpression)
                        {
                            errorMessages = "Code Generation for GroupedWindow: result selector must be a new expression for anonymous types";
                            throw new NotImplementedException(errorMessages);
                        }
                        else
                        {
                            template.computeResult = (stateArg) => computeResultLambda.Inline(stateArg);
                        }
                    }
                    else
                    {
                        template.computeResult = (stateArg) => computeResultLambda.Inline(stateArg);
                    }
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(computeResultLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for GroupedWindow: couldn't inline the result selector lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledComputeResult = true;
                        template.computeResult            = (stateArg) => "computeResult(" + stateArg + ")";
                    }
                }
                #endregion

                template.BatchGeneratedFrom_Unit_TInput = Transformer.GetBatchClassName(typeof(Empty), inputType);
                template.UnitTInputGenericParameters    = string.Empty; // BUGBUG
                template.UnitTResultGenericParameters   = string.Empty; // BUGBUG
                template.inputFields  = inputMessageRepresentation.AllFields;
                template.outputFields = resultRepresentation.AllFields;

                var resultSelector         = stream.ResultSelector;
                var parameterSubstitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >(); // dont want the parameters substituted for at all
                var projectionResult       = SelectTransformer.Transform(resultSelector, parameterSubstitutions, resultRepresentation, true);
                if (projectionResult.Error)
                {
                    return(null);
                }
                template.finalResultSelector =
                    (key, aggregateResult) =>
                {
                    var parameters = new Dictionary <ParameterExpression, string>
                    {
                        { resultSelector.Parameters.ElementAt(0), key }
                    };
                    var sb = new System.Text.StringBuilder();
                    sb.AppendLine("{");
                    sb.AppendLine(string.Format("var {0} = {1};\n", resultSelector.Parameters.ElementAt(1).Name, aggregateResult));
                    foreach (var kv in projectionResult.ComputedFields)
                    {
                        var f = kv.Key;
                        var e = kv.Value;
                        sb.AppendFormat("this.batch.{0}.col[_c] = {1};\n", f.Name, e.ExpressionToCSharpStringWithParameterSubstitution(parameters));
                    }
                    sb.AppendLine("}");
                    return(sb.ToString());
                };
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(resultSelector));

                template.staticCtor = Transformer.StaticCtor(template.className);
                expandedCode        = template.TransformText();

                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(typeof(Empty), typeof(TKey), typeof(TInput), typeof(TState), typeof(TOutput), typeof(FastDictionaryGenerator3)));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <Empty, TInput>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <Empty, TResult>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <Empty, TResult>());

                var assembly = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var t        = assembly.GetType(template.className);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = typeof(TKey).GetAnonymousTypes();
                    list.AddRange(typeof(TInput).GetAnonymousTypes());
                    list.AddRange(typeof(TState).GetAnonymousTypes());
                    list.AddRange(typeof(TOutput).GetAnonymousTypes());
                    return(Tuple.Create(t.MakeGenericType(list.ToArray()), errorMessages));
                }
                else
                {
                    return(Tuple.Create(t, errorMessages));
                }
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
Пример #4
0
        public static Tuple <Type, string> Generate <TOuterKey, TSource, TInnerKey>(
            Expression <Func <TSource, TInnerKey> > keySelector,
            string inlinedHashCodeComputation,
            bool nested,
            bool powerOf2)
        {
            string errorMessages = null;

            try
            {
                var typeOfTOuterKey    = typeof(TOuterKey);
                var typeOfTSource      = typeof(TSource);
                var typeOfTInnerKey    = typeof(TInnerKey);
                var generatedClassName = string.Format(CultureInfo.InvariantCulture, "ShuffleStreamablePipeGeneratedFrom_{0}_{1}_{2}_{3}", typeOfTOuterKey.GetValidIdentifier(), typeOfTSource.GetValidIdentifier(), typeOfTInnerKey.GetValidIdentifier(), shuffleCounter++);

                var inputMessageRepresentation = new ColumnarRepresentation(typeOfTSource);

                var template = new ShuffleTemplate(
                    generatedClassName,
                    typeOfTOuterKey,
                    typeOfTSource,
                    typeOfTInnerKey,
                    inlinedHashCodeComputation,
                    nested, powerOf2)
                {
                    fields = inputMessageRepresentation.AllFields
                };

                var innerKeyIsAnonymous = typeOfTInnerKey.IsAnonymousTypeName();

                if (keySelector != null)
                {
                    var transformedKeySelector     = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector);
                    var keySelectorAsNewExpression = keySelector.Body as NewExpression;
                    if (innerKeyIsAnonymous && keySelectorAsNewExpression != null)
                    {
                        var newPrime = (NewExpression)transformedKeySelector.Body;
                        template.transformedKeySelectorAsString = string.Format(CultureInfo.InvariantCulture, "({0})Activator.CreateInstance(typeof({0}), {1})",
                                                                                template.TInnerKey,
                                                                                string.Join(",", newPrime.Arguments.Select(m => m.ExpressionToCSharp())));
                    }
                    else
                    {
                        template.transformedKeySelectorAsString = transformedKeySelector.Body.ExpressionToCSharp();
                        if (Config.UseMultiString &&
                            typeOfTInnerKey.Equals(typeof(string)) &&
                            keySelector.IsSimpleFieldOrPropertyAccess())
                        {
                            template.inlinedHashCodeComputation = "hashCodeVector.col[i]";
                            var fieldName = ((MemberExpression)(keySelector.Body)).Member.Name;
                            template.vectorHashCodeInitialization = string.Format(CultureInfo.InvariantCulture, "var hashCodeVector = {0}{1}_col.GetHashCode(batch.bitvector);", Transformer.ColumnFieldPrefix, fieldName);
                        }
                    }
                }
                else
                {
                    template.transformedKeySelectorAsString = string.Empty;
                }

                template.innerKeyIsAnonymous = innerKeyIsAnonymous;
                template.staticCtor          = Transformer.StaticCtor(template.CLASSNAME);
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey);
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TOuterKey, TSource>());
                if (nested)
                {
                    assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>());
                    assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>());
                }
                else
                {
                    assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TInnerKey, TSource>());
                    assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TInnerKey, TSource>());
                }
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keySelector));

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                if (typeOfTInnerKey.IsAnonymousTypeName())
                {
                    if (errorMessages == null)
                    {
                        errorMessages = string.Empty;
                    }
                    errorMessages += "\nCodegen Warning: The inner key type for Shuffle is anonymous, causing the use of Activator.CreateInstance in an inner loop. This will lead to poor performance.\n";
                }

                generatedClassName = generatedClassName.AddNumberOfNecessaryGenericArguments(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey);
                var t = a.GetType(generatedClassName);
                return(Tuple.Create(t.InstantiateAsNecessary(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey), errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }