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