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