Merge pull request #980 from StephenMcConnel/bug-18638
[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 // Copyright 2011 Xamarin Inc
10 //
11
12 using System;
13 using System.Collections.Generic;
14
15 namespace Mono.CSharp.Linq
16 {
17         public class QueryExpression : AQueryClause
18         {
19                 public QueryExpression (AQueryClause start)
20                         : base (null, null, start.Location)
21                 {
22                         this.next = start;
23                 }
24
25                 public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parentParameter)
26                 {
27                         return next.BuildQueryClause (ec, lSide, parentParameter);
28                 }
29
30                 protected override Expression DoResolve (ResolveContext ec)
31                 {
32                         int counter = QueryBlock.TransparentParameter.Counter;
33
34                         Expression e = BuildQueryClause (ec, null, null);
35                         if (e != null)
36                                 e = e.Resolve (ec);
37
38                         //
39                         // Reset counter in probing mode to ensure that all transparent
40                         // identifier anonymous types are created only once
41                         //
42                         if (ec.IsInProbingMode)
43                                 QueryBlock.TransparentParameter.Counter = counter;
44
45                         return e;
46                 }
47
48                 protected override string MethodName {
49                         get { throw new NotSupportedException (); }
50                 }
51         }
52
53         public abstract class AQueryClause : ShimExpression
54         {
55                 protected class QueryExpressionAccess : MemberAccess
56                 {
57                         public QueryExpressionAccess (Expression expr, string methodName, Location loc)
58                                 : base (expr, methodName, loc)
59                         {
60                         }
61
62                         public QueryExpressionAccess (Expression expr, string methodName, TypeArguments typeArguments, Location loc)
63                                 : base (expr, methodName, typeArguments, loc)
64                         {
65                         }
66
67                         public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
68                         {
69                                 ec.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                         }
73                 }
74
75                 protected class QueryExpressionInvocation : Invocation, OverloadResolver.IErrorHandler
76                 {
77                         public QueryExpressionInvocation (QueryExpressionAccess expr, Arguments arguments)
78                                 : base (expr, arguments)
79                         {
80                         }
81
82                         protected override MethodGroupExpr DoResolveOverload (ResolveContext ec)
83                         {
84                                 MethodGroupExpr rmg = mg.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.None);
85                                 return rmg;
86                         }
87
88                         protected override Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
89                         {
90                                 ec.Report.Error (1979, loc,
91                                         "Query expressions with a source or join sequence of type `dynamic' are not allowed");
92                                 return null;
93                         }
94
95                         #region IErrorHandler Members
96
97                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
98                         {
99                                 ec.Report.SymbolRelatedToPreviousError (best);
100                                 ec.Report.SymbolRelatedToPreviousError (ambiguous);
101                                 ec.Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'",
102                                         best.Name, mg.InstanceExpression.GetSignatureForError ());
103                                 return true;
104                         }
105
106                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
107                         {
108                                 return false;
109                         }
110
111                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
112                         {
113                                 return false;
114                         }
115
116                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
117                         {
118                                 var ms = (MethodSpec) best;
119                                 TypeSpec source_type = ms.Parameters.ExtensionMethodType;
120                                 if (source_type != null) {
121                                         Argument a = arguments[0];
122
123                                         if (TypeManager.IsGenericType (source_type) && InflatedTypeSpec.ContainsTypeParameter (source_type)) {
124                                                 TypeInferenceContext tic = new TypeInferenceContext (source_type.TypeArguments);
125                                                 tic.OutputTypeInference (rc, a.Expr, source_type);
126                                                 if (tic.FixAllTypes (rc)) {
127                                                         source_type = source_type.GetDefinition ().MakeGenericType (rc, tic.InferredTypeArguments);
128                                                 }
129                                         }
130
131                                         if (!Convert.ImplicitConversionExists (rc, a.Expr, source_type)) {
132                                                 rc.Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
133                                                         best.Name, a.Type.GetSignatureForError ());
134                                                 return true;
135                                         }
136                                 }
137
138                                 if (best.Name == "SelectMany") {
139                                         rc.Report.Error (1943, loc,
140                                                 "An expression type is incorrect in a subsequent `from' clause in a query expression with source type `{0}'",
141                                                 arguments[0].GetSignatureForError ());
142                                 } else {
143                                         rc.Report.Error (1942, loc,
144                                                 "An expression type in `{0}' clause is incorrect. Type inference failed in the call to `{1}'",
145                                                 best.Name.ToLowerInvariant (), best.Name);
146                                 }
147
148                                 return true;
149                         }
150
151                         #endregion
152                 }
153
154                 public AQueryClause next;
155                 public QueryBlock block;
156
157                 protected AQueryClause (QueryBlock block, Expression expr, Location loc)
158                          : base (expr)
159                 {
160                         this.block = block;
161                         this.loc = loc;
162                 }
163                 
164                 protected override void CloneTo (CloneContext clonectx, Expression target)
165                 {
166                         base.CloneTo (clonectx, target);
167
168                         AQueryClause t = (AQueryClause) target;
169
170                         if (block != null)
171                                 t.block = (QueryBlock) clonectx.LookupBlock (block);
172
173                         if (next != null)
174                                 t.next = (AQueryClause) next.Clone (clonectx);
175                 }
176
177                 protected override Expression DoResolve (ResolveContext ec)
178                 {
179                         return expr.Resolve (ec);
180                 }
181
182                 public virtual Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
183                 {
184                         Arguments args = null;
185                         CreateArguments (ec, parameter, ref args);
186                         lSide = CreateQueryExpression (lSide, args);
187                         if (next != null) {
188                                 parameter = CreateChildrenParameters (parameter);
189
190                                 Select s = next as Select;
191                                 if (s == null || s.IsRequired (parameter))
192                                         return next.BuildQueryClause (ec, lSide, parameter);
193                                         
194                                 // Skip transparent select clause if any clause follows
195                                 if (next.next != null)
196                                         return next.next.BuildQueryClause (ec, lSide, parameter);
197                         }
198
199                         return lSide;
200                 }
201
202                 protected virtual Parameter CreateChildrenParameters (Parameter parameter)
203                 {
204                         // Have to clone the parameter for any children use, it carries block sensitive data
205                         return parameter.Clone ();
206                 }
207
208                 protected virtual void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
209                 {
210                         args = new Arguments (2);
211
212                         LambdaExpression selector = new LambdaExpression (loc);
213
214                         block.SetParameter (parameter);
215                         selector.Block = block;
216                         selector.Block.AddStatement (new ContextualReturn (expr));
217
218                         args.Add (new Argument (selector));
219                 }
220
221                 protected Invocation CreateQueryExpression (Expression lSide, Arguments arguments)
222                 {
223                         return new QueryExpressionInvocation (
224                                 new QueryExpressionAccess (lSide, MethodName, loc), arguments);
225                 }
226
227                 protected abstract string MethodName { get; }
228
229                 public AQueryClause Next {
230                         set {
231                                 next = value;
232                         }
233                 }
234
235                 public AQueryClause Tail {
236                         get {
237                                 return next == null ? this : next.Tail;
238                         }
239                 }
240         }
241
242         //
243         // A query clause with an identifier (range variable)
244         //
245         public abstract class ARangeVariableQueryClause : AQueryClause
246         {
247                 sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter
248                 {
249                         public RangeAnonymousTypeParameter (Expression initializer, RangeVariable parameter)
250                                 : base (initializer, parameter.Name, parameter.Location)
251                         {
252                         }
253
254                         protected override void Error_InvalidInitializer (ResolveContext ec, string initializer)
255                         {
256                                 ec.Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
257                                         Name, initializer);
258                         }
259                 }
260
261                 class RangeParameterReference : ParameterReference
262                 {
263                         Parameter parameter;
264
265                         public RangeParameterReference (Parameter p)
266                                 : base (null, p.Location)
267                         {
268                                 this.parameter = p;
269                         }
270
271                         protected override Expression DoResolve (ResolveContext ec)
272                         {
273                                 pi = ec.CurrentBlock.ParametersBlock.GetParameterInfo (parameter);
274                                 return base.DoResolve (ec);
275                         }
276                 }
277
278                 protected RangeVariable identifier;
279
280                 protected ARangeVariableQueryClause (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
281                         : base (block, expr, loc)
282                 {
283                         this.identifier = identifier;
284                 }
285
286                 public RangeVariable Identifier {
287                         get {
288                                 return identifier;
289                         }
290                 }
291
292                 public FullNamedExpression IdentifierType { get; set; }
293
294                 protected Invocation CreateCastExpression (Expression lSide)
295                 {
296                         return new QueryExpressionInvocation (
297                                 new QueryExpressionAccess (lSide, "Cast", new TypeArguments (IdentifierType), loc), null);
298                 }
299
300                 protected override Parameter CreateChildrenParameters (Parameter parameter)
301                 {
302                         return new QueryBlock.TransparentParameter (parameter.Clone (), GetIntoVariable ());
303                 }
304
305                 protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, RangeVariable name, Expression init)
306                 {
307                         var args = new List<AnonymousTypeParameter> (2);
308
309                         //
310                         // The first argument is the reference to the parameter
311                         //
312                         args.Add (new AnonymousTypeParameter (new RangeParameterReference (parameter), parameter.Name, parameter.Location));
313
314                         //
315                         // The second argument is the linq expression
316                         //
317                         args.Add (new RangeAnonymousTypeParameter (init, name));
318
319                         //
320                         // Create unique anonymous type
321                         //
322                         return new NewAnonymousType (args, rc.MemberContext.CurrentMemberDefinition.Parent, name.Location);
323                 }
324
325                 protected virtual RangeVariable GetIntoVariable ()
326                 {
327                         return identifier;
328                 }
329         }
330
331         public sealed class RangeVariable : INamedBlockVariable
332         {
333                 Block block;
334
335                 public RangeVariable (string name, Location loc)
336                 {
337                         Name = name;
338                         Location = loc;
339                 }
340
341                 #region Properties
342
343                 public Block Block {
344                         get {
345                                 return block;
346                         }
347                         set {
348                                 block = value;
349                         }
350                 }
351
352                 public bool IsDeclared {
353                         get {
354                                 return true;
355                         }
356                 }
357
358                 public bool IsParameter {
359                         get {
360                                 return false;
361                         }
362                 }
363
364                 public Location Location { get; private set; }
365
366                 public string Name { get; private set; }
367
368                 #endregion
369
370                 public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
371                 {
372                         // 
373                         // We know the variable name is somewhere in the scope. This generates
374                         // an access expression from current block
375                         //
376                         var pb = rc.CurrentBlock.ParametersBlock;
377                         while (true) {
378                                 if (pb is QueryBlock) {
379                                         for (int i = pb.Parameters.Count - 1; i >= 0; --i) {
380                                                 var p = pb.Parameters[i];
381                                                 if (p.Name == Name)
382                                                         return pb.GetParameterReference (i, loc);
383
384                                                 Expression expr = null;
385                                                 var tp = p as QueryBlock.TransparentParameter;
386                                                 while (tp != null) {
387                                                         if (expr == null)
388                                                                 expr = pb.GetParameterReference (i, loc);
389                                                         else
390                                                                 expr = new TransparentMemberAccess (expr, tp.Name);
391
392                                                         if (tp.Identifier == Name)
393                                                                 return new TransparentMemberAccess (expr, Name);
394
395                                                         if (tp.Parent.Name == Name)
396                                                                 return new TransparentMemberAccess (expr, Name);
397
398                                                         tp = tp.Parent as QueryBlock.TransparentParameter;
399                                                 }
400                                         }
401                                 }
402
403                                 if (pb == block)
404                                         return null;
405
406                                 pb = pb.Parent.ParametersBlock;
407                         }
408                 }
409         }
410
411         public class QueryStartClause : ARangeVariableQueryClause
412         {
413                 public QueryStartClause (QueryBlock block, Expression expr, RangeVariable identifier, Location loc)
414                         : base (block, identifier, expr, loc)
415                 {
416                         block.AddRangeVariable (identifier);
417                 }
418
419                 public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
420                 {
421                         if (IdentifierType != null)
422                                 expr = CreateCastExpression (expr);
423
424                         if (parameter == null)
425                                 lSide = expr;
426
427                         return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (identifier.Name, identifier.Location));
428                 }
429
430                 protected override Expression DoResolve (ResolveContext ec)
431                 {
432                         Expression e = BuildQueryClause (ec, null, null);
433                         return e.Resolve (ec);
434                 }
435
436                 protected override string MethodName {
437                         get { throw new NotSupportedException (); }
438                 }
439         }
440
441         public class GroupBy : AQueryClause
442         {
443                 Expression element_selector;
444                 QueryBlock element_block;
445
446                 public GroupBy (QueryBlock block, Expression elementSelector, QueryBlock elementBlock, Expression keySelector, Location loc)
447                         : base (block, keySelector, loc)
448                 {
449                         //
450                         // Optimizes clauses like `group A by A'
451                         //
452                         if (!elementSelector.Equals (keySelector)) {
453                                 this.element_selector = elementSelector;
454                                 this.element_block = elementBlock;
455                         }
456                 }
457
458                 public Expression SelectorExpression {
459                         get {
460                                 return element_selector;
461                         }
462                 }
463
464                 protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
465                 {
466                         base.CreateArguments (ec, parameter, ref args);
467
468                         if (element_selector != null) {
469                                 LambdaExpression lambda = new LambdaExpression (element_selector.Location);
470
471                                 element_block.SetParameter (parameter.Clone ());
472                                 lambda.Block = element_block;
473                                 lambda.Block.AddStatement (new ContextualReturn (element_selector));
474                                 args.Add (new Argument (lambda));
475                         }
476                 }
477
478                 protected override void CloneTo (CloneContext clonectx, Expression target)
479                 {
480                         GroupBy t = (GroupBy) target;
481                         if (element_selector != null) {
482                                 t.element_selector = element_selector.Clone (clonectx);
483                                 t.element_block = (QueryBlock) element_block.Clone (clonectx);
484                         }
485
486                         base.CloneTo (clonectx, t);
487                 }
488
489                 protected override string MethodName {
490                         get { return "GroupBy"; }
491                 }
492                 
493                 public override object Accept (StructuralVisitor visitor)
494                 {
495                         return visitor.Visit (this);
496                 }
497         }
498
499         public class Join : SelectMany
500         {
501                 QueryBlock inner_selector, outer_selector;
502
503                 public Join (QueryBlock block, RangeVariable lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc)
504                         : base (block, lt, inner, loc)
505                 {
506                         this.outer_selector = outerSelector;
507                         this.inner_selector = innerSelector;
508                 }
509
510                 public QueryBlock InnerSelector {
511                         get {
512                                 return inner_selector;
513                         }
514                 }
515                 
516                 public QueryBlock OuterSelector {
517                         get {
518                                 return outer_selector;
519                         }
520                 }
521
522                 protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
523                 {
524                         args = new Arguments (4);
525
526                         if (IdentifierType != null)
527                                 expr = CreateCastExpression (expr);
528
529                         args.Add (new Argument (expr));
530
531                         outer_selector.SetParameter (parameter.Clone ());
532                         var lambda = new LambdaExpression (outer_selector.StartLocation);
533                         lambda.Block = outer_selector;
534                         args.Add (new Argument (lambda));
535
536                         inner_selector.SetParameter (new ImplicitLambdaParameter (identifier.Name, identifier.Location));
537                         lambda = new LambdaExpression (inner_selector.StartLocation);
538                         lambda.Block = inner_selector;
539                         args.Add (new Argument (lambda));
540
541                         base.CreateArguments (ec, parameter, ref args);
542                 }
543
544                 protected override void CloneTo (CloneContext clonectx, Expression target)
545                 {
546                         Join t = (Join) target;
547                         t.inner_selector = (QueryBlock) inner_selector.Clone (clonectx);
548                         t.outer_selector = (QueryBlock) outer_selector.Clone (clonectx);
549                         base.CloneTo (clonectx, t);
550                 }       
551
552                 protected override string MethodName {
553                         get { return "Join"; }
554                 }
555                 
556                 public override object Accept (StructuralVisitor visitor)
557                 {
558                         return visitor.Visit (this);
559                 }
560         }
561
562         public class GroupJoin : Join
563         {
564                 readonly RangeVariable into;
565
566                 public GroupJoin (QueryBlock block, RangeVariable lt, Expression inner,
567                         QueryBlock outerSelector, QueryBlock innerSelector, RangeVariable into, Location loc)
568                         : base (block, lt, inner, outerSelector, innerSelector, loc)
569                 {
570                         this.into = into;
571                 }
572
573                 protected override RangeVariable GetIntoVariable ()
574                 {
575                         return into;
576                 }
577
578                 protected override string MethodName {
579                         get { return "GroupJoin"; }
580                 }
581                 
582                 public override object Accept (StructuralVisitor visitor)
583                 {
584                         return visitor.Visit (this);
585                 }
586         }
587
588         public class Let : ARangeVariableQueryClause
589         {
590                 public Let (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
591                         : base (block, identifier, expr, loc)
592                 {
593                 }
594
595                 protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
596                 {
597                         expr = CreateRangeVariableType (ec, parameter, identifier, expr);
598                         base.CreateArguments (ec, parameter, ref args);
599                 }
600
601                 protected override string MethodName {
602                         get { return "Select"; }
603                 }
604                 
605                 public override object Accept (StructuralVisitor visitor)
606                 {
607                         return visitor.Visit (this);
608                 }
609         }
610
611         public class Select : AQueryClause
612         {
613                 public Select (QueryBlock block, Expression expr, Location loc)
614                         : base (block, expr, loc)
615                 {
616                 }
617                 
618                 //
619                 // For queries like `from a orderby a select a'
620                 // the projection is transparent and select clause can be safely removed 
621                 //
622                 public bool IsRequired (Parameter parameter)
623                 {
624                         SimpleName sn = expr as SimpleName;
625                         if (sn == null)
626                                 return true;
627
628                         return sn.Name != parameter.Name;
629                 }
630
631                 protected override string MethodName {
632                         get { return "Select"; }
633                 }
634                 
635                 public override object Accept (StructuralVisitor visitor)
636                 {
637                         return visitor.Visit (this);
638                 }
639
640         }
641
642         public class SelectMany : ARangeVariableQueryClause
643         {
644                 public SelectMany (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
645                         : base (block, identifier, expr, loc)
646                 {
647                 }
648
649                 protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
650                 {
651                         if (args == null) {
652                                 if (IdentifierType != null)
653                                         expr = CreateCastExpression (expr);
654
655                                 base.CreateArguments (ec, parameter.Clone (), ref args);
656                         }
657
658                         Expression result_selector_expr;
659                         QueryBlock result_block;
660
661                         var target = GetIntoVariable ();
662                         var target_param = new ImplicitLambdaParameter (target.Name, target.Location);
663
664                         //
665                         // When select follows use it as a result selector
666                         //
667                         if (next is Select) {
668                                 result_selector_expr = next.Expr;
669
670                                 result_block = next.block;
671                                 result_block.SetParameters (parameter, target_param);
672
673                                 next = next.next;
674                         } else {
675                                 result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Name, target.Location));
676
677                                 result_block = new QueryBlock (block.Parent, block.StartLocation);
678                                 result_block.SetParameters (parameter, target_param);
679                         }
680
681                         LambdaExpression result_selector = new LambdaExpression (Location);
682                         result_selector.Block = result_block;
683                         result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr));
684
685                         args.Add (new Argument (result_selector));
686                 }
687
688                 protected override string MethodName {
689                         get { return "SelectMany"; }
690                 }
691
692                 public override object Accept (StructuralVisitor visitor)
693                 {
694                         return visitor.Visit (this);
695                 }
696         }
697
698         public class Where : AQueryClause
699         {
700                 public Where (QueryBlock block, Expression expr, Location loc)
701                         : base (block, expr, loc)
702                 {
703                 }
704
705                 protected override string MethodName {
706                         get { return "Where"; }
707                 }
708
709                 public override object Accept (StructuralVisitor visitor)
710                 {
711                         return visitor.Visit (this);
712                 }
713         }
714
715         public class OrderByAscending : AQueryClause
716         {
717                 public OrderByAscending (QueryBlock block, Expression expr)
718                         : base (block, expr, expr.Location)
719                 {
720                 }
721
722                 protected override string MethodName {
723                         get { return "OrderBy"; }
724                 }
725
726                 public override object Accept (StructuralVisitor visitor)
727                 {
728                         return visitor.Visit (this);
729                 }
730         }
731
732         public class OrderByDescending : AQueryClause
733         {
734                 public OrderByDescending (QueryBlock block, Expression expr)
735                         : base (block, expr, expr.Location)
736                 {
737                 }
738
739                 protected override string MethodName {
740                         get { return "OrderByDescending"; }
741                 }
742
743                 public override object Accept (StructuralVisitor visitor)
744                 {
745                         return visitor.Visit (this);
746                 }
747         }
748
749         public class ThenByAscending : OrderByAscending
750         {
751                 public ThenByAscending (QueryBlock block, Expression expr)
752                         : base (block, expr)
753                 {
754                 }
755
756                 protected override string MethodName {
757                         get { return "ThenBy"; }
758                 }
759
760                 public override object Accept (StructuralVisitor visitor)
761                 {
762                         return visitor.Visit (this);
763                 }
764         }
765
766         public class ThenByDescending : OrderByDescending
767         {
768                 public ThenByDescending (QueryBlock block, Expression expr)
769                         : base (block, expr)
770                 {
771                 }
772
773                 protected override string MethodName {
774                         get { return "ThenByDescending"; }
775                 }
776
777                 public override object Accept (StructuralVisitor visitor)
778                 {
779                         return visitor.Visit (this);
780                 }
781         }
782
783         //
784         // Implicit query block
785         //
786         public class QueryBlock : ParametersBlock
787         {
788                 //
789                 // Transparent parameters are used to package up the intermediate results
790                 // and pass them onto next clause
791                 //
792                 public sealed class TransparentParameter : ImplicitLambdaParameter
793                 {
794                         public static int Counter;
795                         const string ParameterNamePrefix = "<>__TranspIdent";
796
797                         public readonly Parameter Parent;
798                         public readonly string Identifier;
799
800                         public TransparentParameter (Parameter parent, RangeVariable identifier)
801                                 : base (ParameterNamePrefix + Counter++, identifier.Location)
802                         {
803                                 Parent = parent;
804                                 Identifier = identifier.Name;
805                         }
806
807                         public static void Reset ()
808                         {
809                                 Counter = 0;
810                         }
811                 }
812
813                 public QueryBlock (Block parent, Location start)
814                         : base (parent, ParametersCompiled.EmptyReadOnlyParameters, start, Flags.CompilerGenerated)
815                 {
816                 }
817
818                 public void AddRangeVariable (RangeVariable variable)
819                 {
820                         variable.Block = this;
821                         TopBlock.AddLocalName (variable.Name, variable, true);
822                 }
823
824                 public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
825                 {
826                         TopBlock.Report.Error (1931, variable.Location,
827                                 "A range variable `{0}' conflicts with a previous declaration of `{0}'",
828                                 name);
829                 }
830
831                 public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
832                 {
833                         TopBlock.Report.Error (1930, variable.Location,
834                                 "A range variable `{0}' has already been declared in this scope",
835                                 name);          
836                 }
837
838                 public override void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
839                 {
840                         TopBlock.Report.Error (1948, loc,
841                                 "A range variable `{0}' conflicts with a method type parameter",
842                                 name);
843                 }
844
845                 public void SetParameter (Parameter parameter)
846                 {
847                         base.parameters = new ParametersCompiled (parameter);
848                         base.parameter_info = new ParameterInfo[] {
849                                 new ParameterInfo (this, 0)
850                         };
851                 }
852
853                 public void SetParameters (Parameter first, Parameter second)
854                 {
855                         base.parameters = new ParametersCompiled (first, second);
856                         base.parameter_info = new ParameterInfo[] {
857                                 new ParameterInfo (this, 0),
858                                 new ParameterInfo (this, 1)
859                         };
860                 }
861         }
862
863         sealed class TransparentMemberAccess : MemberAccess
864         {
865                 public TransparentMemberAccess (Expression expr, string name)
866                         : base (expr, name)
867                 {
868                 }
869
870                 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
871                 {
872                         rc.Report.Error (1947, loc,
873                                 "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
874                                 Name);
875
876                         return null;
877                 }
878         }
879 }