ff1d2857db7f73681f361b9fbed983677a58f4ab
[mono.git] / mcs / mcs / linq.cs
1 //
2 // linq.cs: support for query expressions
3 //
4 // Authors: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2007-2008 Novell, Inc
9 //
10
11 using System;
12 using System.Reflection;
13 using System.Collections;
14
15 namespace Mono.CSharp.Linq
16 {
17         // NOTES:
18         // Expression should be IExpression to save some memory and make a few things
19         // easier to read
20         //
21         //
22
23         public class QueryExpression : AQueryClause
24         {
25                 LocatedToken variable;
26
27                 public QueryExpression (LocatedToken variable, AQueryClause query)
28                         : base (null, query.Location)
29                 {
30                         this.variable = variable;
31                         this.next = query;
32                 }
33
34                 public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
35                 {
36                         Parameter p = CreateBlockParameter (variable);
37                         return next.BuildQueryClause (ec, lSide, p, ti);
38                 }
39
40                 public override Expression DoResolve (EmitContext ec)
41                 {
42                         Expression e = BuildQueryClause (ec, null, null, null);
43                         e = e.Resolve (ec);
44                         return e;
45                 }
46
47                 protected override string MethodName {
48                         get { throw new NotSupportedException (); }
49                 }
50         }
51
52         public abstract class AQueryClause : Expression
53         {
54                 class QueryExpressionAccess : MemberAccess
55                 {
56                         public QueryExpressionAccess (Expression expr, string methodName, Location loc)
57                                 : base (expr, methodName, loc)
58                         {
59                         }
60
61                         public QueryExpressionAccess (Expression expr, string methodName, TypeArguments typeArguments, Location loc)
62                                 : base (expr, methodName, typeArguments, loc)
63                         {
64                         }
65
66                         protected override Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
67                                 Type queried_type, string name, string class_name, MemberTypes mt, BindingFlags bf)
68                         {
69                                 Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " +
70                                         "Are you missing `System.Linq' using directive or `System.Core.dll' assembly reference?",
71                                         name);
72                                 return null;
73                         }
74                 }
75
76                 class QueryExpressionInvocation : Invocation, MethodGroupExpr.IErrorHandler
77                 {
78                         public QueryExpressionInvocation (QueryExpressionAccess expr, ArrayList arguments)
79                                 : base (expr, arguments)
80                         {
81                         }
82
83                         protected override MethodGroupExpr DoResolveOverload (EmitContext ec)
84                         {
85                                 mg.CustomErrorHandler = this;
86                                 MethodGroupExpr rmg = mg.OverloadResolve (ec, ref Arguments, false, loc);
87                                 return rmg;
88                         }
89
90                         public bool NoExactMatch (EmitContext ec, MethodBase method)
91                         {
92 #if GMCS_SOURCE                         
93                                 ParameterData pd = TypeManager.GetParameterData (method);
94                                 Type source_type = pd.ExtensionMethodType;
95                                 if (source_type != null) {
96                                         Argument a = (Argument) Arguments [0];
97
98                                         if (source_type.IsGenericType && source_type.ContainsGenericParameters) {
99                                                 TypeInferenceContext tic = new TypeInferenceContext (source_type.GetGenericArguments ());
100                                                 tic.OutputTypeInference (ec, a.Expr, source_type);
101                                                 if (tic.FixAllTypes ()) {
102                                                         source_type = source_type.GetGenericTypeDefinition ().MakeGenericType (tic.InferredTypeArguments);
103                                                 }
104                                         }
105
106                                         if (!Convert.ImplicitConversionExists (ec, a.Expr, source_type)) {
107                                                 Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
108                                                         mg.Name, TypeManager.CSharpName (a.Type));
109                                                 return true;
110                                         }
111                                 }
112
113                                 if (!method.IsGenericMethod)
114                                         return false;
115
116                                 Report.Error (1942, loc, "Type inference failed to infer type argument for `{0}' clause. " +
117                                         "Try specifying the type argument explicitly",
118                                         mg.Name.ToLower ());
119                                 return true;
120 #else
121                                 return false;
122 #endif
123                         }
124                 }
125
126                 public AQueryClause next;
127                 /*protected*/ public Expression expr;
128
129                 protected AQueryClause (Expression expr, Location loc)
130                 {
131                         this.expr = expr;
132                         this.loc = loc;
133                 }
134                 
135                 protected override void CloneTo (CloneContext clonectx, Expression target)
136                 {
137                         AQueryClause t = (AQueryClause) target;
138                         if (expr != null)
139                                 t.expr = expr.Clone (clonectx);
140                         
141                         if (next != null)
142                                 t.next = (AQueryClause)next.Clone (clonectx);
143                 }
144
145                 public override Expression DoResolve (EmitContext ec)
146                 {
147                         return expr.DoResolve (ec);
148                 }
149
150                 public virtual Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
151                 {
152                         ArrayList args = new ArrayList (1);
153                         args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
154                         lSide = CreateQueryExpression (lSide, args);
155                         if (next != null) {
156                                 Select s = next as Select;
157                                 if (s == null || s.IsRequired (parameter))
158                                         return next.BuildQueryClause (ec, lSide, parameter, ti);
159                                         
160                                 // Skip transparent select clause if any clause follows
161                                 if (next.next != null)
162                                         return next.next.BuildQueryClause (ec, lSide, parameter, ti);
163                         }
164
165                         return lSide;
166                 }
167
168                 protected static Parameter CreateBlockParameter (LocatedToken li)
169                 {
170                         return new ImplicitQueryParameter (li);
171                 }
172
173                 protected Invocation CreateQueryExpression (Expression lSide, ArrayList arguments)
174                 {
175                         return new QueryExpressionInvocation (
176                                 new QueryExpressionAccess (lSide, MethodName, loc), arguments);
177                 }
178
179                 protected Invocation CreateQueryExpression (Expression lSide, TypeArguments typeArguments, ArrayList arguments)
180                 {
181                         return new QueryExpressionInvocation (
182                                 new QueryExpressionAccess (lSide, MethodName, typeArguments, loc), arguments);
183                 }
184
185                 protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter parameter, TransparentIdentifiersScope ti)
186                 {
187                         return CreateSelectorArgument (ec, expr, new Parameter [] { parameter }, ti);
188                 }
189
190                 protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter[] parameters, TransparentIdentifiersScope ti)
191                 {
192                         Parameters p = new Parameters (parameters);
193
194                         LambdaExpression selector = new LambdaExpression (
195                                 null, null, (TypeContainer)ec.TypeContainer, p, ec.CurrentBlock, loc);
196                         selector.Block = new SelectorBlock (ec.CurrentBlock, p, ti, loc);
197                         selector.Block.AddStatement (new Return (expr, loc));
198
199                         if (!ec.IsInProbingMode) {
200                                 selector.CreateAnonymousHelpers ();
201
202                                 // TODO: I am not sure where this should be done to work
203                                 // correctly with anonymous containerss and was called only once
204                                 // FIXME: selector.RootScope == null for nested anonymous
205                                 // methods only ?
206                                 if (selector.RootScope != null)
207                                         selector.RootScope.DefineType ();
208                         }
209                         
210                         return new Argument (selector);
211                 }
212
213                 public override void Emit (EmitContext ec)
214                 {
215                         throw new NotSupportedException ();
216                 }
217
218                 protected abstract string MethodName { get; }
219
220                 public virtual AQueryClause Next {
221                         set {
222                                 next = value;
223                         }
224                 }
225
226                 public AQueryClause Tail {
227                         get {
228                                 return next == null ? this : next.Tail;
229                         }
230                 }
231         }
232
233         //
234         // A query clause with an identifier (range variable)
235         //
236         public abstract class ARangeVariableQueryClause : AQueryClause
237         {
238                 LocatedToken variable;
239                 protected Expression element_selector;
240
241                 protected ARangeVariableQueryClause (LocatedToken variable, Expression expr, Location loc)
242                         : base (expr, loc)
243                 {
244                         this.variable = variable;
245                 }
246
247                 protected virtual void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
248                         ref Parameter parameter, TransparentIdentifiersScope ti)
249                 {
250                         args.Add (CreateSelectorArgument (ec, expr, parentParameter, ti));
251                         args.Add (CreateSelectorArgument (ec, element_selector,
252                                 new Parameter [] { parentParameter, parameter }, ti));
253                 }
254
255                 //
256                 // Customization for range variables which not only creates a lambda expression but
257                 // also builds a chain of range varible pairs
258                 //
259                 public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
260                 {
261                         Parameter parameter = CreateBlockParameter (variable);
262
263                         if (next != null) {
264                                 //
265                                 // Builds transparent identifiers, each identifier includes its parent
266                                 // type at index 0, and new value at index 1. This is not valid for the
267                                 // first one which includes two values directly.
268                                 //
269                                 ArrayList transp_args = new ArrayList (2);
270                                 transp_args.Add (new AnonymousTypeParameter (parentParameter));
271                                 transp_args.Add (CreateAnonymousTypeVariable (parameter));
272                                 element_selector = new AnonymousTypeDeclaration (transp_args, (TypeContainer) ec.TypeContainer, loc);
273                         }
274
275                         ArrayList args = new ArrayList ();
276                         AddSelectorArguments (ec, args, parentParameter, ref parameter, ti);
277
278                         lSide = CreateQueryExpression (lSide, args);
279                         if (next != null) {
280                                 //
281                                 // Parameter identifiers go to the scope
282                                 //
283                                 string[] identifiers;
284                                 if (ti == null) {
285                                         identifiers = new string [] { parentParameter.Name, parameter.Name };
286                                 } else {
287                                         identifiers = new string [] { parameter.Name };
288                                 }
289
290                                 TransparentParameter tp = new TransparentParameter (loc);
291                                 return next.BuildQueryClause (ec, lSide, tp,
292                                         new TransparentIdentifiersScope (ti, tp, identifiers));
293                         }
294
295                         return lSide;
296                 }
297                 
298                 protected override void CloneTo (CloneContext clonectx, Expression target)
299                 {
300                         ARangeVariableQueryClause t = (ARangeVariableQueryClause) target;
301                         if (element_selector != null)
302                                 t.element_selector = element_selector.Clone (clonectx);
303                         base.CloneTo (clonectx, t);
304                 }
305                 
306                 //
307                 // For transparent identifiers, creates an instance of variable expression
308                 //
309                 protected virtual AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
310                 {
311                         return new AnonymousTypeParameter (parameter);
312                 }
313         }
314
315         public class QueryStartClause : AQueryClause
316         {
317                 public QueryStartClause (Expression expr)
318                         : base (expr, expr.Location)
319                 {
320                 }
321
322                 public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
323                 {
324                         return next.BuildQueryClause (ec, expr, parameter, ti);
325                 }
326
327                 public override Expression DoResolve (EmitContext ec)
328                 {
329                         Expression e = BuildQueryClause (ec, null, null, null);
330                         return e.Resolve (ec);
331                 }
332
333                 protected override string MethodName {
334                         get { throw new NotSupportedException (); }
335                 }
336         }
337
338         public class Cast : QueryStartClause
339         {
340                 // We don't have to clone cast type
341                 readonly Expression type_expr;
342
343                 public Cast (Expression type, Expression expr)
344                         : base (expr)
345                 {
346                         this.type_expr = type;
347                 }
348                 
349                 public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
350                 {
351                         lSide = CreateQueryExpression (expr, new TypeArguments (loc, type_expr), null);
352                         if (next != null)
353                                 return next.BuildQueryClause (ec, lSide, parameter, ti);
354
355                         return lSide;
356                 }
357
358                 protected override string MethodName {
359                         get { return "Cast"; }
360                 }
361         }
362
363         public class GroupBy : AQueryClause
364         {
365                 Expression element_selector;
366                 
367                 public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
368                         : base (keySelector, loc)
369                 {
370                         this.element_selector = elementSelector;
371                 }
372
373                 public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
374                 {
375                         ArrayList args = new ArrayList (2);
376                         args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
377
378                         // A query can be optimized when selector is not group by specific
379                         if (!element_selector.Equals (lSide))
380                                 args.Add (CreateSelectorArgument (ec, element_selector, parameter, ti));
381
382                         lSide = CreateQueryExpression (lSide, args);
383                         if (next != null)
384                                 return next.BuildQueryClause (ec, lSide, parameter, ti);
385
386                         return lSide;
387                 }
388         
389                 protected override void CloneTo (CloneContext clonectx, Expression target)
390                 {
391                         GroupBy t = (GroupBy) target;
392                         t.element_selector = element_selector.Clone (clonectx);
393                         base.CloneTo (clonectx, t);
394                 }
395
396                 protected override string MethodName {
397                         get { return "GroupBy"; }
398                 }
399         }
400
401         public class Join : ARangeVariableQueryClause
402         {
403                 Expression projection;
404                 Expression inner_selector, outer_selector;
405
406                 public Join (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector, Location loc)
407                         : base (variable, inner, loc)
408                 {
409                         this.outer_selector = outerSelector;
410                         this.inner_selector = innerSelector;
411                 }
412
413                 protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
414                         ref Parameter parameter, TransparentIdentifiersScope ti)
415                 {
416                         args.Add (new Argument (expr));
417                         args.Add (CreateSelectorArgument (ec, outer_selector, parentParameter, ti));
418                         args.Add (CreateSelectorArgument (ec, inner_selector, parameter, ti));
419
420                         parameter = CreateResultSelectorParameter (parameter);
421                         if (projection == null) {
422                                 ArrayList join_args = new ArrayList (2);
423                                 join_args.Add (new AnonymousTypeParameter (parentParameter));
424                                 join_args.Add (new AnonymousTypeParameter (parameter));
425                                 projection = new AnonymousTypeDeclaration (join_args, (TypeContainer) ec.TypeContainer, loc);
426                         }
427
428                         args.Add (CreateSelectorArgument (ec, projection,
429                                 new Parameter [] { parentParameter, parameter }, ti));
430                 }
431         
432                 protected override void CloneTo (CloneContext clonectx, Expression target)
433                 {
434                         Join t = (Join) target;
435                         t.projection = projection.Clone (clonectx);
436                         t.inner_selector = inner_selector.Clone (clonectx);
437                         t.outer_selector = outer_selector.Clone (clonectx);
438                         base.CloneTo (clonectx, t);
439                 }       
440
441                 protected virtual Parameter CreateResultSelectorParameter (Parameter parameter)
442                 {
443                         return parameter;
444                 }
445
446                 public override AQueryClause Next {
447                         set {
448                                 // Use select as join projection
449                                 if (value is Select) {
450                                         projection = value.expr;
451                                         next = value.next;
452                                         return;
453                                 }
454
455                                 base.Next = value;
456                         }
457                 }
458
459                 protected override string MethodName {
460                         get { return "Join"; }
461                 }
462         }
463
464         public class GroupJoin : Join
465         {
466                 readonly LocatedToken into_variable;
467
468                 public GroupJoin (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector,
469                         LocatedToken into, Location loc)
470                         : base (variable, inner, outerSelector, innerSelector, loc)
471                 {
472                         this.into_variable = into;
473                 }
474
475                 protected override Parameter CreateResultSelectorParameter (Parameter parameter)
476                 {
477                         //
478                         // into variable is used as result selector and it's passed as
479                         // transparent identifiers to the next clause
480                         //
481                         return CreateBlockParameter (into_variable);
482                 }
483
484                 protected override string MethodName {
485                         get { return "GroupJoin"; }
486                 }
487         }
488
489         public class Let : ARangeVariableQueryClause
490         {
491                 class RangeAnonymousTypeParameter : AnonymousTypeParameter
492                 {
493                         readonly Parameter parameter;
494
495                         public RangeAnonymousTypeParameter (Expression initializer, Parameter parameter)
496                                 : base (initializer, parameter.Name, parameter.Location)
497                         {
498                                 this.parameter = parameter;
499                         }
500
501                         public override Expression DoResolve (EmitContext ec)
502                         {
503                                 Expression e = base.DoResolve (ec);
504                                 if (e != null) {
505                                         //
506                                         // Spread resolved initializer type
507                                         //
508                                         parameter.ParameterType = type;
509                                         parameter.Resolve (ec);
510                                 }
511
512                                 return e;
513                         }
514
515                         protected override void Error_InvalidInitializer (Expression initializer)
516                         {
517                                 Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
518                                         Name, initializer.GetSignatureForError ());
519                         }                       
520                 }
521
522                 public Let (LocatedToken variable, Expression expr, Location loc)
523                         : base (variable, expr, loc)
524                 {
525                 }
526
527                 protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
528                         ref Parameter parameter, TransparentIdentifiersScope ti)
529                 {
530                         args.Add (CreateSelectorArgument (ec, element_selector, parentParameter, ti));
531                 }
532
533                 protected override AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
534                 {
535                         return new RangeAnonymousTypeParameter (expr, parameter);
536                 }
537
538                 protected override string MethodName {
539                         get { return "Select"; }
540                 }
541         }
542
543         public class Select : AQueryClause
544         {
545                 public Select (Expression expr, Location loc)
546                         : base (expr, loc)
547                 {
548                 }
549                 
550                 //
551                 // For queries like `from a orderby a select a'
552                 // the projection is transparent and select clause can be safely removed 
553                 //
554                 public bool IsRequired (Parameter parameter)
555                 {
556                         SimpleName sn = expr as SimpleName;
557                         if (sn == null)
558                                 return true;
559
560                         return sn.Name != parameter.Name;
561                 }
562
563                 protected override string MethodName {
564                         get { return "Select"; }
565                 }
566         }
567
568         public class SelectMany : ARangeVariableQueryClause
569         {
570                 public SelectMany (LocatedToken variable, Expression expr)
571                         : base (variable, expr, expr.Location)
572                 {
573                 }
574
575                 protected override string MethodName {
576                         get { return "SelectMany"; }
577                 }
578
579                 public override AQueryClause Next {
580                         set {
581                                 element_selector = value.expr;
582
583                                 // Can be optimized as SelectMany element selector
584                                 if (value is Select)
585                                         return;
586
587                                 next = value;
588                         }
589                 }
590         }
591
592         public class Where : AQueryClause
593         {
594                 public Where (Expression expr, Location loc)
595                         : base (expr, loc)
596                 {
597                 }
598
599                 protected override string MethodName {
600                         get { return "Where"; }
601                 }
602         }
603
604         public class OrderByAscending : AQueryClause
605         {
606                 public OrderByAscending (Expression expr)
607                         : base (expr, expr.Location)
608                 {
609                 }
610
611                 protected override string MethodName {
612                         get { return "OrderBy"; }
613                 }
614         }
615
616         public class OrderByDescending : AQueryClause
617         {
618                 public OrderByDescending (Expression expr)
619                         : base (expr, expr.Location)
620                 {
621                 }
622
623                 protected override string MethodName {
624                         get { return "OrderByDescending"; }
625                 }
626         }
627
628         public class ThenByAscending : OrderByAscending
629         {
630                 public ThenByAscending (Expression expr)
631                         : base (expr)
632                 {
633                 }
634
635                 protected override string MethodName {
636                         get { return "ThenBy"; }
637                 }
638         }
639
640         public class ThenByDescending : OrderByDescending
641         {
642                 public ThenByDescending (Expression expr)
643                         : base (expr)
644                 {
645                 }
646
647                 protected override string MethodName {
648                         get { return "ThenByDescending"; }
649                 }
650         }
651
652         class ImplicitQueryParameter : ImplicitLambdaParameter
653         {
654                 public sealed class ImplicitType : Expression
655                 {
656                         public static ImplicitType Instance = new ImplicitType ();
657
658                         private ImplicitType ()
659                         {
660                         }
661
662                         protected override void CloneTo (CloneContext clonectx, Expression target)
663                         {
664                                 // Nothing to clone
665                         }
666
667                         public override Expression DoResolve (EmitContext ec)
668                         {
669                                 throw new NotSupportedException ();
670                         }
671
672                         public override void Emit (EmitContext ec)
673                         {
674                                 throw new NotSupportedException ();
675                         }
676                 }
677
678                 public ImplicitQueryParameter (LocatedToken variable)
679                         : base (variable.Value, variable.Location)
680                 {
681                 }
682         }
683
684         //
685         // Transparent parameters are used to package up the intermediate results
686         // and pass them onto next clause
687         //
688         public class TransparentParameter : ImplicitLambdaParameter
689         {
690                 static int counter;
691                 const string ParameterNamePrefix = "<>__TranspIdent";
692
693                 public TransparentParameter (Location loc)
694                         : base (ParameterNamePrefix + counter++, loc)
695                 {
696                 }
697         }
698
699         //
700         // Transparent identifiers are stored in nested anonymous types, each type can contain
701         // up to 2 identifiers or 1 identifier and parent type.
702         //
703         public class TransparentIdentifiersScope
704         {
705                 readonly string [] identifiers;
706                 readonly TransparentIdentifiersScope parent;
707                 readonly TransparentParameter parameter;
708
709                 public TransparentIdentifiersScope (TransparentIdentifiersScope parent,
710                         TransparentParameter parameter, string [] identifiers)
711                 {
712                         this.parent = parent;
713                         this.parameter = parameter;
714                         this.identifiers = identifiers;
715                 }
716
717                 public MemberAccess GetIdentifier (string name)
718                 {
719                         TransparentIdentifiersScope ident = FindIdentifier (name);
720                         if (ident == null)
721                                 return null;
722
723                         return new MemberAccess (CreateIdentifierNestingExpression (ident), name);
724                 }
725
726                 TransparentIdentifiersScope FindIdentifier (string name)
727                 {
728                         foreach (string s in identifiers) {
729                                 if (s == name)
730                                         return this;
731                         }
732
733                         if (parent == null)
734                                 return null;
735
736                         return parent.FindIdentifier (name);
737                 }
738
739                 Expression CreateIdentifierNestingExpression (TransparentIdentifiersScope end)
740                 {
741                         Expression expr = new SimpleName (parameter.Name, parameter.Location);
742                         TransparentIdentifiersScope current = this;
743                         while (current != end)
744                         {
745                                 current = current.parent;
746                                 expr = new MemberAccess (expr, current.parameter.Name);
747                         }
748
749                         return expr;
750                 }
751         }
752
753         //
754         // Lambda expression block which contains transparent identifiers
755         //
756         class SelectorBlock : ToplevelBlock
757         {
758                 readonly TransparentIdentifiersScope transparent_identifiers;
759
760                 public SelectorBlock (Block block, Parameters parameters, 
761                         TransparentIdentifiersScope transparentIdentifiers, Location loc)
762                         : base (block, parameters, loc)
763                 {
764                         this.transparent_identifiers = transparentIdentifiers;
765                 }
766
767                 public override Expression GetTransparentIdentifier (string name)
768                 {
769                         Expression expr = null;
770                         if (transparent_identifiers != null)
771                                 expr = transparent_identifiers.GetIdentifier (name);
772
773                         if (expr != null || Container == null)
774                                 return expr;
775                         
776                         return Container.GetTransparentIdentifier (name);
777                 }
778         }
779
780         //
781         // This block is actually never used, it is used by parser only
782         //
783         public class QueryBlock : Block
784         {
785                 Hashtable range_variables = new Hashtable ();
786
787                 public QueryBlock (Block parent, Location start)
788                         : base (parent, start, Location.Null)
789                 {
790                 }
791
792                 protected override void AddVariable (LocalInfo li)
793                 {
794                         string name = li.Name;
795                         if (range_variables.Contains (name)) {
796                                 Location conflict = (Location)range_variables [name];
797                                 Report.SymbolRelatedToPreviousError (conflict, name);
798                                 Error_AlreadyDeclared (li.Location, name);
799                                 return;
800                         }
801
802                         range_variables.Add (name, li.Location);
803                 }
804                 
805                 protected override void Error_AlreadyDeclared (Location loc, string var, string reason)
806                 {
807                         Report.Error (1931, loc, "A range variable `{0}' conflicts with a previous declaration of `{0}'",
808                                 var);
809                 }
810                 
811                 protected override void Error_AlreadyDeclared (Location loc, string var)
812                 {
813                         Report.Error (1930, loc, "A range variable `{0}' has already been declared in this scope",
814                                 var);           
815                 }
816                 
817                 protected override void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
818                 {
819                         Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
820                                 name);
821                 }
822         }
823 }