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