New tests.
[mono.git] / mcs / mcs / linq.cs
index 079786a7429f23030ad502700c6fdf92b76d667e..420dae4bf832e7c4fcc18125e7c51c3f31bb855b 100644 (file)
@@ -3,14 +3,14 @@
 //
 // Authors: Marek Safar (marek.safar@gmail.com)
 //
-// Licensed under the terms of the GNU GPL
+// Dual licensed under the terms of the MIT X11 or GNU GPL
 //
-// (C) 2007 Novell, Inc
+// Copyright 2007-2008 Novell, Inc
 //
 
 using System;
 using System.Reflection;
-using System.Collections;
+using System.Collections.Generic;
 
 namespace Mono.CSharp.Linq
 {
@@ -20,27 +20,34 @@ namespace Mono.CSharp.Linq
        //
        //
 
-       public class QueryExpression : AQueryClause
+       class QueryExpression : AQueryClause
        {
-               LocatedToken variable;
-
-               public QueryExpression (LocatedToken variable, AQueryClause query)
-                       : base (null, query.Location)
+               public QueryExpression (Block block, AQueryClause query)
+                       : base (null, null, query.Location)
                {
-                       this.variable = variable;
                        this.next = query;
                }
 
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide)
                {
-                       Parameter p = CreateBlockParameter (variable);
-                       return next.BuildQueryClause (ec, lSide, p, ti);
+                       return next.BuildQueryClause (ec, lSide);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       Expression e = BuildQueryClause (ec, null, null, null);
-                       e = e.Resolve (ec);
+                       int counter = QueryBlock.TransparentParameter.Counter;
+
+                       Expression e = BuildQueryClause (ec, null);
+                       if (e != null)
+                               e = e.Resolve (ec);
+
+                       //
+                       // Reset counter in probing mode to ensure that all transparent
+                       // identifier anonymous types are created only once
+                       //
+                       if (ec.IsInProbingMode)
+                               QueryBlock.TransparentParameter.Counter = counter;
+
                        return e;
                }
 
@@ -49,7 +56,7 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public abstract class AQueryClause : Expression
+       abstract class AQueryClause : ShimExpression
        {
                class QueryExpressionAccess : MemberAccess
                {
@@ -63,10 +70,10 @@ 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 Expression Error_MemberLookupFailed (ResolveContext ec, TypeSpec container_type, TypeSpec qualifier_type,
+                               TypeSpec queried_type, string name, int arity, string class_name, MemberKind mt, BindingRestriction bf)
                        {
-                               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;
@@ -75,146 +82,136 @@ namespace Mono.CSharp.Linq
 
                class QueryExpressionInvocation : Invocation, MethodGroupExpr.IErrorHandler
                {
-                       public QueryExpressionInvocation (QueryExpressionAccess expr, ArrayList arguments)
+                       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, false, loc);
                                return rmg;
                        }
 
-                       public bool NoExactMatch (EmitContext ec, MethodBase method)
+                       public bool AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
                        {
-#if GMCS_SOURCE                                
-                               ParameterData pd = TypeManager.GetParameterData (method);
-                               Type source_type = pd.ExtensionMethodType;
+                               ec.Report.SymbolRelatedToPreviousError (mg.BestCandidate);
+                               ec.Report.SymbolRelatedToPreviousError (ambiguous);
+                               ec.Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'",
+                                       mg.Name, mg.InstanceExpression.GetSignatureForError ());
+                               return true;
+                       }
+
+                       public bool NoExactMatch (ResolveContext ec, MethodSpec method)
+                       {
+                               var pd = method.Parameters;
+                               TypeSpec source_type = pd.ExtensionMethodType;
                                if (source_type != null) {
-                                       Argument a = (Argument) Arguments [0];
+                                       Argument a = arguments [0];
 
-                                       if (source_type.IsGenericType && source_type.ContainsGenericParameters) {
-                                               TypeInferenceContext tic = new TypeInferenceContext (source_type.GetGenericArguments ());
+                                       if (TypeManager.IsGenericType (source_type) && TypeManager.ContainsGenericParameters (source_type)) {
+                                               TypeInferenceContext tic = new TypeInferenceContext (source_type.TypeArguments);
                                                tic.OutputTypeInference (ec, a.Expr, source_type);
-                                               if (tic.FixAllTypes ()) {
-                                                       source_type = source_type.GetGenericTypeDefinition ().MakeGenericType (tic.InferredTypeArguments);
+                                               if (tic.FixAllTypes (ec)) {
+                                                       source_type = source_type.GetDefinition ().MakeGenericType (tic.InferredTypeArguments);
                                                }
                                        }
 
                                        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",
+                                               ec.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));
                                                return true;
                                        }
                                }
 
-                               if (!method.IsGenericMethod)
+                               if (!method.IsGeneric)
                                        return false;
 
-                               Report.Error (1942, loc, "Type inference failed to infer type argument for `{0}' clause. " +
-                                       "Try specifying the type argument explicitly",
-                                       mg.Name.ToLower ());
+                               if (mg.Name == "SelectMany") {
+                                       ec.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 ());
+                               } else {
+                                       ec.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);
+                               }
+
                                return true;
-#else
-                               return false;
-#endif
                        }
                }
 
+               // TODO: protected
                public AQueryClause next;
-               /*protected*/ public Expression expr;
+               protected ToplevelBlock block;
 
-               protected AQueryClause (Expression expr, Location loc)
+               protected AQueryClause (ToplevelBlock block, Expression expr, Location loc)
+                        : base (expr)
                {
-                       this.expr = expr;
+                       this.block = block;
                        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);
+
                        if (next != null)
-                               t.next = (AQueryClause)next.Clone (clonectx);
+                               t.next = (AQueryClause) next.Clone (clonectx);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       return expr.DoResolve (ec);
+                       return expr.Resolve (ec);
                }
 
-               public virtual Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+               public virtual Expression BuildQueryClause (ResolveContext ec, Expression lSide)
                {
-                       ArrayList args = new ArrayList (1);
-                       args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
+                       Arguments args;
+                       CreateArguments (ec, out args);
                        lSide = CreateQueryExpression (lSide, args);
                        if (next != null) {
                                Select s = next as Select;
-                               if (s == null || s.IsRequired (parameter))
-                                       return next.BuildQueryClause (ec, lSide, parameter, ti);
+                               if (s == null || s.IsRequired)
+                                       return next.BuildQueryClause (ec, lSide);
                                        
                                // Skip transparent select clause if any clause follows
                                if (next.next != null)
-                                       return next.next.BuildQueryClause (ec, lSide, parameter, ti);
+                                       return next.next.BuildQueryClause (ec, lSide);
                        }
 
                        return lSide;
                }
 
-               protected static Parameter CreateBlockParameter (LocatedToken li)
+               protected virtual void CreateArguments (ResolveContext ec, out Arguments args)
                {
-                       return new ImplicitQueryParameter (li);
+                       args = new Arguments (2);
+
+                       LambdaExpression selector = new LambdaExpression (loc);
+                       selector.Block = block;
+                       selector.Block.AddStatement (new ContextualReturn (expr));
+
+                       args.Add (new Argument (selector));
                }
 
-               protected Invocation CreateQueryExpression (Expression lSide, ArrayList arguments)
+               protected Invocation CreateQueryExpression (Expression lSide, Arguments arguments)
                {
                        return new QueryExpressionInvocation (
                                new QueryExpressionAccess (lSide, MethodName, loc), arguments);
                }
 
-               protected Invocation CreateQueryExpression (Expression lSide, TypeArguments typeArguments, ArrayList arguments)
+               protected Invocation CreateQueryExpression (Expression lSide, TypeArguments typeArguments, Arguments arguments)
                {
                        return new QueryExpressionInvocation (
                                new QueryExpressionAccess (lSide, MethodName, typeArguments, loc), arguments);
                }
 
-               protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter parameter, TransparentIdentifiersScope ti)
-               {
-                       return CreateSelectorArgument (ec, expr, new Parameter [] { parameter }, ti);
-               }
-
-               protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter[] parameters, TransparentIdentifiersScope ti)
-               {
-                       Parameters p = new Parameters (parameters);
-
-                       LambdaExpression selector = new LambdaExpression (
-                               null, null, (TypeContainer)ec.TypeContainer, p, ec.CurrentBlock, loc);
-                       selector.Block = new SelectorBlock (ec.CurrentBlock, p, ti, loc);
-                       selector.Block.AddStatement (new Return (expr, loc));
-
-                       if (!ec.IsInProbingMode) {
-                               selector.CreateAnonymousHelpers ();
-
-                               // TODO: I am not sure where this should be done to work
-                               // correctly with anonymous containerss and was called only once
-                               // FIXME: selector.RootScope == null for nested anonymous
-                               // methods only ?
-                               if (selector.RootScope != null)
-                                       selector.RootScope.DefineType ();
-                       }
-                       
-                       return new Argument (selector);
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       throw new NotSupportedException ();
-               }
-
                protected abstract string MethodName { get; }
 
                public virtual AQueryClause Next {
@@ -233,100 +230,62 @@ namespace Mono.CSharp.Linq
        //
        // A query clause with an identifier (range variable)
        //
-       public abstract class ARangeVariableQueryClause : AQueryClause
+       abstract class ARangeVariableQueryClause : AQueryClause
        {
-               LocatedToken variable;
-               protected Expression element_selector;
-
-               protected ARangeVariableQueryClause (LocatedToken variable, Expression expr, Location loc)
-                       : base (expr, loc)
-               {
-                       this.variable = variable;
-               }
-
-               protected virtual void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
-                       ref Parameter parameter, TransparentIdentifiersScope ti)
-               {
-                       args.Add (CreateSelectorArgument (ec, expr, parentParameter, ti));
-                       args.Add (CreateSelectorArgument (ec, element_selector,
-                               new Parameter [] { parentParameter, parameter }, ti));
-               }
-
-               //
-               // Customization for range variables which not only creates a lambda expression but
-               // also builds a chain of range varible pairs
-               //
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
+               sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter
                {
-                       Parameter parameter = CreateBlockParameter (variable);
-
-                       if (next != null) {
-                               //
-                               // Builds transparent identifiers, each identifier includes its parent
-                               // type at index 0, and new value at index 1. This is not valid for the
-                               // first one which includes two values directly.
-                               //
-                               ArrayList transp_args = new ArrayList (2);
-                               transp_args.Add (new AnonymousTypeParameter (parentParameter));
-                               transp_args.Add (CreateAnonymousTypeVariable (parameter));
-                               element_selector = new AnonymousTypeDeclaration (transp_args, (TypeContainer) ec.TypeContainer, loc);
+                       public RangeAnonymousTypeParameter (Expression initializer, SimpleMemberName parameter)
+                               : base (initializer, parameter.Value, parameter.Location)
+                       {
                        }
 
-                       ArrayList args = new ArrayList ();
-                       AddSelectorArguments (ec, args, parentParameter, ref parameter, ti);
-
-                       lSide = CreateQueryExpression (lSide, args);
-                       if (next != null) {
-                               //
-                               // Parameter identifiers go to the scope
-                               //
-                               string[] identifiers;
-                               if (ti == null) {
-                                       identifiers = new string [] { parentParameter.Name, parameter.Name };
-                               } else {
-                                       identifiers = new string [] { parameter.Name };
-                               }
-
-                               TransparentParameter tp = new TransparentParameter (loc);
-                               return next.BuildQueryClause (ec, lSide, tp,
-                                       new TransparentIdentifiersScope (ti, tp, identifiers));
+                       protected override void Error_InvalidInitializer (ResolveContext ec, string initializer)
+                       {
+                               ec.Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
+                                       Name, initializer);
                        }
-
-                       return lSide;
                }
-               
-               protected override void CloneTo (CloneContext clonectx, Expression target)
+
+               protected ARangeVariableQueryClause (ToplevelBlock block, Expression expr)
+                       : base (block, expr, expr.Location)
                {
-                       ARangeVariableQueryClause t = (ARangeVariableQueryClause) target;
-                       if (element_selector != null)
-                               t.element_selector = element_selector.Clone (clonectx);
-                       base.CloneTo (clonectx, t);
                }
-               
-               //
-               // For transparent identifiers, creates an instance of variable expression
-               //
-               protected virtual AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
+
+               protected static Expression CreateRangeVariableType (ToplevelBlock block, TypeContainer container, SimpleMemberName name, Expression init)
                {
-                       return new AnonymousTypeParameter (parameter);
+                       var args = new List<AnonymousTypeParameter> (2);
+                       args.Add (new AnonymousTypeParameter (block.Parameters [0]));
+                       args.Add (new RangeAnonymousTypeParameter (init, name));
+                       return new NewAnonymousType (args, container, name.Location);
                }
        }
 
-       public class QueryStartClause : AQueryClause
+       class QueryStartClause : AQueryClause
        {
                public QueryStartClause (Expression expr)
-                       : base (expr, expr.Location)
+                       : base (null, expr, expr.Location)
                {
                }
 
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide)
                {
-                       return next.BuildQueryClause (ec, expr, parameter, ti);
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return null;
+
+                       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;
+                       }
+
+                       return next.BuildQueryClause (ec, expr);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       Expression e = BuildQueryClause (ec, null, null, null);
+                       Expression e = BuildQueryClause (ec, null);
                        return e.Resolve (ec);
                }
 
@@ -335,22 +294,22 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class Cast : QueryStartClause
+       class Cast : QueryStartClause
        {
                // We don't have to clone cast type
-               readonly Expression type_expr;
+               readonly FullNamedExpression type_expr;
 
-               public Cast (Expression type, Expression expr)
+               public Cast (FullNamedExpression type, Expression expr)
                        : base (expr)
                {
                        this.type_expr = type;
                }
                
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide)
                {
-                       lSide = CreateQueryExpression (expr, new TypeArguments (loc, type_expr), null);
+                       lSide = CreateQueryExpression (expr, new TypeArguments (type_expr), null);
                        if (next != null)
-                               return next.BuildQueryClause (ec, lSide, parameter, ti);
+                               return next.BuildQueryClause (ec, lSide);
 
                        return lSide;
                }
@@ -360,36 +319,43 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class GroupBy : AQueryClause
+       class GroupBy : AQueryClause
        {
                Expression element_selector;
+               ToplevelBlock element_block;
                
-               public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
-                       : base (keySelector, loc)
+               public GroupBy (ToplevelBlock block, Expression elementSelector, ToplevelBlock elementBlock, Expression keySelector, Location loc)
+                       : base (block, keySelector, loc)
                {
-                       this.element_selector = elementSelector;
+                       //
+                       // Optimizes clauses like `group A by A'
+                       //
+                       if (!elementSelector.Equals (keySelector)) {
+                               this.element_selector = elementSelector;
+                               this.element_block = elementBlock;
+                       }
                }
 
-               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+               protected override void CreateArguments (ResolveContext ec, out Arguments args)
                {
-                       ArrayList args = new ArrayList (2);
-                       args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
-
-                       // A query can be optimized when selector is not group by specific
-                       if (!element_selector.Equals (lSide))
-                               args.Add (CreateSelectorArgument (ec, element_selector, parameter, ti));
-
-                       lSide = CreateQueryExpression (lSide, args);
-                       if (next != null)
-                               return next.BuildQueryClause (ec, lSide, parameter, ti);
+                       base.CreateArguments (ec, out args);
 
-                       return lSide;
+                       if (element_selector != null) {
+                               LambdaExpression lambda = new LambdaExpression (element_selector.Location);
+                               lambda.Block = element_block;
+                               lambda.Block.AddStatement (new ContextualReturn (element_selector));
+                               args.Add (new Argument (lambda));
+                       }
                }
-       
+
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        GroupBy t = (GroupBy) target;
-                       t.element_selector = element_selector.Clone (clonectx);
+                       if (element_selector != null) {
+                               t.element_selector = element_selector.Clone (clonectx);
+                               t.element_block = (ToplevelBlock) element_block.Clone (clonectx);
+                       }
+
                        base.CloneTo (clonectx, t);
                }
 
@@ -398,87 +364,85 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class Join : ARangeVariableQueryClause
+       class Join : ARangeVariableQueryClause
        {
-               Expression projection;
-               Expression inner_selector, outer_selector;
+               readonly SimpleMemberName lt;
+               ToplevelBlock inner_selector, outer_selector;
 
-               public Join (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector, Location loc)
-                       : base (variable, inner, loc)
+               public Join (ToplevelBlock block, SimpleMemberName lt, Expression inner, ToplevelBlock outerSelector, ToplevelBlock innerSelector, Location loc)
+                       : base (block, inner)
                {
+                       this.lt = lt;
                        this.outer_selector = outerSelector;
                        this.inner_selector = innerSelector;
                }
 
-               protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
-                       ref Parameter parameter, TransparentIdentifiersScope ti)
+               protected override void CreateArguments (ResolveContext ec, out Arguments args)
                {
+                       args = new Arguments (4);
+
                        args.Add (new Argument (expr));
-                       args.Add (CreateSelectorArgument (ec, outer_selector, parentParameter, ti));
-                       args.Add (CreateSelectorArgument (ec, inner_selector, parameter, ti));
-
-                       parameter = CreateResultSelectorParameter (parameter);
-                       if (projection == null) {
-                               ArrayList join_args = new ArrayList (2);
-                               join_args.Add (new AnonymousTypeParameter (parentParameter));
-                               join_args.Add (new AnonymousTypeParameter (parameter));
-                               projection = new AnonymousTypeDeclaration (join_args, (TypeContainer) ec.TypeContainer, loc);
+
+                       LambdaExpression lambda = new LambdaExpression (outer_selector.StartLocation);
+                       lambda.Block = outer_selector;
+                       args.Add (new Argument (lambda));
+
+                       lambda = new LambdaExpression (inner_selector.StartLocation);
+                       lambda.Block = inner_selector;
+                       args.Add (new Argument (lambda));
+
+                       Expression result_selector_expr;
+                       SimpleMemberName 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, ec.MemberContext.CurrentMemberDefinition.Parent, into_variable,
+                                       new SimpleName (into_variable.Value, into_variable.Location));
                        }
 
-                       args.Add (CreateSelectorArgument (ec, projection,
-                               new Parameter [] { parentParameter, parameter }, ti));
+                       LambdaExpression result_selector = new LambdaExpression (lt.Location);
+                       result_selector.Block = new QueryBlock (ec.Compiler, 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 SimpleMemberName GetIntoVariable ()
+               {
+                       return lt;
                }
-       
+
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        Join t = (Join) target;
-                       t.projection = projection.Clone (clonectx);
-                       t.inner_selector = inner_selector.Clone (clonectx);
-                       t.outer_selector = outer_selector.Clone (clonectx);
+                       t.inner_selector = (ToplevelBlock) inner_selector.Clone (clonectx);
+                       t.outer_selector = (ToplevelBlock) outer_selector.Clone (clonectx);
                        base.CloneTo (clonectx, t);
                }       
 
-               protected virtual Parameter CreateResultSelectorParameter (Parameter parameter)
-               {
-                       return parameter;
-               }
-
-               public override AQueryClause Next {
-                       set {
-                               // Use select as join projection
-                               if (value is Select) {
-                                       projection = value.expr;
-                                       next = value.next;
-                                       return;
-                               }
-
-                               base.Next = value;
-                       }
-               }
-
                protected override string MethodName {
                        get { return "Join"; }
                }
        }
 
-       public class GroupJoin : Join
+       class GroupJoin : Join
        {
-               readonly LocatedToken into_variable;
+               readonly SimpleMemberName into;
 
-               public GroupJoin (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector,
-                       LocatedToken into, Location loc)
-                       : base (variable, inner, outerSelector, innerSelector, loc)
+               public GroupJoin (ToplevelBlock block, SimpleMemberName lt, Expression inner,
+                       ToplevelBlock outerSelector, ToplevelBlock innerSelector, SimpleMemberName into, Location loc)
+                       : base (block, lt, inner, outerSelector, innerSelector, loc)
                {
-                       this.into_variable = into;
+                       this.into = into;
                }
 
-               protected override Parameter CreateResultSelectorParameter (Parameter parameter)
+               protected override SimpleMemberName GetIntoVariable ()
                {
-                       //
-                       // into variable is used as result selector and it's passed as
-                       // transparent identifiers to the next clause
-                       //
-                       return CreateBlockParameter (into_variable);
+                       return into;
                }
 
                protected override string MethodName {
@@ -486,53 +450,11 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class Let : ARangeVariableQueryClause
+       class Let : ARangeVariableQueryClause
        {
-               class RangeAnonymousTypeParameter : AnonymousTypeParameter
+               public Let (ToplevelBlock block, TypeContainer container, SimpleMemberName identifier, Expression expr)
+                       : base (block, CreateRangeVariableType (block, container, identifier, expr))
                {
-                       readonly Parameter parameter;
-
-                       public RangeAnonymousTypeParameter (Expression initializer, Parameter parameter)
-                               : base (initializer, parameter.Name, parameter.Location)
-                       {
-                               this.parameter = parameter;
-                       }
-
-                       public override Expression DoResolve (EmitContext ec)
-                       {
-                               Expression e = base.DoResolve (ec);
-                               if (e != null) {
-                                       //
-                                       // Spread resolved initializer type
-                                       //
-                                       parameter.ParameterType = type;
-                                       parameter.Resolve (ec);
-                               }
-
-                               return e;
-                       }
-
-                       protected override void Error_InvalidInitializer (Expression initializer)
-                       {
-                               Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
-                                       Name, initializer.GetSignatureForError ());
-                       }                       
-               }
-
-               public Let (LocatedToken variable, Expression expr, Location loc)
-                       : base (variable, expr, loc)
-               {
-               }
-
-               protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
-                       ref Parameter parameter, TransparentIdentifiersScope ti)
-               {
-                       args.Add (CreateSelectorArgument (ec, element_selector, parentParameter, ti));
-               }
-
-               protected override AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
-               {
-                       return new RangeAnonymousTypeParameter (expr, parameter);
                }
 
                protected override string MethodName {
@@ -540,10 +462,10 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class Select : AQueryClause
+       class Select : AQueryClause
        {
-               public Select (Expression expr, Location loc)
-                       : base (expr, loc)
+               public Select (ToplevelBlock block, Expression expr, Location loc)
+                       : base (block, expr, loc)
                {
                }
                
@@ -551,13 +473,14 @@ 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 (Parameter parameter)
-               {
-                       SimpleName sn = expr as SimpleName;
-                       if (sn == null)
-                               return true;
+               public bool IsRequired {
+                       get {
+                               SimpleName sn = expr as SimpleName;
+                               if (sn == null)
+                                       return true;
 
-                       return sn.Name != parameter.Name;
+                               return sn.Name != block.Parameters.FixedParameters [0].Name;
+                       }
                }
 
                protected override string MethodName {
@@ -565,34 +488,47 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class SelectMany : ARangeVariableQueryClause
+       class SelectMany : ARangeVariableQueryClause
        {
-               public SelectMany (LocatedToken variable, Expression expr)
-                       : base (variable, expr, expr.Location)
+               SimpleMemberName lt;
+
+               public SelectMany (ToplevelBlock block, SimpleMemberName lt, Expression expr)
+                       : base (block, expr)
                {
+                       this.lt = lt;
                }
 
-               protected override string MethodName {
-                       get { return "SelectMany"; }
-               }
+               protected override void CreateArguments (ResolveContext ec, out Arguments args)
+               {
+                       base.CreateArguments (ec, out args);
 
-               public override AQueryClause Next {
-                       set {
-                               element_selector = value.expr;
+                       Expression result_selector_expr;
+                       //
+                       // When select follow use is as result selector
+                       //
+                       if (next is Select) {
+                               result_selector_expr = next.Expr;
+                               next = next.next;
+                       } else {
+                               result_selector_expr = CreateRangeVariableType (block, ec.MemberContext.CurrentMemberDefinition.Parent, lt, new SimpleName (lt.Value, lt.Location));
+                       }
 
-                               // Can be optimized as SelectMany element selector
-                               if (value is Select)
-                                       return;
+                       LambdaExpression result_selector = new LambdaExpression (lt.Location);
+                       result_selector.Block = new QueryBlock (ec.Compiler, block.Parent, block.Parameters, lt, block.StartLocation);
+                       result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr));
 
-                               next = value;
-                       }
+                       args.Add (new Argument (result_selector));
+               }
+
+               protected override string MethodName {
+                       get { return "SelectMany"; }
                }
        }
 
-       public class Where : AQueryClause
+       class Where : AQueryClause
        {
-               public Where (Expression expr, Location loc)
-                       : base (expr, loc)
+               public Where (ToplevelBlock block, BooleanExpression expr, Location loc)
+                       : base (block, expr, loc)
                {
                }
 
@@ -601,10 +537,10 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class OrderByAscending : AQueryClause
+       class OrderByAscending : AQueryClause
        {
-               public OrderByAscending (Expression expr)
-                       : base (expr, expr.Location)
+               public OrderByAscending (ToplevelBlock block,Expression expr)
+                       : base (block, expr, expr.Location)
                {
                }
 
@@ -613,10 +549,10 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class OrderByDescending : AQueryClause
+       class OrderByDescending : AQueryClause
        {
-               public OrderByDescending (Expression expr)
-                       : base (expr, expr.Location)
+               public OrderByDescending (ToplevelBlock block, Expression expr)
+                       : base (block, expr, expr.Location)
                {
                }
 
@@ -625,10 +561,10 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class ThenByAscending : OrderByAscending
+       class ThenByAscending : OrderByAscending
        {
-               public ThenByAscending (Expression expr)
-                       : base (expr)
+               public ThenByAscending (ToplevelBlock block, Expression expr)
+                       : base (block, expr)
                {
                }
 
@@ -637,10 +573,10 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       public class ThenByDescending : OrderByDescending
+       class ThenByDescending : OrderByDescending
        {
-               public ThenByDescending (Expression expr)
-                       : base (expr)
+               public ThenByDescending (ToplevelBlock block, Expression expr)
+                       : base (block, expr)
                {
                }
 
@@ -649,159 +585,110 @@ namespace Mono.CSharp.Linq
                }
        }
 
-       class ImplicitQueryParameter : ImplicitLambdaParameter
+       //
+       // Implicit query block
+       //
+       class QueryBlock : ToplevelBlock
        {
-               public sealed class ImplicitType : Expression
+               //
+               // Transparent parameters are used to package up the intermediate results
+               // and pass them onto next clause
+               //
+               public sealed class TransparentParameter : ImplicitLambdaParameter
                {
-                       public static ImplicitType Instance = new ImplicitType ();
+                       public static int Counter;
+                       const string ParameterNamePrefix = "<>__TranspIdent";
 
-                       private ImplicitType ()
-                       {
-                       }
-
-                       protected override void CloneTo (CloneContext clonectx, Expression target)
-                       {
-                               // Nothing to clone
-                       }
+                       public readonly ParametersCompiled Parent;
+                       public readonly string Identifier;
 
-                       public override Expression DoResolve (EmitContext ec)
+                       public TransparentParameter (ParametersCompiled parent, SimpleMemberName identifier)
+                               : base (ParameterNamePrefix + Counter++, identifier.Location)
                        {
-                               throw new NotSupportedException ();
+                               Parent = parent;
+                               Identifier = identifier.Value;
                        }
 
-                       public override void Emit (EmitContext ec)
+                       public new static void Reset ()
                        {
-                               throw new NotSupportedException ();
+                               Counter = 0;
                        }
                }
 
-               public ImplicitQueryParameter (LocatedToken variable)
-                       : base (variable.Value, variable.Location)
+               public sealed class ImplicitQueryParameter : ImplicitLambdaParameter
                {
+                       public ImplicitQueryParameter (string name, Location loc)
+                               : base (name, loc)
+                       {
+                       }
                }
-       }
-
-       //
-       // Transparent parameters are used to package up the intermediate results
-       // and pass them onto next clause
-       //
-       public class TransparentParameter : ImplicitLambdaParameter
-       {
-               static int counter;
-               const string ParameterNamePrefix = "<>__TranspIdent";
 
-               public TransparentParameter (Location loc)
-                       : base (ParameterNamePrefix + counter++, loc)
+               public QueryBlock (CompilerContext ctx, Block parent, SimpleMemberName lt, Location start)
+                       : base (ctx, parent, new ParametersCompiled (ctx, new ImplicitQueryParameter (lt.Value, lt.Location)), start)
                {
+                       if (parent != null)
+                               base.CheckParentConflictName (parent.Toplevel, lt.Value, lt.Location);
                }
-       }
 
-       //
-       // Transparent identifiers are stored in nested anonymous types, each type can contain
-       // up to 2 identifiers or 1 identifier and parent type.
-       //
-       public class TransparentIdentifiersScope
-       {
-               readonly string [] identifiers;
-               readonly TransparentIdentifiersScope parent;
-               readonly TransparentParameter parameter;
-
-               public TransparentIdentifiersScope (TransparentIdentifiersScope parent,
-                       TransparentParameter parameter, string [] identifiers)
+               public QueryBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, SimpleMemberName lt, Location start)
+                       : base (ctx, parent, new ParametersCompiled (ctx, parameters [0].Clone (), new ImplicitQueryParameter (lt.Value, lt.Location)), start)
                {
-                       this.parent = parent;
-                       this.parameter = parameter;
-                       this.identifiers = identifiers;
                }
 
-               public MemberAccess GetIdentifier (string name)
+               public QueryBlock (CompilerContext ctx, Block parent, Location start)
+                       : base (ctx, parent, parent.Toplevel.Parameters.Clone (), start)
                {
-                       TransparentIdentifiersScope ident = FindIdentifier (name);
-                       if (ident == null)
-                               return null;
-
-                       return new MemberAccess (CreateIdentifierNestingExpression (ident), name);
                }
 
-               TransparentIdentifiersScope FindIdentifier (string name)
+               public void AddTransparentParameter (CompilerContext ctx, SimpleMemberName name)
                {
-                       foreach (string s in identifiers) {
-                               if (s == name)
-                                       return this;
-                       }
-
-                       if (parent == null)
-                               return null;
+                       base.CheckParentConflictName (this, name.Value, name.Location);
 
-                       return parent.FindIdentifier (name);
+                       parameters = new ParametersCompiled (ctx, new TransparentParameter (parameters, name));
                }
 
-               Expression CreateIdentifierNestingExpression (TransparentIdentifiersScope end)
+               protected override bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
                {
-                       Expression expr = new SimpleName (parameter.Name, parameter.Location);
-                       TransparentIdentifiersScope current = this;
-                       while (current != end)
-                       {
-                               current = current.parent;
-                               expr = new MemberAccess (expr, current.parameter.Name);
-                       }
-
-                       return expr;
+                       return true;
                }
-       }
-
-       //
-       // Lambda expression block which contains transparent identifiers
-       //
-       class SelectorBlock : ToplevelBlock
-       {
-               readonly TransparentIdentifiersScope transparent_identifiers;
 
-               public SelectorBlock (Block block, Parameters parameters, 
-                       TransparentIdentifiersScope transparentIdentifiers, Location loc)
-                       : base (block, parameters, loc)
+               // 
+               // Query parameter reference can include transparent parameters
+               //
+               protected override Expression GetParameterReferenceExpression (string name, Location loc)
                {
-                       this.transparent_identifiers = transparentIdentifiers;
-               }
+                       Expression expr = base.GetParameterReferenceExpression (name, loc);
+                       if (expr != null)
+                               return expr;
 
-               public override Expression GetTransparentIdentifier (string name)
-               {
-                       Expression expr = null;
-                       if (transparent_identifiers != null)
-                               expr = transparent_identifiers.GetIdentifier (name);
+                       TransparentParameter tp = parameters [0] as TransparentParameter;
+                       while (tp != null) {
+                               if (tp.Identifier == name)
+                                       break;
 
-                       if (expr != null || Container == null)
-                               return expr;
-                       
-                       return Container.GetTransparentIdentifier (name);
-               }
-       }
+                               TransparentParameter tp_next = tp.Parent [0] as TransparentParameter;
+                               if (tp_next == null) {
+                                       if (tp.Parent.GetParameterIndexByName (name) >= 0)
+                                               break;
+                               }
 
-       //
-       // This block is actually never used, it is used by parser only
-       //
-       public class QueryBlock : Block
-       {
-               Hashtable range_variables = new Hashtable ();
+                               tp = tp_next;
+                       }
 
-               public QueryBlock (Block parent, Location start)
-                       : base (parent, start, Location.Null)
-               {
-               }
+                       if (tp != null) {
+                               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);
+                               }
 
-               protected override void AddVariable (LocalInfo li)
-               {
-                       string name = li.Name;
-                       if (range_variables.Contains (name)) {
-                               Location conflict = (Location)range_variables [name];
-                               Report.SymbolRelatedToPreviousError (conflict, name);
-                               Error_AlreadyDeclared (li.Location, name);
-                               return;
+                               return new MemberAccess (expr, name);
                        }
 
-                       range_variables.Add (name, li.Location);
+                       return null;
                }
-               
+
                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}'",
@@ -814,9 +701,9 @@ namespace Mono.CSharp.Linq
                                var);           
                }
                
-               protected override void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+               public override void Error_AlreadyDeclaredTypeParameter (Report r, Location loc, string name, string conflict)
                {
-                       Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
+                       r.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
                                name);
                }
        }