2007-10-19 Nagappan A <anagappan@novell.com>
[mono.git] / mcs / gmcs / linq.cs
index 5d852b10fe1895fbb892effc78c108e1ab914d8e..02a078077af6fdd2a572460a50b6aabe2c647220 100644 (file)
@@ -20,14 +20,23 @@ namespace Mono.CSharp.Linq
        //
        //
 
-       public class QueryExpression : ARangeVariableQueryClause
+       public class QueryExpression : AQueryClause
        {
-               public QueryExpression (Block block, AQueryClause query)
-                       : base (block, null, query.Location)
+               LocatedToken variable;
+
+               public QueryExpression (LocatedToken variable, AQueryClause query)
+                       : base (null, query.Location)
                {
+                       this.variable = variable;
                        this.next = query;
                }
 
+               public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
+               {
+                       Parameter p = CreateBlockParameter (variable);
+                       return next.BuildQueryClause (ec, lSide, p, ti);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        Expression e = BuildQueryClause (ec, null, null, null);
@@ -64,7 +73,7 @@ namespace Mono.CSharp.Linq
                        }
                }
 
-               class QueryExpressionInvocation : Invocation
+               class QueryExpressionInvocation : Invocation, MethodGroupExpr.IErrorHandler
                {
                        public QueryExpressionInvocation (QueryExpressionAccess expr, ArrayList arguments)
                                : base (expr, arguments)
@@ -73,15 +82,41 @@ namespace Mono.CSharp.Linq
 
                        protected override MethodGroupExpr DoResolveOverload (EmitContext ec)
                        {
-                               int errors = Report.Errors;
-                               MethodGroupExpr rmg = mg.OverloadResolve (ec, Arguments, true, loc);
-                               if (rmg == null && errors == Report.Errors) {
-                                       // TODO: investigate whether would be better to re-use extension methods error handling
-                                       Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
-                                               mg.Name, TypeManager.CSharpName (mg.Type));
+                               MethodGroupExpr.CustomErrorHandler = this;
+                               MethodGroupExpr rmg = mg.OverloadResolve (ec, Arguments, false, loc);
+                               MethodGroupExpr.CustomErrorHandler = null;
+                               return rmg;
+                       }
+
+                       public bool NoExactMatch (EmitContext ec, MethodBase method)
+                       {
+                               ParameterData pd = TypeManager.GetParameterData (method);
+                               Type source_type = pd.ExtensionMethodType;
+                               if (source_type != null) {
+                                       Argument a = (Argument) Arguments [0];
+
+                                       if (source_type.IsGenericType && source_type.ContainsGenericParameters) {
+                                               TypeInferenceContext tic = new TypeInferenceContext (source_type.GetGenericArguments ());
+                                               tic.OutputTypeInference (ec, a.Expr, source_type);
+                                               if (tic.FixAllTypes ()) {
+                                                       source_type = source_type.GetGenericTypeDefinition ().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",
+                                                       mg.Name, TypeManager.CSharpName (a.Type));
+                                               return true;
+                                       }
                                }
 
-                               return rmg;
+                               if (!method.IsGenericMethod)
+                                       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 ());
+                               return true;
                        }
                }
 
@@ -93,6 +128,16 @@ namespace Mono.CSharp.Linq
                        this.expr = expr;
                        this.loc = loc;
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression target)
+               {
+                       AQueryClause t = (AQueryClause) target;
+                       if (expr != null)
+                               t.expr = expr.Clone (clonectx);
+                       
+                       if (next != null)
+                               t.next = (AQueryClause)next.Clone (clonectx);
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -108,11 +153,20 @@ namespace Mono.CSharp.Linq
                                Select s = next as Select;
                                if (s == null || s.IsRequired (parameter))
                                        return next.BuildQueryClause (ec, lSide, parameter, ti);
+                                       
+                               // Skip transparent select clause if any clause follows
+                               if (next.next != null)
+                                       return next.next.BuildQueryClause (ec, lSide, parameter, ti);
                        }
 
                        return lSide;
                }
 
+               protected static Parameter CreateBlockParameter (LocatedToken li)
+               {
+                       return new ImplicitQueryParameter (li);
+               }
+
                protected Invocation CreateQueryExpression (Expression lSide, ArrayList arguments)
                {
                        return new QueryExpressionInvocation (
@@ -135,13 +189,21 @@ namespace Mono.CSharp.Linq
                        Parameters p = new Parameters (parameters);
 
                        LambdaExpression selector = new LambdaExpression (
-                               null, null, (TypeContainer) ec.DeclContainer, p, ec.CurrentBlock, loc);
+                               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));
 
-                       selector.CreateAnonymousHelpers ();
-                       selector.RootScope.DefineType ();
+                       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);
                }
 
@@ -170,13 +232,13 @@ namespace Mono.CSharp.Linq
        //
        public abstract class ARangeVariableQueryClause : AQueryClause
        {
-               public readonly Block block;
+               LocatedToken variable;
                protected Expression element_selector;
 
-               protected ARangeVariableQueryClause (Block block, Expression expr, Location loc)
+               protected ARangeVariableQueryClause (LocatedToken variable, Expression expr, Location loc)
                        : base (expr, loc)
                {
-                       this.block = block;
+                       this.variable = variable;
                }
 
                protected virtual void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
@@ -193,17 +255,7 @@ namespace Mono.CSharp.Linq
                //
                public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
                {
-                       ICollection values = block.Variables.Values;
-                       if (values.Count != 1)
-                               throw new NotImplementedException ("Count != 1");
-
-                       IEnumerator enumerator = values.GetEnumerator ();
-                       enumerator.MoveNext ();
-                       LocalInfo li = (LocalInfo) enumerator.Current;
-
-                       Parameter parameter = new ImplicitQueryParameter (li);
-                       if (parentParameter == null)
-                               return next.BuildQueryClause (ec, expr, parameter, ti);
+                       Parameter parameter = CreateBlockParameter (variable);
 
                        if (next != null) {
                                //
@@ -214,7 +266,7 @@ namespace Mono.CSharp.Linq
                                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.DeclContainer, loc);
+                               element_selector = new AnonymousTypeDeclaration (transp_args, (TypeContainer) ec.TypeContainer, loc);
                        }
 
                        ArrayList args = new ArrayList ();
@@ -239,7 +291,15 @@ namespace Mono.CSharp.Linq
 
                        return lSide;
                }
-
+               
+               protected override void CloneTo (CloneContext clonectx, Expression target)
+               {
+                       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
                //
@@ -274,6 +334,7 @@ namespace Mono.CSharp.Linq
 
        public class Cast : QueryStartClause
        {
+               // We don't have to clone cast type
                readonly Expression type_expr;
 
                public Cast (Expression type, Expression expr)
@@ -282,13 +343,6 @@ namespace Mono.CSharp.Linq
                        this.type_expr = type;
                }
                
-               protected override void CloneTo (CloneContext clonectx, Expression target)
-               {
-                       // We don't have to clone cast type
-                       Cast t = (Cast) target;
-                       t.expr = expr.Clone (clonectx);
-               }               
-
                public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
                {
                        lSide = CreateQueryExpression (expr, new TypeArguments (loc, type_expr), null);
@@ -305,7 +359,7 @@ namespace Mono.CSharp.Linq
 
        public class GroupBy : AQueryClause
        {
-               readonly Expression element_selector;
+               Expression element_selector;
                
                public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
                        : base (keySelector, loc)
@@ -328,6 +382,13 @@ namespace Mono.CSharp.Linq
 
                        return lSide;
                }
+       
+               protected override void CloneTo (CloneContext clonectx, Expression target)
+               {
+                       GroupBy t = (GroupBy) target;
+                       t.element_selector = element_selector.Clone (clonectx);
+                       base.CloneTo (clonectx, t);
+               }
 
                protected override string MethodName {
                        get { return "GroupBy"; }
@@ -339,8 +400,8 @@ namespace Mono.CSharp.Linq
                Expression projection;
                Expression inner_selector, outer_selector;
 
-               public Join (Block block, Expression inner, Expression outerSelector, Expression innerSelector, Location loc)
-                       : base (block, inner, loc)
+               public Join (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector, Location loc)
+                       : base (variable, inner, loc)
                {
                        this.outer_selector = outerSelector;
                        this.inner_selector = innerSelector;
@@ -358,12 +419,21 @@ namespace Mono.CSharp.Linq
                                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.DeclContainer, loc);
+                               projection = new AnonymousTypeDeclaration (join_args, (TypeContainer) ec.TypeContainer, loc);
                        }
 
                        args.Add (CreateSelectorArgument (ec, projection,
                                new Parameter [] { parentParameter, parameter }, ti));
                }
+       
+               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);
+                       base.CloneTo (clonectx, t);
+               }       
 
                protected virtual Parameter CreateResultSelectorParameter (Parameter parameter)
                {
@@ -390,11 +460,11 @@ namespace Mono.CSharp.Linq
 
        public class GroupJoin : Join
        {
-               string into_variable;
+               readonly LocatedToken into_variable;
 
-               public GroupJoin (Block block, Expression inner, Expression outerSelector, Expression innerSelector,
-                       string into, Location loc)
-                       : base (block, inner, outerSelector, innerSelector, loc)
+               public GroupJoin (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector,
+                       LocatedToken into, Location loc)
+                       : base (variable, inner, outerSelector, innerSelector, loc)
                {
                        this.into_variable = into;
                }
@@ -405,7 +475,7 @@ namespace Mono.CSharp.Linq
                        // into variable is used as result selector and it's passed as
                        // transparent identifiers to the next clause
                        //
-                       return new ImplicitLambdaParameter (into_variable, loc);
+                       return CreateBlockParameter (into_variable);
                }
 
                protected override string MethodName {
@@ -438,10 +508,16 @@ namespace Mono.CSharp.Linq
 
                                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 (Block block, Expression expr, Location loc)
-                       : base (block, expr, loc)
+               public Let (LocatedToken variable, Expression expr, Location loc)
+                       : base (variable, expr, loc)
                {
                }
 
@@ -488,8 +564,8 @@ namespace Mono.CSharp.Linq
 
        public class SelectMany : ARangeVariableQueryClause
        {
-               public SelectMany (Block block, Expression expr)
-                       : base (block, expr, expr.Location)
+               public SelectMany (LocatedToken variable, Expression expr)
+                       : base (variable, expr, expr.Location)
                {
                }
 
@@ -596,21 +672,9 @@ namespace Mono.CSharp.Linq
                        }
                }
 
-               readonly LocalInfo variable;
-
-               public ImplicitQueryParameter (LocalInfo variable)
-                       : base (variable.Name, variable.Location)
-               {
-                       this.variable = variable;
-               }
-
-               public override bool Resolve (IResolveContext ec)
+               public ImplicitQueryParameter (LocatedToken variable)
+                       : base (variable.Value, variable.Location)
                {
-                       if (!base.Resolve (ec))
-                               return false;
-
-                       variable.VariableType = parameter_type;
-                       return true;
                }
        }
 
@@ -699,10 +763,58 @@ namespace Mono.CSharp.Linq
 
                public override Expression GetTransparentIdentifier (string name)
                {
-                       if (transparent_identifiers == null)
-                               return null;
+                       Expression expr = null;
+                       if (transparent_identifiers != null)
+                               expr = transparent_identifiers.GetIdentifier (name);
 
-                       return transparent_identifiers.GetIdentifier (name);
+                       if (expr != null || Container == null)
+                               return expr;
+                       
+                       return Container.GetTransparentIdentifier (name);
+               }
+       }
+
+       //
+       // This block is actually never used, it is used by parser only
+       //
+       public class QueryBlock : Block
+       {
+               Hashtable range_variables = new Hashtable ();
+
+               public QueryBlock (Block parent, Location start)
+                       : base (parent, start, Location.Null)
+               {
+               }
+
+               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;
+                       }
+
+                       range_variables.Add (name, li.Location);
+               }
+               
+               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)
+               {
+                       Report.Error (1930, loc, "A range variable `{0}' has already been declared in this scope",
+                               var);           
+               }
+               
+               protected override void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+               {
+                       Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
+                               name);
                }
        }
 }