Merge branch 'master' of http://github.com/mono/mono
[mono.git] / mcs / mcs / linq.cs
index 5d193d51418afce413e47460fdef251f8fac078e..8578323eb8fc0d8a2d13d46bf7dd3c5e78464798 100644 (file)
 
 using System;
 using System.Reflection;
-using System.Collections;
+using System.Collections.Generic;
 
 namespace Mono.CSharp.Linq
 {
-       // NOTES:
-       // Expression should be IExpression to save some memory and make a few things
-       // easier to read
-       //
-       //
-
-       class QueryExpression : AQueryClause
+       public class QueryExpression : AQueryClause
        {
-               public QueryExpression (Block block, AQueryClause query)
-                       : base (null, null, query.Location)
+               public QueryExpression (AQueryClause start)
+                       : base (null, null, Location.Null)
                {
-                       this.next = query;
+                       this.next = start;
                }
 
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide)
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parentParameter)
                {
-                       return next.BuildQueryClause (ec, lSide);
+                       return next.BuildQueryClause (ec, lSide, parentParameter);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        int counter = QueryBlock.TransparentParameter.Counter;
 
-                       Expression e = BuildQueryClause (ec, null);
-                       e = e.Resolve (ec);
+                       Expression e = BuildQueryClause (ec, null, null);
+                       if (e != null)
+                               e = e.Resolve (ec);
 
                        //
                        // Reset counter in probing mode to ensure that all transparent
@@ -55,9 +50,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       abstract class AQueryClause : Expression
+       public abstract class AQueryClause : ShimExpression
        {
-               class QueryExpressionAccess : MemberAccess
+               protected class QueryExpressionAccess : MemberAccess
                {
                        public QueryExpressionAccess (Expression expr, string methodName, Location loc)
                                : base (expr, methodName, loc)
@@ -69,141 +64,146 @@ namespace Mono.CSharp.Linq
                        {
                        }
 
-                       protected override Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
-                               Type queried_type, string name, string class_name, MemberTypes mt, BindingFlags bf)
+                       protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
                        {
-                               Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " +
+                               ec.Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " +
                                        "Are you missing `System.Linq' using directive or `System.Core.dll' assembly reference?",
                                        name);
-                               return null;
                        }
                }
 
-               class QueryExpressionInvocation : Invocation, MethodGroupExpr.IErrorHandler
+               protected class QueryExpressionInvocation : Invocation, OverloadResolver.IErrorHandler
                {
                        public QueryExpressionInvocation (QueryExpressionAccess expr, Arguments arguments)
                                : base (expr, arguments)
                        {
                        }
 
-                       protected override MethodGroupExpr DoResolveOverload (EmitContext ec)
+                       protected override MethodGroupExpr DoResolveOverload (ResolveContext ec)
                        {
-                               mg.CustomErrorHandler = this;
-                               MethodGroupExpr rmg = mg.OverloadResolve (ec, ref Arguments, false, loc);
+                               MethodGroupExpr rmg = mg.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.None);
                                return rmg;
                        }
 
-                       public bool AmbiguousCall (MethodBase ambiguous)
+                       #region IErrorHandler Members
+
+                       bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
                        {
-                               Report.SymbolRelatedToPreviousError ((MethodInfo) mg);
-                               Report.SymbolRelatedToPreviousError (ambiguous);
-                               Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'",
-                                       mg.Name, mg.InstanceExpression.GetSignatureForError ());
+                               ec.Report.SymbolRelatedToPreviousError (best);
+                               ec.Report.SymbolRelatedToPreviousError (ambiguous);
+                               ec.Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'",
+                                       best.Name, mg.InstanceExpression.GetSignatureForError ());
                                return true;
                        }
 
-                       public bool NoExactMatch (EmitContext ec, MethodBase method)
+                       bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
+                       {
+                               return false;
+                       }
+
+                       bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
                        {
-                               AParametersCollection pd = TypeManager.GetParameterData (method);
-                               Type source_type = pd.ExtensionMethodType;
+                               return false;
+                       }
+
+                       bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
+                       {
+                               var ms = (MethodSpec) best;
+                               TypeSpec source_type = ms.Parameters.ExtensionMethodType;
                                if (source_type != null) {
-                                       Argument a = Arguments [0];
+                                       Argument a = arguments[0];
 
                                        if (TypeManager.IsGenericType (source_type) && TypeManager.ContainsGenericParameters (source_type)) {
-#if GMCS_SOURCE
-                                               TypeInferenceContext tic = new TypeInferenceContext (TypeManager.GetTypeArguments (source_type));
-                                               tic.OutputTypeInference (ec, a.Expr, source_type);
-                                               if (tic.FixAllTypes ()) {
-                                                       source_type = TypeManager.DropGenericTypeArguments (source_type).MakeGenericType (tic.InferredTypeArguments);
+                                               TypeInferenceContext tic = new TypeInferenceContext (source_type.TypeArguments);
+                                               tic.OutputTypeInference (rc, a.Expr, source_type);
+                                               if (tic.FixAllTypes (rc)) {
+                                                       source_type = source_type.GetDefinition ().MakeGenericType (tic.InferredTypeArguments);
                                                }
-#else
-                                               throw new NotSupportedException ();
-#endif
                                        }
 
-                                       if (!Convert.ImplicitConversionExists (ec, a.Expr, source_type)) {
-                                               Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
-                                                       mg.Name, TypeManager.CSharpName (a.Type));
+                                       if (!Convert.ImplicitConversionExists (rc, a.Expr, source_type)) {
+                                               rc.Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
+                                                       best.Name, TypeManager.CSharpName (a.Type));
                                                return true;
                                        }
                                }
 
-                               if (!TypeManager.IsGenericMethod (method))
-                                       return false;
-
-                               if (mg.Name == "SelectMany") {
-                                       Report.Error (1943, loc,
+                               if (best.Name == "SelectMany") {
+                                       rc.Report.Error (1943, loc,
                                                "An expression type is incorrect in a subsequent `from' clause in a query expression with source type `{0}'",
-                                               Arguments [0].GetSignatureForError ());
+                                               arguments[0].GetSignatureForError ());
                                } else {
-                                       Report.Error (1942, loc,
+                                       rc.Report.Error (1942, loc,
                                                "An expression type in `{0}' clause is incorrect. Type inference failed in the call to `{1}'",
-                                               mg.Name.ToLower (), mg.Name);
+                                               best.Name.ToLowerInvariant (), best.Name);
                                }
 
                                return true;
                        }
+
+                       #endregion
                }
 
-               // TODO: protected
                public AQueryClause next;
-               public Expression expr;
-               protected ToplevelBlock block;
+               public QueryBlock block;
 
-               protected AQueryClause (ToplevelBlock block, Expression expr, Location loc)
+               protected AQueryClause (QueryBlock block, Expression expr, Location loc)
+                        : base (expr)
                {
                        this.block = block;
-                       this.expr = expr;
                        this.loc = loc;
                }
                
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
+                       base.CloneTo (clonectx, target);
+
                        AQueryClause t = (AQueryClause) target;
-                       if (expr != null)
-                               t.expr = expr.Clone (clonectx);
 
                        if (block != null)
-                               t.block = (ToplevelBlock) block.Clone (clonectx);
+                               t.block = (QueryBlock) clonectx.LookupBlock (block);
 
                        if (next != null)
                                t.next = (AQueryClause) next.Clone (clonectx);
                }
 
-               public override Expression CreateExpressionTree (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       // Should not be reached
-                       throw new NotSupportedException ("ET");
+                       return expr.Resolve (ec);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               public virtual Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
                {
-                       return expr.DoResolve (ec);
-               }
-
-               public virtual Expression BuildQueryClause (EmitContext ec, Expression lSide)
-               {
-                       Arguments args;
-                       CreateArguments (ec, out args);
+                       Arguments args = null;
+                       CreateArguments (ec, parameter, ref args);
                        lSide = CreateQueryExpression (lSide, args);
                        if (next != null) {
+                               parameter = CreateChildrenParameters (parameter);
+
                                Select s = next as Select;
-                               if (s == null || s.IsRequired)
-                                       return next.BuildQueryClause (ec, lSide);
+                               if (s == null || s.IsRequired (parameter))
+                                       return next.BuildQueryClause (ec, lSide, parameter);
                                        
                                // Skip transparent select clause if any clause follows
                                if (next.next != null)
-                                       return next.next.BuildQueryClause (ec, lSide);
+                                       return next.next.BuildQueryClause (ec, lSide, parameter);
                        }
 
                        return lSide;
                }
 
-               protected virtual void CreateArguments (EmitContext ec, out Arguments args)
+               protected virtual Parameter CreateChildrenParameters (Parameter parameter)
+               {
+                       return parameter;
+               }
+
+               protected virtual void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
                        args = new Arguments (2);
 
                        LambdaExpression selector = new LambdaExpression (loc);
+
+                       block.SetParameter (parameter.Clone ());
                        selector.Block = block;
                        selector.Block.AddStatement (new ContextualReturn (expr));
 
@@ -216,25 +216,9 @@ namespace Mono.CSharp.Linq
                                new QueryExpressionAccess (lSide, MethodName, loc), arguments);
                }
 
-               protected Invocation CreateQueryExpression (Expression lSide, TypeArguments typeArguments, Arguments arguments)
-               {
-                       return new QueryExpressionInvocation (
-                               new QueryExpressionAccess (lSide, MethodName, typeArguments, loc), arguments);
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       throw new NotSupportedException ();
-               }
-
                protected abstract string MethodName { get; }
 
-               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
-               {
-                       // Nothing to mutate
-               }
-
-               public virtual AQueryClause Next {
+               public AQueryClause Next {
                        set {
                                next = value;
                        }
@@ -250,90 +234,106 @@ namespace Mono.CSharp.Linq
        //
        // A query clause with an identifier (range variable)
        //
-       abstract class ARangeVariableQueryClause : AQueryClause
+       public abstract class ARangeVariableQueryClause : AQueryClause
        {
                sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter
                {
-                       public RangeAnonymousTypeParameter (Expression initializer, LocatedToken parameter)
+                       public RangeAnonymousTypeParameter (Expression initializer, SimpleMemberName parameter)
                                : base (initializer, parameter.Value, parameter.Location)
                        {
                        }
 
-                       protected override void Error_InvalidInitializer (string initializer)
+                       protected override void Error_InvalidInitializer (ResolveContext ec, string initializer)
                        {
-                               Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
+                               ec.Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
                                        Name, initializer);
                        }
                }
 
-               protected ARangeVariableQueryClause (ToplevelBlock block, Expression expr)
-                       : base (block, expr, expr.Location)
-               {
-               }
+               protected SimpleMemberName range_variable;
 
-               protected static Expression CreateRangeVariableType (ToplevelBlock block, TypeContainer container, LocatedToken name, Expression init)
+               protected ARangeVariableQueryClause (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+                       : base (block, expr, loc)
                {
-                       ArrayList args = new ArrayList (2);
-                       args.Add (new AnonymousTypeParameter (block.Parameters [0]));
-                       args.Add (new RangeAnonymousTypeParameter (init, name));
-                       return new AnonymousTypeDeclaration (args, container, name.Location);
+                       range_variable = identifier;
                }
-       }
 
-       class QueryStartClause : AQueryClause
-       {
-               public QueryStartClause (Expression expr)
-                       : base (null, expr, expr.Location)
+               public FullNamedExpression IdentifierType { get; set; }
+
+               protected Invocation CreateCastExpression (Expression lSide)
                {
+                       return new QueryExpressionInvocation (
+                               new QueryExpressionAccess (lSide, "Cast", new TypeArguments (IdentifierType), loc), null);
                }
 
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide)
+               protected override Parameter CreateChildrenParameters (Parameter parameter)
                {
-                       return next.BuildQueryClause (ec, expr);
+                       return new QueryBlock.TransparentParameter (parameter, GetIntoVariable ());
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, SimpleMemberName name, Expression init)
                {
-                       Expression e = BuildQueryClause (ec, null);
-                       return e.Resolve (ec);
+                       var args = new List<AnonymousTypeParameter> (2);
+                       args.Add (new AnonymousTypeParameter (parameter));
+                       args.Add (new RangeAnonymousTypeParameter (init, name));
+                       return new NewAnonymousType (args, rc.MemberContext.CurrentMemberDefinition.Parent, name.Location);
                }
 
-               protected override string MethodName {
-                       get { throw new NotSupportedException (); }
+               protected virtual SimpleMemberName GetIntoVariable ()
+               {
+                       return range_variable;
                }
        }
 
-       class Cast : QueryStartClause
+       class QueryStartClause : ARangeVariableQueryClause
        {
-               // We don't have to clone cast type
-               readonly FullNamedExpression type_expr;
-
-               public Cast (FullNamedExpression type, Expression expr)
-                       : base (expr)
+               public QueryStartClause (QueryBlock block, Expression expr, SimpleMemberName identifier, Location loc)
+                       : base (block, identifier, expr, loc)
                {
-                       this.type_expr = type;
+                       block.AddRangeVariable (identifier);
                }
-               
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide)
+
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
                {
-                       lSide = CreateQueryExpression (expr, new TypeArguments (type_expr), null);
-                       if (next != null)
-                               return next.BuildQueryClause (ec, lSide);
+/*
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return null;
 
-                       return lSide;
+                       if (expr.Type == InternalType.Dynamic || expr.Type == TypeManager.void_type) {
+                               ec.Report.Error (1979, expr.Location,
+                                       "Query expression with a source or join sequence of type `{0}' is not allowed",
+                                       TypeManager.CSharpName (expr.Type));
+                               return null;
+                       }
+*/
+
+                       if (IdentifierType != null)
+                               expr = CreateCastExpression (expr);
+
+                       if (parameter == null)
+                               lSide = expr;
+
+                       return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (range_variable.Value, range_variable.Location));
+               }
+
+               protected override Expression DoResolve (ResolveContext ec)
+               {
+                       Expression e = BuildQueryClause (ec, null, null);
+                       return e.Resolve (ec);
                }
 
                protected override string MethodName {
-                       get { return "Cast"; }
+                       get { throw new NotSupportedException (); }
                }
        }
 
-       class GroupBy : AQueryClause
+       public class GroupBy : AQueryClause
        {
                Expression element_selector;
-               ToplevelBlock element_block;
-               
-               public GroupBy (ToplevelBlock block, Expression elementSelector, ToplevelBlock elementBlock, Expression keySelector, Location loc)
+               QueryBlock element_block;
+
+               public GroupBy (QueryBlock block, Expression elementSelector, QueryBlock elementBlock, Expression keySelector, Location loc)
                        : base (block, keySelector, loc)
                {
                        //
@@ -345,12 +345,14 @@ namespace Mono.CSharp.Linq
                        }
                }
 
-               protected override void CreateArguments (EmitContext ec, out Arguments args)
+               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
-                       base.CreateArguments (ec, out args);
+                       base.CreateArguments (ec, parameter, ref args);
 
                        if (element_selector != null) {
                                LambdaExpression lambda = new LambdaExpression (element_selector.Location);
+
+                               element_block.SetParameter (parameter.Clone ());
                                lambda.Block = element_block;
                                lambda.Block.AddStatement (new ContextualReturn (element_selector));
                                args.Add (new Argument (lambda));
@@ -362,7 +364,7 @@ namespace Mono.CSharp.Linq
                        GroupBy t = (GroupBy) target;
                        if (element_selector != null) {
                                t.element_selector = element_selector.Clone (clonectx);
-                               t.element_block = (ToplevelBlock) element_block.Clone (clonectx);
+                               t.element_block = (QueryBlock) element_block.Clone (clonectx);
                        }
 
                        base.CloneTo (clonectx, t);
@@ -373,63 +375,44 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class Join : ARangeVariableQueryClause
+       public class Join : SelectMany
        {
-               readonly LocatedToken lt;
-               ToplevelBlock inner_selector, outer_selector;
+               QueryBlock inner_selector, outer_selector;
 
-               public Join (ToplevelBlock block, LocatedToken lt, Expression inner, ToplevelBlock outerSelector, ToplevelBlock innerSelector, Location loc)
-                       : base (block, inner)
+               public Join (QueryBlock block, SimpleMemberName lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc)
+                       : base (block, lt, inner, loc)
                {
-                       this.lt = lt;
                        this.outer_selector = outerSelector;
                        this.inner_selector = innerSelector;
                }
 
-               protected override void CreateArguments (EmitContext ec, out Arguments args)
+               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
                        args = new Arguments (4);
 
+                       if (IdentifierType != null)
+                               expr = CreateCastExpression (expr);
+
                        args.Add (new Argument (expr));
 
-                       LambdaExpression lambda = new LambdaExpression (outer_selector.StartLocation);
+                       outer_selector.SetParameter (parameter.Clone ());
+                       var lambda = new LambdaExpression (outer_selector.StartLocation);
                        lambda.Block = outer_selector;
                        args.Add (new Argument (lambda));
 
+                       inner_selector.SetParameter (new ImplicitLambdaParameter (range_variable.Value, range_variable.Location));
                        lambda = new LambdaExpression (inner_selector.StartLocation);
                        lambda.Block = inner_selector;
                        args.Add (new Argument (lambda));
 
-                       Expression result_selector_expr;
-                       LocatedToken into_variable = GetIntoVariable ();
-                       //
-                       // When select follows use is as result selector
-                       //
-                       if (next is Select) {
-                               result_selector_expr = next.expr;
-                               next = next.next;
-                       } else {
-                               result_selector_expr = CreateRangeVariableType (block, (TypeContainer) ec.TypeContainer, into_variable,
-                                       new SimpleName (into_variable.Value, into_variable.Location));
-                       }
-
-                       LambdaExpression result_selector = new LambdaExpression (lt.Location);
-                       result_selector.Block = new QueryBlock (block.Parent, block.Parameters, into_variable, block.StartLocation);
-                       result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr));
-
-                       args.Add (new Argument (result_selector));
-               }
-
-               protected virtual LocatedToken GetIntoVariable ()
-               {
-                       return lt;
+                       base.CreateArguments (ec, parameter, ref args);
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        Join t = (Join) target;
-                       t.inner_selector = (ToplevelBlock) inner_selector.Clone (clonectx);
-                       t.outer_selector = (ToplevelBlock) outer_selector.Clone (clonectx);
+                       t.inner_selector = (QueryBlock) inner_selector.Clone (clonectx);
+                       t.outer_selector = (QueryBlock) outer_selector.Clone (clonectx);
                        base.CloneTo (clonectx, t);
                }       
 
@@ -438,18 +421,18 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class GroupJoin : Join
+       public class GroupJoin : Join
        {
-               readonly LocatedToken into;
+               readonly SimpleMemberName into;
 
-               public GroupJoin (ToplevelBlock block, LocatedToken lt, Expression inner,
-                       ToplevelBlock outerSelector, ToplevelBlock innerSelector, LocatedToken into, Location loc)
+               public GroupJoin (QueryBlock block, SimpleMemberName lt, Expression inner,
+                       QueryBlock outerSelector, QueryBlock innerSelector, SimpleMemberName into, Location loc)
                        : base (block, lt, inner, outerSelector, innerSelector, loc)
                {
                        this.into = into;
                }
 
-               protected override LocatedToken GetIntoVariable ()
+               protected override SimpleMemberName GetIntoVariable ()
                {
                        return into;
                }
@@ -459,11 +442,17 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class Let : ARangeVariableQueryClause
+       public class Let : ARangeVariableQueryClause
        {
-               public Let (ToplevelBlock block, TypeContainer container, LocatedToken identifier, Expression expr)
-                       : base (block, CreateRangeVariableType (block, container, identifier, expr))
+               public Let (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+                       : base (block, identifier, expr, loc)
+               {
+               }
+
+               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
+                       expr = CreateRangeVariableType (ec, parameter, range_variable, expr);
+                       base.CreateArguments (ec, parameter, ref args);
                }
 
                protected override string MethodName {
@@ -471,9 +460,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class Select : AQueryClause
+       public class Select : AQueryClause
        {
-               public Select (ToplevelBlock block, Expression expr, Location loc)
+               public Select (QueryBlock block, Expression expr, Location loc)
                        : base (block, expr, loc)
                {
                }
@@ -482,14 +471,13 @@ namespace Mono.CSharp.Linq
                // For queries like `from a orderby a select a'
                // the projection is transparent and select clause can be safely removed 
                //
-               public bool IsRequired {
-                       get {
-                               SimpleName sn = expr as SimpleName;
-                               if (sn == null)
-                                       return true;
+               public bool IsRequired (Parameter parameter)
+               {
+                       SimpleName sn = expr as SimpleName;
+                       if (sn == null)
+                               return true;
 
-                               return sn.Name != block.Parameters.FixedParameters [0].Name;
-                       }
+                       return sn.Name != parameter.Name;
                }
 
                protected override string MethodName {
@@ -497,33 +485,47 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class SelectMany : ARangeVariableQueryClause
+       public class SelectMany : ARangeVariableQueryClause
        {
-               LocatedToken lt;
-
-               public SelectMany (ToplevelBlock block, LocatedToken lt, Expression expr)
-                       : base (block, expr)
+               public SelectMany (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+                       : base (block, identifier, expr, loc)
                {
-                       this.lt = lt;
                }
 
-               protected override void CreateArguments (EmitContext ec, out Arguments args)
+               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
-                       base.CreateArguments (ec, out args);
+                       if (args == null) {
+                               if (IdentifierType != null)
+                                       expr = CreateCastExpression (expr);
+
+                               base.CreateArguments (ec, parameter, ref args);
+                       }
 
                        Expression result_selector_expr;
+                       QueryBlock result_block;
+
+                       var target = GetIntoVariable ();
+                       var target_param = new ImplicitLambdaParameter (target.Value, target.Location);
+
                        //
-                       // When select follow use is as result selector
+                       // When select follows use it as a result selector
                        //
                        if (next is Select) {
-                               result_selector_expr = next.expr;
+                               result_selector_expr = next.Expr;
+
+                               result_block = next.block;
+                               result_block.SetParameters (parameter, target_param);
+
                                next = next.next;
                        } else {
-                               result_selector_expr = CreateRangeVariableType (block, (TypeContainer)ec.TypeContainer, lt, new SimpleName (lt.Value, lt.Location));
+                               result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Value, target.Location));
+
+                               result_block = new QueryBlock (ec.Compiler, block.Parent, block.StartLocation);
+                               result_block.SetParameters (parameter, target_param);
                        }
 
-                       LambdaExpression result_selector = new LambdaExpression (lt.Location);
-                       result_selector.Block = new QueryBlock (block.Parent, block.Parameters, lt, block.StartLocation);
+                       LambdaExpression result_selector = new LambdaExpression (Location);
+                       result_selector.Block = result_block;
                        result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr));
 
                        args.Add (new Argument (result_selector));
@@ -534,9 +536,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class Where : AQueryClause
+       public class Where : AQueryClause
        {
-               public Where (ToplevelBlock block, Expression expr, Location loc)
+               public Where (QueryBlock block, BooleanExpression expr, Location loc)
                        : base (block, expr, loc)
                {
                }
@@ -544,11 +546,16 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "Where"; }
                }
+
+               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
+               {
+                       base.CreateArguments (ec, parameter, ref args);
+               }
        }
 
-       class OrderByAscending : AQueryClause
+       public class OrderByAscending : AQueryClause
        {
-               public OrderByAscending (ToplevelBlock block,Expression expr)
+               public OrderByAscending (QueryBlock block, Expression expr)
                        : base (block, expr, expr.Location)
                {
                }
@@ -558,9 +565,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class OrderByDescending : AQueryClause
+       public class OrderByDescending : AQueryClause
        {
-               public OrderByDescending (ToplevelBlock block, Expression expr)
+               public OrderByDescending (QueryBlock block, Expression expr)
                        : base (block, expr, expr.Location)
                {
                }
@@ -570,9 +577,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class ThenByAscending : OrderByAscending
+       public class ThenByAscending : OrderByAscending
        {
-               public ThenByAscending (ToplevelBlock block, Expression expr)
+               public ThenByAscending (QueryBlock block, Expression expr)
                        : base (block, expr)
                {
                }
@@ -582,9 +589,9 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class ThenByDescending : OrderByDescending
+       public class ThenByDescending : OrderByDescending
        {
-               public ThenByDescending (ToplevelBlock block, Expression expr)
+               public ThenByDescending (QueryBlock block, Expression expr)
                        : base (block, expr)
                {
                }
@@ -597,7 +604,7 @@ namespace Mono.CSharp.Linq
        //
        // Implicit query block
        //
-       class QueryBlock : ToplevelBlock
+       public class QueryBlock : ToplevelBlock
        {
                //
                // Transparent parameters are used to package up the intermediate results
@@ -608,57 +615,52 @@ namespace Mono.CSharp.Linq
                        public static int Counter;
                        const string ParameterNamePrefix = "<>__TranspIdent";
 
-                       public readonly ParametersCompiled Parent;
+                       public readonly Parameter Parent;
                        public readonly string Identifier;
 
-                       public TransparentParameter (ParametersCompiled parent, LocatedToken identifier)
+                       public TransparentParameter (Parameter parent, SimpleMemberName identifier)
                                : base (ParameterNamePrefix + Counter++, identifier.Location)
                        {
                                Parent = parent;
                                Identifier = identifier.Value;
                        }
 
-                       public static void Reset ()
+                       public new static void Reset ()
                        {
                                Counter = 0;
                        }
                }
 
-               public sealed class ImplicitQueryParameter : ImplicitLambdaParameter
+               sealed class RangeVariable : IKnownVariable
                {
-                       public ImplicitQueryParameter (string name, Location loc)
-                               : base (name, loc)
+                       public RangeVariable (QueryBlock block, Location loc)
                        {
+                               Block = block;
+                               Location = loc;
                        }
-               }
 
-               public QueryBlock (Block parent, LocatedToken lt, Location start)
-                       : base (parent, new ParametersCompiled (new ImplicitQueryParameter (lt.Value, lt.Location)), start)
-               {
-                       if (parent != null)
-                               base.CheckParentConflictName (parent.Toplevel, lt.Value, lt.Location);
-               }
+                       public Block Block { get; private set; }
 
-               public QueryBlock (Block parent, ParametersCompiled parameters, LocatedToken lt, Location start)
-                       : base (parent, new ParametersCompiled (parameters [0].Clone (), new ImplicitQueryParameter (lt.Value, lt.Location)), start)
-               {
+                       public Location Location { get; private set; }
                }
 
-               public QueryBlock (Block parent, Location start)
-                       : base (parent, parent.Toplevel.Parameters.Clone (), start)
+               List<SimpleMemberName> range_variables;
+
+               public QueryBlock (CompilerContext ctx, Block parent, Location start)
+                       : base (ctx, parent, ParametersCompiled.EmptyReadOnlyParameters, start)
                {
                }
 
-               public void AddTransparentParameter (LocatedToken name)
+               public void AddRangeVariable (SimpleMemberName name)
                {
-                       base.CheckParentConflictName (this, name.Value, name.Location);
+                       if (!CheckParentConflictName (this, name.Value, name.Location))
+                               return;
 
-                       parameters = new ParametersCompiled (new TransparentParameter (parameters, name));
-               }
+                       if (range_variables == null)
+                               range_variables = new List<SimpleMemberName> ();
 
-               protected override bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
-               {
-                       return true;
+                       range_variables.Add (name);
+                       AddKnownVariable (name.Value, new RangeVariable (this, name.Location));
                }
 
                // 
@@ -675,11 +677,9 @@ namespace Mono.CSharp.Linq
                                if (tp.Identifier == name)
                                        break;
 
-                               TransparentParameter tp_next = tp.Parent [0] as TransparentParameter;
-                               if (tp_next == null) {
-                                       if (tp.Parent.GetParameterIndexByName (name) >= 0)
-                                               break;
-                               }
+                               TransparentParameter tp_next = tp.Parent as TransparentParameter;
+                               if (tp_next == null && tp.Parent.Name == name)
+                                       break;
 
                                tp = tp_next;
                        }
@@ -688,16 +688,21 @@ namespace Mono.CSharp.Linq
                                expr = new SimpleName (parameters[0].Name, loc);
                                TransparentParameter tp_cursor = (TransparentParameter) parameters[0];
                                while (tp_cursor != tp) {
-                                       tp_cursor = (TransparentParameter) tp_cursor.Parent[0];
-                                       expr = new MemberAccess (expr, tp_cursor.Name);
+                                       tp_cursor = (TransparentParameter) tp_cursor.Parent;
+                                       expr = new TransparentMemberAccess (expr, tp_cursor.Name);
                                }
 
-                               return new MemberAccess (expr, name);
+                               return new TransparentMemberAccess (expr, name);
                        }
 
                        return null;
                }
 
+               protected override bool HasParameterWithName (string name)
+               {
+                       return range_variables != null && range_variables.Exists (l => l.Value == name);
+               }
+
                protected override void Error_AlreadyDeclared (Location loc, string var, string reason)
                {
                        Report.Error (1931, loc, "A range variable `{0}' conflicts with a previous declaration of `{0}'",
@@ -715,5 +720,30 @@ namespace Mono.CSharp.Linq
                        Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
                                name);
                }
+
+               public void SetParameter (Parameter parameter)
+               {
+                       base.parameters = new ParametersCompiled (null, parameter);
+                       base.parameter_info = new ToplevelParameterInfo [] {
+                               new ToplevelParameterInfo (this, 0)
+                       };
+               }
+
+               public void SetParameters (Parameter first, Parameter second)
+               {
+                       base.parameters = new ParametersCompiled (null, first, second);
+                       base.parameter_info = new ToplevelParameterInfo[] {
+                               new ToplevelParameterInfo (this, 0),
+                               new ToplevelParameterInfo (this, 1)
+                       };
+               }
+       }
+
+       sealed class TransparentMemberAccess : MemberAccess
+       {
+               public TransparentMemberAccess (Expression expr, string name)
+                       : base (expr, name)
+               {
+               }
        }
 }