Merge pull request #1439 from BrzVlad/feature-managed-allocator
[mono.git] / mcs / mcs / linq.cs
index 8578323eb8fc0d8a2d13d46bf7dd3c5e78464798..7f19c2d89b35524f73e49b9b00c4029326fb4276 100644 (file)
@@ -6,10 +6,10 @@
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
 // Copyright 2007-2008 Novell, Inc
+// Copyright 2011 Xamarin Inc
 //
 
 using System;
-using System.Reflection;
 using System.Collections.Generic;
 
 namespace Mono.CSharp.Linq
@@ -17,7 +17,7 @@ namespace Mono.CSharp.Linq
        public class QueryExpression : AQueryClause
        {
                public QueryExpression (AQueryClause start)
-                       : base (null, null, Location.Null)
+                       : base (null, null, start.Location)
                {
                        this.next = start;
                }
@@ -64,7 +64,7 @@ namespace Mono.CSharp.Linq
                        {
                        }
 
-                       protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
+                       public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
                        {
                                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?",
@@ -85,6 +85,13 @@ namespace Mono.CSharp.Linq
                                return rmg;
                        }
 
+                       protected override Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
+                       {
+                               ec.Report.Error (1979, loc,
+                                       "Query expressions with a source or join sequence of type `dynamic' are not allowed");
+                               return null;
+                       }
+
                        #region IErrorHandler Members
 
                        bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
@@ -113,17 +120,17 @@ namespace Mono.CSharp.Linq
                                if (source_type != null) {
                                        Argument a = arguments[0];
 
-                                       if (TypeManager.IsGenericType (source_type) && TypeManager.ContainsGenericParameters (source_type)) {
+                                       if (TypeManager.IsGenericType (source_type) && InflatedTypeSpec.ContainsTypeParameter (source_type)) {
                                                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);
+                                                       source_type = source_type.GetDefinition ().MakeGenericType (rc, tic.InferredTypeArguments);
                                                }
                                        }
 
                                        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));
+                                                       best.Name, a.Type.GetSignatureForError ());
                                                return true;
                                        }
                                }
@@ -194,7 +201,8 @@ namespace Mono.CSharp.Linq
 
                protected virtual Parameter CreateChildrenParameters (Parameter parameter)
                {
-                       return parameter;
+                       // Have to clone the parameter for any children use, it carries block sensitive data
+                       return parameter.Clone ();
                }
 
                protected virtual void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
@@ -203,7 +211,7 @@ namespace Mono.CSharp.Linq
 
                        LambdaExpression selector = new LambdaExpression (loc);
 
-                       block.SetParameter (parameter.Clone ());
+                       block.SetParameter (parameter);
                        selector.Block = block;
                        selector.Block.AddStatement (new ContextualReturn (expr));
 
@@ -238,8 +246,8 @@ namespace Mono.CSharp.Linq
        {
                sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter
                {
-                       public RangeAnonymousTypeParameter (Expression initializer, SimpleMemberName parameter)
-                               : base (initializer, parameter.Value, parameter.Location)
+                       public RangeAnonymousTypeParameter (Expression initializer, RangeVariable parameter)
+                               : base (initializer, parameter.Name, parameter.Location)
                        {
                        }
 
@@ -250,12 +258,35 @@ namespace Mono.CSharp.Linq
                        }
                }
 
-               protected SimpleMemberName range_variable;
+               class RangeParameterReference : ParameterReference
+               {
+                       Parameter parameter;
+
+                       public RangeParameterReference (Parameter p)
+                               : base (null, p.Location)
+                       {
+                               this.parameter = p;
+                       }
 
-               protected ARangeVariableQueryClause (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+                       protected override Expression DoResolve (ResolveContext ec)
+                       {
+                               pi = ec.CurrentBlock.ParametersBlock.GetParameterInfo (parameter);
+                               return base.DoResolve (ec);
+                       }
+               }
+
+               protected RangeVariable identifier;
+
+               protected ARangeVariableQueryClause (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
                        : base (block, expr, loc)
                {
-                       range_variable = identifier;
+                       this.identifier = identifier;
+               }
+
+               public RangeVariable Identifier {
+                       get {
+                               return identifier;
+                       }
                }
 
                public FullNamedExpression IdentifierType { get; set; }
@@ -268,53 +299,132 @@ namespace Mono.CSharp.Linq
 
                protected override Parameter CreateChildrenParameters (Parameter parameter)
                {
-                       return new QueryBlock.TransparentParameter (parameter, GetIntoVariable ());
+                       return new QueryBlock.TransparentParameter (parameter.Clone (), GetIntoVariable ());
                }
 
-               protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, SimpleMemberName name, Expression init)
+               protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, RangeVariable name, Expression init)
                {
                        var args = new List<AnonymousTypeParameter> (2);
-                       args.Add (new AnonymousTypeParameter (parameter));
+
+                       //
+                       // The first argument is the reference to the parameter
+                       //
+                       args.Add (new AnonymousTypeParameter (new RangeParameterReference (parameter), parameter.Name, parameter.Location));
+
+                       //
+                       // The second argument is the linq expression
+                       //
                        args.Add (new RangeAnonymousTypeParameter (init, name));
+
+                       //
+                       // Create unique anonymous type
+                       //
                        return new NewAnonymousType (args, rc.MemberContext.CurrentMemberDefinition.Parent, name.Location);
                }
 
-               protected virtual SimpleMemberName GetIntoVariable ()
+               protected virtual RangeVariable GetIntoVariable ()
                {
-                       return range_variable;
+                       return identifier;
                }
        }
 
-       class QueryStartClause : ARangeVariableQueryClause
+       public sealed class RangeVariable : INamedBlockVariable
        {
-               public QueryStartClause (QueryBlock block, Expression expr, SimpleMemberName identifier, Location loc)
-                       : base (block, identifier, expr, loc)
+               Block block;
+
+               public RangeVariable (string name, Location loc)
                {
-                       block.AddRangeVariable (identifier);
+                       Name = name;
+                       Location = loc;
                }
 
-               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
+               #region Properties
+
+               public Block Block {
+                       get {
+                               return block;
+                       }
+                       set {
+                               block = value;
+                       }
+               }
+
+               public bool IsDeclared {
+                       get {
+                               return true;
+                       }
+               }
+
+               public bool IsParameter {
+                       get {
+                               return false;
+                       }
+               }
+
+               public Location Location { get; private set; }
+
+               public string Name { get; private set; }
+
+               #endregion
+
+               public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
                {
-/*
-                       expr = expr.Resolve (ec);
-                       if (expr == null)
-                               return null;
+                       // 
+                       // We know the variable name is somewhere in the scope. This generates
+                       // an access expression from current block
+                       //
+                       var pb = rc.CurrentBlock.ParametersBlock;
+                       while (true) {
+                               if (pb is QueryBlock) {
+                                       for (int i = pb.Parameters.Count - 1; i >= 0; --i) {
+                                               var p = pb.Parameters[i];
+                                               if (p.Name == Name)
+                                                       return pb.GetParameterReference (i, loc);
+
+                                               Expression expr = null;
+                                               var tp = p as QueryBlock.TransparentParameter;
+                                               while (tp != null) {
+                                                       if (expr == null)
+                                                               expr = pb.GetParameterReference (i, loc);
+                                                       else
+                                                               expr = new TransparentMemberAccess (expr, tp.Name);
+
+                                                       if (tp.Identifier == Name)
+                                                               return new TransparentMemberAccess (expr, Name);
+
+                                                       if (tp.Parent.Name == Name)
+                                                               return new TransparentMemberAccess (expr, Name);
+
+                                                       tp = tp.Parent as QueryBlock.TransparentParameter;
+                                               }
+                                       }
+                               }
 
-                       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 (pb == block)
+                                       return null;
+
+                               pb = pb.Parent.ParametersBlock;
                        }
-*/
+               }
+       }
+
+       public class QueryStartClause : ARangeVariableQueryClause
+       {
+               public QueryStartClause (QueryBlock block, Expression expr, RangeVariable identifier, Location loc)
+                       : base (block, identifier, expr, loc)
+               {
+                       block.AddRangeVariable (identifier);
+               }
 
+               public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
+               {
                        if (IdentifierType != null)
                                expr = CreateCastExpression (expr);
 
                        if (parameter == null)
                                lSide = expr;
 
-                       return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (range_variable.Value, range_variable.Location));
+                       return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (identifier.Name, identifier.Location));
                }
 
                protected override Expression DoResolve (ResolveContext ec)
@@ -345,6 +455,12 @@ namespace Mono.CSharp.Linq
                        }
                }
 
+               public Expression SelectorExpression {
+                       get {
+                               return element_selector;
+                       }
+               }
+
                protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
                        base.CreateArguments (ec, parameter, ref args);
@@ -373,19 +489,36 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "GroupBy"; }
                }
+               
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class Join : SelectMany
        {
                QueryBlock inner_selector, outer_selector;
 
-               public Join (QueryBlock block, SimpleMemberName lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc)
+               public Join (QueryBlock block, RangeVariable lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc)
                        : base (block, lt, inner, loc)
                {
                        this.outer_selector = outerSelector;
                        this.inner_selector = innerSelector;
                }
 
+               public QueryBlock InnerSelector {
+                       get {
+                               return inner_selector;
+                       }
+               }
+               
+               public QueryBlock OuterSelector {
+                       get {
+                               return outer_selector;
+                       }
+               }
+
                protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
                {
                        args = new Arguments (4);
@@ -400,7 +533,7 @@ namespace Mono.CSharp.Linq
                        lambda.Block = outer_selector;
                        args.Add (new Argument (lambda));
 
-                       inner_selector.SetParameter (new ImplicitLambdaParameter (range_variable.Value, range_variable.Location));
+                       inner_selector.SetParameter (new ImplicitLambdaParameter (identifier.Name, identifier.Location));
                        lambda = new LambdaExpression (inner_selector.StartLocation);
                        lambda.Block = inner_selector;
                        args.Add (new Argument (lambda));
@@ -419,20 +552,25 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "Join"; }
                }
+               
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class GroupJoin : Join
        {
-               readonly SimpleMemberName into;
+               readonly RangeVariable into;
 
-               public GroupJoin (QueryBlock block, SimpleMemberName lt, Expression inner,
-                       QueryBlock outerSelector, QueryBlock innerSelector, SimpleMemberName into, Location loc)
+               public GroupJoin (QueryBlock block, RangeVariable lt, Expression inner,
+                       QueryBlock outerSelector, QueryBlock innerSelector, RangeVariable into, Location loc)
                        : base (block, lt, inner, outerSelector, innerSelector, loc)
                {
                        this.into = into;
                }
 
-               protected override SimpleMemberName GetIntoVariable ()
+               protected override RangeVariable GetIntoVariable ()
                {
                        return into;
                }
@@ -440,24 +578,34 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "GroupJoin"; }
                }
+               
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class Let : ARangeVariableQueryClause
        {
-               public Let (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+               public Let (QueryBlock block, RangeVariable 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);
+                       expr = CreateRangeVariableType (ec, parameter, identifier, expr);
                        base.CreateArguments (ec, parameter, ref args);
                }
 
                protected override string MethodName {
                        get { return "Select"; }
                }
+               
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class Select : AQueryClause
@@ -483,11 +631,17 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "Select"; }
                }
+               
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
+
        }
 
        public class SelectMany : ARangeVariableQueryClause
        {
-               public SelectMany (QueryBlock block, SimpleMemberName identifier, Expression expr, Location loc)
+               public SelectMany (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
                        : base (block, identifier, expr, loc)
                {
                }
@@ -498,14 +652,14 @@ namespace Mono.CSharp.Linq
                                if (IdentifierType != null)
                                        expr = CreateCastExpression (expr);
 
-                               base.CreateArguments (ec, parameter, ref args);
+                               base.CreateArguments (ec, parameter.Clone (), ref args);
                        }
 
                        Expression result_selector_expr;
                        QueryBlock result_block;
 
                        var target = GetIntoVariable ();
-                       var target_param = new ImplicitLambdaParameter (target.Value, target.Location);
+                       var target_param = new ImplicitLambdaParameter (target.Name, target.Location);
 
                        //
                        // When select follows use it as a result selector
@@ -518,9 +672,9 @@ namespace Mono.CSharp.Linq
 
                                next = next.next;
                        } else {
-                               result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Value, target.Location));
+                               result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Name, target.Location));
 
-                               result_block = new QueryBlock (ec.Compiler, block.Parent, block.StartLocation);
+                               result_block = new QueryBlock (block.Parent, block.StartLocation);
                                result_block.SetParameters (parameter, target_param);
                        }
 
@@ -534,11 +688,16 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "SelectMany"; }
                }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class Where : AQueryClause
        {
-               public Where (QueryBlock block, BooleanExpression expr, Location loc)
+               public Where (QueryBlock block, Expression expr, Location loc)
                        : base (block, expr, loc)
                {
                }
@@ -547,9 +706,9 @@ namespace Mono.CSharp.Linq
                        get { return "Where"; }
                }
 
-               protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
+               public override object Accept (StructuralVisitor visitor)
                {
-                       base.CreateArguments (ec, parameter, ref args);
+                       return visitor.Visit (this);
                }
        }
 
@@ -563,6 +722,11 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "OrderBy"; }
                }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class OrderByDescending : AQueryClause
@@ -575,6 +739,11 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "OrderByDescending"; }
                }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class ThenByAscending : OrderByAscending
@@ -587,6 +756,11 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "ThenBy"; }
                }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        public class ThenByDescending : OrderByDescending
@@ -599,12 +773,17 @@ namespace Mono.CSharp.Linq
                protected override string MethodName {
                        get { return "ThenByDescending"; }
                }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
        }
 
        //
        // Implicit query block
        //
-       public class QueryBlock : ToplevelBlock
+       public class QueryBlock : ParametersBlock
        {
                //
                // Transparent parameters are used to package up the intermediate results
@@ -618,123 +797,65 @@ namespace Mono.CSharp.Linq
                        public readonly Parameter Parent;
                        public readonly string Identifier;
 
-                       public TransparentParameter (Parameter parent, SimpleMemberName identifier)
+                       public TransparentParameter (Parameter parent, RangeVariable identifier)
                                : base (ParameterNamePrefix + Counter++, identifier.Location)
                        {
                                Parent = parent;
-                               Identifier = identifier.Value;
+                               Identifier = identifier.Name;
                        }
 
-                       public new static void Reset ()
+                       public static void Reset ()
                        {
                                Counter = 0;
                        }
                }
 
-               sealed class RangeVariable : IKnownVariable
-               {
-                       public RangeVariable (QueryBlock block, Location loc)
-                       {
-                               Block = block;
-                               Location = loc;
-                       }
-
-                       public Block Block { get; private set; }
-
-                       public Location Location { get; private set; }
-               }
-
-               List<SimpleMemberName> range_variables;
-
-               public QueryBlock (CompilerContext ctx, Block parent, Location start)
-                       : base (ctx, parent, ParametersCompiled.EmptyReadOnlyParameters, start)
+               public QueryBlock (Block parent, Location start)
+                       : base (parent, ParametersCompiled.EmptyReadOnlyParameters, start, Flags.CompilerGenerated)
                {
                }
 
-               public void AddRangeVariable (SimpleMemberName name)
+               public void AddRangeVariable (RangeVariable variable)
                {
-                       if (!CheckParentConflictName (this, name.Value, name.Location))
-                               return;
-
-                       if (range_variables == null)
-                               range_variables = new List<SimpleMemberName> ();
-
-                       range_variables.Add (name);
-                       AddKnownVariable (name.Value, new RangeVariable (this, name.Location));
+                       variable.Block = this;
+                       TopBlock.AddLocalName (variable.Name, variable, true);
                }
 
-               // 
-               // Query parameter reference can include transparent parameters
-               //
-               protected override Expression GetParameterReferenceExpression (string name, Location loc)
+               public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
                {
-                       Expression expr = base.GetParameterReferenceExpression (name, loc);
-                       if (expr != null)
-                               return expr;
-
-                       TransparentParameter tp = parameters [0] as TransparentParameter;
-                       while (tp != null) {
-                               if (tp.Identifier == name)
-                                       break;
-
-                               TransparentParameter tp_next = tp.Parent as TransparentParameter;
-                               if (tp_next == null && tp.Parent.Name == name)
-                                       break;
-
-                               tp = tp_next;
-                       }
-
-                       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;
-                                       expr = new TransparentMemberAccess (expr, tp_cursor.Name);
-                               }
-
-                               return new TransparentMemberAccess (expr, name);
-                       }
-
-                       return null;
+                       TopBlock.Report.Error (1931, variable.Location,
+                               "A range variable `{0}' conflicts with a previous declaration of `{0}'",
+                               name);
                }
 
-               protected override bool HasParameterWithName (string name)
+               public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
                {
-                       return range_variables != null && range_variables.Exists (l => l.Value == name);
+                       TopBlock.Report.Error (1930, variable.Location,
+                               "A range variable `{0}' has already been declared in this scope",
+                               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}'",
-                               var);
-               }
-               
-               protected override void Error_AlreadyDeclared (Location loc, string var)
+               public override void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
                {
-                       Report.Error (1930, loc, "A range variable `{0}' has already been declared in this scope",
-                               var);           
-               }
-               
-               public override void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
-               {
-                       Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
+                       TopBlock.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)
+                       base.parameters = new ParametersCompiled (parameter);
+                       base.parameter_info = new ParameterInfo[] {
+                               new ParameterInfo (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)
+                       base.parameters = new ParametersCompiled (first, second);
+                       base.parameter_info = new ParameterInfo[] {
+                               new ParameterInfo (this, 0),
+                               new ParameterInfo (this, 1)
                        };
                }
        }
@@ -745,5 +866,14 @@ namespace Mono.CSharp.Linq
                        : base (expr, name)
                {
                }
+
+               public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+               {
+                       rc.Report.Error (1947, loc,
+                               "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
+                               Name);
+
+                       return null;
+               }
        }
 }