~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/mcs/statement.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// statement.cs: Statement representation for the IL tree.
 
3
//
 
4
// Author:
 
5
//   Miguel de Icaza (miguel@ximian.com)
 
6
//   Martin Baulig (martin@ximian.com)
 
7
//   Marek Safar (marek.safar@seznam.cz)
 
8
//
 
9
// Copyright 2001, 2002, 2003 Ximian, Inc.
 
10
// Copyright 2003, 2004 Novell, Inc.
 
11
//
 
12
 
 
13
using System;
 
14
using System.Collections.Generic;
 
15
 
 
16
#if STATIC
 
17
using IKVM.Reflection.Emit;
 
18
#else
 
19
using System.Reflection.Emit;
 
20
#endif
 
21
 
 
22
namespace Mono.CSharp {
 
23
        
 
24
        public abstract class Statement {
 
25
                public Location loc;
 
26
                
 
27
                /// <summary>
 
28
                ///   Resolves the statement, true means that all sub-statements
 
29
                ///   did resolve ok.
 
30
                //  </summary>
 
31
                public virtual bool Resolve (BlockContext ec)
 
32
                {
 
33
                        return true;
 
34
                }
 
35
 
 
36
                /// <summary>
 
37
                ///   We already know that the statement is unreachable, but we still
 
38
                ///   need to resolve it to catch errors.
 
39
                /// </summary>
 
40
                public virtual bool ResolveUnreachable (BlockContext ec, bool warn)
 
41
                {
 
42
                        //
 
43
                        // This conflicts with csc's way of doing this, but IMHO it's
 
44
                        // the right thing to do.
 
45
                        //
 
46
                        // If something is unreachable, we still check whether it's
 
47
                        // correct.  This means that you cannot use unassigned variables
 
48
                        // in unreachable code, for instance.
 
49
                        //
 
50
 
 
51
                        if (warn)
 
52
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
 
53
 
 
54
                        ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
 
55
                        bool ok = Resolve (ec);
 
56
                        ec.KillFlowBranching ();
 
57
 
 
58
                        return ok;
 
59
                }
 
60
                                
 
61
                /// <summary>
 
62
                ///   Return value indicates whether all code paths emitted return.
 
63
                /// </summary>
 
64
                protected abstract void DoEmit (EmitContext ec);
 
65
 
 
66
                public virtual void Emit (EmitContext ec)
 
67
                {
 
68
                        ec.Mark (loc);
 
69
                        DoEmit (ec);
 
70
                }
 
71
 
 
72
                //
 
73
                // This routine must be overrided in derived classes and make copies
 
74
                // of all the data that might be modified if resolved
 
75
                // 
 
76
                protected abstract void CloneTo (CloneContext clonectx, Statement target);
 
77
 
 
78
                public Statement Clone (CloneContext clonectx)
 
79
                {
 
80
                        Statement s = (Statement) this.MemberwiseClone ();
 
81
                        CloneTo (clonectx, s);
 
82
                        return s;
 
83
                }
 
84
 
 
85
                public virtual Expression CreateExpressionTree (ResolveContext ec)
 
86
                {
 
87
                        ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
 
88
                        return null;
 
89
                }
 
90
                
 
91
                public virtual object Accept (StructuralVisitor visitor)
 
92
                {
 
93
                        return visitor.Visit (this);
 
94
                }
 
95
        }
 
96
 
 
97
        public sealed class EmptyStatement : Statement
 
98
        {
 
99
                public EmptyStatement (Location loc)
 
100
                {
 
101
                        this.loc = loc;
 
102
                }
 
103
                
 
104
                public override bool Resolve (BlockContext ec)
 
105
                {
 
106
                        return true;
 
107
                }
 
108
 
 
109
                public override bool ResolveUnreachable (BlockContext ec, bool warn)
 
110
                {
 
111
                        return true;
 
112
                }
 
113
 
 
114
                public override void Emit (EmitContext ec)
 
115
                {
 
116
                }
 
117
 
 
118
                protected override void DoEmit (EmitContext ec)
 
119
                {
 
120
                        throw new NotSupportedException ();
 
121
                }
 
122
 
 
123
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
124
                {
 
125
                        // nothing needed.
 
126
                }
 
127
                
 
128
                public override object Accept (StructuralVisitor visitor)
 
129
                {
 
130
                        return visitor.Visit (this);
 
131
                }
 
132
        }
 
133
        
 
134
        public class If : Statement {
 
135
                Expression expr;
 
136
                public Statement TrueStatement;
 
137
                public Statement FalseStatement;
 
138
 
 
139
                bool is_true_ret;
 
140
 
 
141
                public If (Expression bool_expr, Statement true_statement, Location l)
 
142
                        : this (bool_expr, true_statement, null, l)
 
143
                {
 
144
                }
 
145
 
 
146
                public If (Expression bool_expr,
 
147
                           Statement true_statement,
 
148
                           Statement false_statement,
 
149
                           Location l)
 
150
                {
 
151
                        this.expr = bool_expr;
 
152
                        TrueStatement = true_statement;
 
153
                        FalseStatement = false_statement;
 
154
                        loc = l;
 
155
                }
 
156
                
 
157
                public Expression Expr {
 
158
                        get { return this.expr; }
 
159
                }
 
160
                
 
161
                public override bool Resolve (BlockContext ec)
 
162
                {
 
163
                        bool ok = true;
 
164
 
 
165
                        expr = expr.Resolve (ec);
 
166
                        if (expr == null) {
 
167
                                ok = false;
 
168
                        } else {
 
169
                                //
 
170
                                // Dead code elimination
 
171
                                //
 
172
                                if (expr is Constant) {
 
173
                                        bool take = !((Constant) expr).IsDefaultValue;
 
174
 
 
175
                                        if (take) {
 
176
                                                if (!TrueStatement.Resolve (ec))
 
177
                                                        return false;
 
178
 
 
179
                                                if ((FalseStatement != null) &&
 
180
                                                        !FalseStatement.ResolveUnreachable (ec, true))
 
181
                                                        return false;
 
182
                                                FalseStatement = null;
 
183
                                        } else {
 
184
                                                if (!TrueStatement.ResolveUnreachable (ec, true))
 
185
                                                        return false;
 
186
                                                TrueStatement = null;
 
187
 
 
188
                                                if ((FalseStatement != null) &&
 
189
                                                        !FalseStatement.Resolve (ec))
 
190
                                                        return false;
 
191
                                        }
 
192
 
 
193
                                        return true;
 
194
                                }
 
195
                        }
 
196
 
 
197
                        ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
 
198
                        
 
199
                        ok &= TrueStatement.Resolve (ec);
 
200
 
 
201
                        is_true_ret = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
202
 
 
203
                        ec.CurrentBranching.CreateSibling ();
 
204
 
 
205
                        if (FalseStatement != null)
 
206
                                ok &= FalseStatement.Resolve (ec);
 
207
                                        
 
208
                        ec.EndFlowBranching ();
 
209
 
 
210
                        return ok;
 
211
                }
 
212
                
 
213
                protected override void DoEmit (EmitContext ec)
 
214
                {
 
215
                        Label false_target = ec.DefineLabel ();
 
216
                        Label end;
 
217
 
 
218
                        //
 
219
                        // If we're a boolean constant, Resolve() already
 
220
                        // eliminated dead code for us.
 
221
                        //
 
222
                        Constant c = expr as Constant;
 
223
                        if (c != null){
 
224
                                c.EmitSideEffect (ec);
 
225
 
 
226
                                if (!c.IsDefaultValue)
 
227
                                        TrueStatement.Emit (ec);
 
228
                                else if (FalseStatement != null)
 
229
                                        FalseStatement.Emit (ec);
 
230
 
 
231
                                return;
 
232
                        }                       
 
233
                        
 
234
                        expr.EmitBranchable (ec, false_target, false);
 
235
                        
 
236
                        TrueStatement.Emit (ec);
 
237
 
 
238
                        if (FalseStatement != null){
 
239
                                bool branch_emitted = false;
 
240
                                
 
241
                                end = ec.DefineLabel ();
 
242
                                if (!is_true_ret){
 
243
                                        ec.Emit (OpCodes.Br, end);
 
244
                                        branch_emitted = true;
 
245
                                }
 
246
 
 
247
                                ec.MarkLabel (false_target);
 
248
                                FalseStatement.Emit (ec);
 
249
 
 
250
                                if (branch_emitted)
 
251
                                        ec.MarkLabel (end);
 
252
                        } else {
 
253
                                ec.MarkLabel (false_target);
 
254
                        }
 
255
                }
 
256
 
 
257
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
258
                {
 
259
                        If target = (If) t;
 
260
 
 
261
                        target.expr = expr.Clone (clonectx);
 
262
                        target.TrueStatement = TrueStatement.Clone (clonectx);
 
263
                        if (FalseStatement != null)
 
264
                                target.FalseStatement = FalseStatement.Clone (clonectx);
 
265
                }
 
266
                
 
267
                public override object Accept (StructuralVisitor visitor)
 
268
                {
 
269
                        return visitor.Visit (this);
 
270
                }
 
271
        }
 
272
 
 
273
        public class Do : Statement {
 
274
                public Expression expr;
 
275
                public Statement  EmbeddedStatement;
 
276
 
 
277
                public Do (Statement statement, BooleanExpression bool_expr, Location l)
 
278
                {
 
279
                        expr = bool_expr;
 
280
                        EmbeddedStatement = statement;
 
281
                        loc = l;
 
282
                }
 
283
 
 
284
                public override bool Resolve (BlockContext ec)
 
285
                {
 
286
                        bool ok = true;
 
287
 
 
288
                        ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
289
 
 
290
                        bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
291
 
 
292
                        ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
 
293
                        if (!EmbeddedStatement.Resolve (ec))
 
294
                                ok = false;
 
295
                        ec.EndFlowBranching ();
 
296
 
 
297
                        if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
 
298
                                ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected");
 
299
 
 
300
                        expr = expr.Resolve (ec);
 
301
                        if (expr == null)
 
302
                                ok = false;
 
303
                        else if (expr is Constant){
 
304
                                bool infinite = !((Constant) expr).IsDefaultValue;
 
305
                                if (infinite)
 
306
                                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
307
                        }
 
308
 
 
309
                        ec.EndFlowBranching ();
 
310
 
 
311
                        return ok;
 
312
                }
 
313
                
 
314
                protected override void DoEmit (EmitContext ec)
 
315
                {
 
316
                        Label loop = ec.DefineLabel ();
 
317
                        Label old_begin = ec.LoopBegin;
 
318
                        Label old_end = ec.LoopEnd;
 
319
                        
 
320
                        ec.LoopBegin = ec.DefineLabel ();
 
321
                        ec.LoopEnd = ec.DefineLabel ();
 
322
                                
 
323
                        ec.MarkLabel (loop);
 
324
                        EmbeddedStatement.Emit (ec);
 
325
                        ec.MarkLabel (ec.LoopBegin);
 
326
 
 
327
                        //
 
328
                        // Dead code elimination
 
329
                        //
 
330
                        if (expr is Constant){
 
331
                                bool res = !((Constant) expr).IsDefaultValue;
 
332
 
 
333
                                expr.EmitSideEffect (ec);
 
334
                                if (res)
 
335
                                        ec.Emit (OpCodes.Br, loop); 
 
336
                        } else
 
337
                                expr.EmitBranchable (ec, loop, true);
 
338
                        
 
339
                        ec.MarkLabel (ec.LoopEnd);
 
340
 
 
341
                        ec.LoopBegin = old_begin;
 
342
                        ec.LoopEnd = old_end;
 
343
                }
 
344
 
 
345
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
346
                {
 
347
                        Do target = (Do) t;
 
348
 
 
349
                        target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
 
350
                        target.expr = expr.Clone (clonectx);
 
351
                }
 
352
                
 
353
                public override object Accept (StructuralVisitor visitor)
 
354
                {
 
355
                        return visitor.Visit (this);
 
356
                }
 
357
        }
 
358
 
 
359
        public class While : Statement {
 
360
                public Expression expr;
 
361
                public Statement Statement;
 
362
                bool infinite, empty;
 
363
 
 
364
                public While (BooleanExpression bool_expr, Statement statement, Location l)
 
365
                {
 
366
                        this.expr = bool_expr;
 
367
                        Statement = statement;
 
368
                        loc = l;
 
369
                }
 
370
 
 
371
                public override bool Resolve (BlockContext ec)
 
372
                {
 
373
                        bool ok = true;
 
374
 
 
375
                        expr = expr.Resolve (ec);
 
376
                        if (expr == null)
 
377
                                ok = false;
 
378
 
 
379
                        //
 
380
                        // Inform whether we are infinite or not
 
381
                        //
 
382
                        if (expr is Constant){
 
383
                                bool value = !((Constant) expr).IsDefaultValue;
 
384
 
 
385
                                if (value == false){
 
386
                                        if (!Statement.ResolveUnreachable (ec, true))
 
387
                                                return false;
 
388
                                        empty = true;
 
389
                                        return true;
 
390
                                } else
 
391
                                        infinite = true;
 
392
                        }
 
393
 
 
394
                        ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
395
                        if (!infinite)
 
396
                                ec.CurrentBranching.CreateSibling ();
 
397
 
 
398
                        ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
 
399
                        if (!Statement.Resolve (ec))
 
400
                                ok = false;
 
401
                        ec.EndFlowBranching ();
 
402
 
 
403
                        // There's no direct control flow from the end of the embedded statement to the end of the loop
 
404
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
405
 
 
406
                        ec.EndFlowBranching ();
 
407
 
 
408
                        return ok;
 
409
                }
 
410
                
 
411
                protected override void DoEmit (EmitContext ec)
 
412
                {
 
413
                        if (empty) {
 
414
                                expr.EmitSideEffect (ec);
 
415
                                return;
 
416
                        }
 
417
 
 
418
                        Label old_begin = ec.LoopBegin;
 
419
                        Label old_end = ec.LoopEnd;
 
420
                        
 
421
                        ec.LoopBegin = ec.DefineLabel ();
 
422
                        ec.LoopEnd = ec.DefineLabel ();
 
423
 
 
424
                        //
 
425
                        // Inform whether we are infinite or not
 
426
                        //
 
427
                        if (expr is Constant){
 
428
                                // expr is 'true', since the 'empty' case above handles the 'false' case
 
429
                                ec.MarkLabel (ec.LoopBegin);
 
430
                                expr.EmitSideEffect (ec);
 
431
                                Statement.Emit (ec);
 
432
                                ec.Emit (OpCodes.Br, ec.LoopBegin);
 
433
                                        
 
434
                                //
 
435
                                // Inform that we are infinite (ie, `we return'), only
 
436
                                // if we do not `break' inside the code.
 
437
                                //
 
438
                                ec.MarkLabel (ec.LoopEnd);
 
439
                        } else {
 
440
                                Label while_loop = ec.DefineLabel ();
 
441
 
 
442
                                ec.Emit (OpCodes.Br, ec.LoopBegin);
 
443
                                ec.MarkLabel (while_loop);
 
444
 
 
445
                                Statement.Emit (ec);
 
446
                        
 
447
                                ec.MarkLabel (ec.LoopBegin);
 
448
                                ec.Mark (loc);
 
449
 
 
450
                                expr.EmitBranchable (ec, while_loop, true);
 
451
                                
 
452
                                ec.MarkLabel (ec.LoopEnd);
 
453
                        }       
 
454
 
 
455
                        ec.LoopBegin = old_begin;
 
456
                        ec.LoopEnd = old_end;
 
457
                }
 
458
 
 
459
                public override void Emit (EmitContext ec)
 
460
                {
 
461
                        DoEmit (ec);
 
462
                }
 
463
 
 
464
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
465
                {
 
466
                        While target = (While) t;
 
467
 
 
468
                        target.expr = expr.Clone (clonectx);
 
469
                        target.Statement = Statement.Clone (clonectx);
 
470
                }
 
471
                
 
472
                public override object Accept (StructuralVisitor visitor)
 
473
                {
 
474
                        return visitor.Visit (this);
 
475
                }
 
476
        }
 
477
 
 
478
        public class For : Statement {
 
479
                public Expression Test { get; private set; }
 
480
                public Statement InitStatement { get; private set; }
 
481
                public Statement Increment { get; private set; }
 
482
                public Statement Statement { get; private set; }
 
483
                bool infinite, empty;
 
484
                
 
485
                public For (Statement init_statement,
 
486
                            BooleanExpression test,
 
487
                            Statement increment,
 
488
                            Statement statement,
 
489
                            Location l)
 
490
                {
 
491
                        InitStatement = init_statement;
 
492
                        Test = test;
 
493
                        Increment = increment;
 
494
                        Statement = statement;
 
495
                        loc = l;
 
496
                }
 
497
 
 
498
                public override bool Resolve (BlockContext ec)
 
499
                {
 
500
                        bool ok = true;
 
501
 
 
502
                        if (InitStatement != null){
 
503
                                if (!InitStatement.Resolve (ec))
 
504
                                        ok = false;
 
505
                        }
 
506
 
 
507
                        if (Test != null){
 
508
                                Test = Test.Resolve (ec);
 
509
                                if (Test == null)
 
510
                                        ok = false;
 
511
                                else if (Test is Constant){
 
512
                                        bool value = !((Constant) Test).IsDefaultValue;
 
513
 
 
514
                                        if (value == false){
 
515
                                                if (!Statement.ResolveUnreachable (ec, true))
 
516
                                                        return false;
 
517
                                                if ((Increment != null) &&
 
518
                                                    !Increment.ResolveUnreachable (ec, false))
 
519
                                                        return false;
 
520
                                                empty = true;
 
521
                                                return true;
 
522
                                        } else
 
523
                                                infinite = true;
 
524
                                }
 
525
                        } else
 
526
                                infinite = true;
 
527
 
 
528
                        ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
529
                        if (!infinite)
 
530
                                ec.CurrentBranching.CreateSibling ();
 
531
 
 
532
                        bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
533
 
 
534
                        ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
 
535
                        if (!Statement.Resolve (ec))
 
536
                                ok = false;
 
537
                        ec.EndFlowBranching ();
 
538
 
 
539
                        if (Increment != null){
 
540
                                if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
 
541
                                        if (!Increment.ResolveUnreachable (ec, !was_unreachable))
 
542
                                                ok = false;
 
543
                                } else {
 
544
                                        if (!Increment.Resolve (ec))
 
545
                                                ok = false;
 
546
                                }
 
547
                        }
 
548
 
 
549
                        // There's no direct control flow from the end of the embedded statement to the end of the loop
 
550
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
551
 
 
552
                        ec.EndFlowBranching ();
 
553
 
 
554
                        return ok;
 
555
                }
 
556
 
 
557
                protected override void DoEmit (EmitContext ec)
 
558
                {
 
559
                        if (InitStatement != null)
 
560
                                InitStatement.Emit (ec);
 
561
 
 
562
                        if (empty) {
 
563
                                Test.EmitSideEffect (ec);
 
564
                                return;
 
565
                        }
 
566
 
 
567
                        Label old_begin = ec.LoopBegin;
 
568
                        Label old_end = ec.LoopEnd;
 
569
                        Label loop = ec.DefineLabel ();
 
570
                        Label test = ec.DefineLabel ();
 
571
 
 
572
                        ec.LoopBegin = ec.DefineLabel ();
 
573
                        ec.LoopEnd = ec.DefineLabel ();
 
574
 
 
575
                        ec.Emit (OpCodes.Br, test);
 
576
                        ec.MarkLabel (loop);
 
577
                        Statement.Emit (ec);
 
578
 
 
579
                        ec.MarkLabel (ec.LoopBegin);
 
580
                        Increment.Emit (ec);
 
581
 
 
582
                        ec.MarkLabel (test);
 
583
                        //
 
584
                        // If test is null, there is no test, and we are just
 
585
                        // an infinite loop
 
586
                        //
 
587
                        if (Test != null){
 
588
                                //
 
589
                                // The Resolve code already catches the case for
 
590
                                // Test == Constant (false) so we know that
 
591
                                // this is true
 
592
                                //
 
593
                                if (Test is Constant) {
 
594
                                        Test.EmitSideEffect (ec);
 
595
                                        ec.Emit (OpCodes.Br, loop);
 
596
                                } else {
 
597
                                        Test.EmitBranchable (ec, loop, true);
 
598
                                }
 
599
                                
 
600
                        } else
 
601
                                ec.Emit (OpCodes.Br, loop);
 
602
                        ec.MarkLabel (ec.LoopEnd);
 
603
 
 
604
                        ec.LoopBegin = old_begin;
 
605
                        ec.LoopEnd = old_end;
 
606
                }
 
607
 
 
608
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
609
                {
 
610
                        For target = (For) t;
 
611
 
 
612
                        if (InitStatement != null)
 
613
                                target.InitStatement = InitStatement.Clone (clonectx);
 
614
                        if (Test != null)
 
615
                                target.Test = Test.Clone (clonectx);
 
616
                        if (Increment != null)
 
617
                                target.Increment = Increment.Clone (clonectx);
 
618
                        target.Statement = Statement.Clone (clonectx);
 
619
                }
 
620
                
 
621
                public override object Accept (StructuralVisitor visitor)
 
622
                {
 
623
                        return visitor.Visit (this);
 
624
                }
 
625
        }
 
626
        
 
627
        public class StatementExpression : Statement {
 
628
                ExpressionStatement expr;
 
629
                
 
630
                public StatementExpression (ExpressionStatement expr)
 
631
                {
 
632
                        this.expr = expr;
 
633
                        loc = expr.Location;
 
634
                }
 
635
                
 
636
                public ExpressionStatement Expr {
 
637
                        get { return this.expr; }
 
638
                }
 
639
                
 
640
                public override bool Resolve (BlockContext ec)
 
641
                {
 
642
                        expr = expr.ResolveStatement (ec);
 
643
                        return expr != null;
 
644
                }
 
645
                
 
646
                protected override void DoEmit (EmitContext ec)
 
647
                {
 
648
                        expr.EmitStatement (ec);
 
649
                }
 
650
 
 
651
                public override string ToString ()
 
652
                {
 
653
                        return "StatementExpression (" + expr + ")";
 
654
                }
 
655
 
 
656
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
657
                {
 
658
                        StatementExpression target = (StatementExpression) t;
 
659
 
 
660
                        target.expr = (ExpressionStatement) expr.Clone (clonectx);
 
661
                }
 
662
                
 
663
                public override object Accept (StructuralVisitor visitor)
 
664
                {
 
665
                        return visitor.Visit (this);
 
666
                }
 
667
        }
 
668
 
 
669
        //
 
670
        // Simple version of statement list not requiring a block
 
671
        //
 
672
        public class StatementList : Statement
 
673
        {
 
674
                List<Statement> statements;
 
675
 
 
676
                public StatementList (Statement first, Statement second)
 
677
                {
 
678
                        statements = new List<Statement> () { first, second };
 
679
                }
 
680
 
 
681
                #region Properties
 
682
                public IList<Statement> Statements {
 
683
                        get {
 
684
                                return statements;
 
685
                        }
 
686
                }
 
687
                #endregion
 
688
 
 
689
                public void Add (Statement statement)
 
690
                {
 
691
                        statements.Add (statement);
 
692
                }
 
693
 
 
694
                public override bool Resolve (BlockContext ec)
 
695
                {
 
696
                        foreach (var s in statements)
 
697
                                s.Resolve (ec);
 
698
 
 
699
                        return true;
 
700
                }
 
701
 
 
702
                protected override void DoEmit (EmitContext ec)
 
703
                {
 
704
                        foreach (var s in statements)
 
705
                                s.Emit (ec);
 
706
                }
 
707
 
 
708
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
709
                {
 
710
                        StatementList t = (StatementList) target;
 
711
 
 
712
                        t.statements = new List<Statement> (statements.Count);
 
713
                        foreach (Statement s in statements)
 
714
                                t.statements.Add (s.Clone (clonectx));
 
715
                }
 
716
                
 
717
                public override object Accept (StructuralVisitor visitor)
 
718
                {
 
719
                        return visitor.Visit (this);
 
720
                }
 
721
        }
 
722
 
 
723
        // A 'return' or a 'yield break'
 
724
        public abstract class ExitStatement : Statement
 
725
        {
 
726
                protected bool unwind_protect;
 
727
                protected abstract bool DoResolve (BlockContext ec);
 
728
 
 
729
                public virtual void Error_FinallyClause (Report Report)
 
730
                {
 
731
                        Report.Error (157, loc, "Control cannot leave the body of a finally clause");
 
732
                }
 
733
 
 
734
                public sealed override bool Resolve (BlockContext ec)
 
735
                {
 
736
                        if (!DoResolve (ec))
 
737
                                return false;
 
738
 
 
739
                        unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
 
740
                        if (unwind_protect)
 
741
                                ec.NeedReturnLabel ();
 
742
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
743
                        return true;
 
744
                }
 
745
        }
 
746
 
 
747
        /// <summary>
 
748
        ///   Implements the return statement
 
749
        /// </summary>
 
750
        public class Return : ExitStatement
 
751
        {
 
752
                public Expression Expr { get; protected set; }
 
753
                
 
754
                public Return (Expression expr, Location l)
 
755
                {
 
756
                        Expr = expr;
 
757
                        loc = l;
 
758
                }
 
759
 
 
760
                #region Properties
 
761
                public Expression Expression {
 
762
                        get {
 
763
                                return Expr;
 
764
                        }
 
765
                }
 
766
                #endregion
 
767
 
 
768
                protected override bool DoResolve (BlockContext ec)
 
769
                {
 
770
                        if (Expr == null) {
 
771
                                if (ec.ReturnType.Kind == MemberKind.Void)
 
772
                                        return true;
 
773
 
 
774
                                if (ec.CurrentIterator != null) {
 
775
                                        Error_ReturnFromIterator (ec);
 
776
                                } else {
 
777
                                        ec.Report.Error (126, loc,
 
778
                                                "An object of a type convertible to `{0}' is required for the return statement",
 
779
                                                ec.ReturnType.GetSignatureForError ());
 
780
                                }
 
781
 
 
782
                                return false;
 
783
                        }
 
784
 
 
785
                        Expr = Expr.Resolve (ec);
 
786
 
 
787
                        AnonymousExpression am = ec.CurrentAnonymousMethod;
 
788
                        if (am == null) {
 
789
                                if (ec.ReturnType.Kind == MemberKind.Void) {
 
790
                                        ec.Report.Error (127, loc,
 
791
                                                "`{0}': A return keyword must not be followed by any expression when method returns void",
 
792
                                                ec.GetSignatureForError ());
 
793
                                }
 
794
                        } else {
 
795
                                if (am.IsIterator) {
 
796
                                        Error_ReturnFromIterator (ec);
 
797
                                        return false;
 
798
                                }
 
799
 
 
800
                                var l = am as AnonymousMethodBody;
 
801
                                if (l != null && l.ReturnTypeInference != null && Expr != null) {
 
802
                                        l.ReturnTypeInference.AddCommonTypeBound (Expr.Type);
 
803
                                        return true;
 
804
                                }
 
805
                        }
 
806
 
 
807
                        if (Expr == null)
 
808
                                return false;
 
809
 
 
810
                        if (Expr.Type != ec.ReturnType) {
 
811
                                Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc);
 
812
 
 
813
                                if (Expr == null) {
 
814
                                        if (am != null) {
 
815
                                                ec.Report.Error (1662, loc,
 
816
                                                        "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
 
817
                                                        am.ContainerType, am.GetSignatureForError ());
 
818
                                        }
 
819
                                        return false;
 
820
                                }
 
821
                        }
 
822
 
 
823
                        return true;                    
 
824
                }
 
825
                
 
826
                protected override void DoEmit (EmitContext ec)
 
827
                {
 
828
                        if (Expr != null) {
 
829
                                Expr.Emit (ec);
 
830
 
 
831
                                if (unwind_protect)
 
832
                                        ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
 
833
                        }
 
834
 
 
835
                        if (unwind_protect)
 
836
                                ec.Emit (OpCodes.Leave, ec.ReturnLabel);
 
837
                        else
 
838
                                ec.Emit (OpCodes.Ret);
 
839
                }
 
840
 
 
841
                void Error_ReturnFromIterator (ResolveContext rc)
 
842
                {
 
843
                        rc.Report.Error (1622, loc,
 
844
                                "Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration");
 
845
                }
 
846
 
 
847
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
848
                {
 
849
                        Return target = (Return) t;
 
850
                        // It's null for simple return;
 
851
                        if (Expr != null)
 
852
                                target.Expr = Expr.Clone (clonectx);
 
853
                }
 
854
                public override object Accept (StructuralVisitor visitor)
 
855
                {
 
856
                        return visitor.Visit (this);
 
857
                }
 
858
        }
 
859
 
 
860
        public class Goto : Statement {
 
861
                string target;
 
862
                LabeledStatement label;
 
863
                bool unwind_protect;
 
864
 
 
865
                public override bool Resolve (BlockContext ec)
 
866
                {
 
867
                        unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
 
868
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
869
                        return true;
 
870
                }
 
871
                
 
872
                public Goto (string label, Location l)
 
873
                {
 
874
                        loc = l;
 
875
                        target = label;
 
876
                }
 
877
 
 
878
                public string Target {
 
879
                        get { return target; }
 
880
                }
 
881
 
 
882
                public void SetResolvedTarget (LabeledStatement label)
 
883
                {
 
884
                        this.label = label;
 
885
                        label.AddReference ();
 
886
                }
 
887
 
 
888
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
889
                {
 
890
                        // Nothing to clone
 
891
                }
 
892
 
 
893
                protected override void DoEmit (EmitContext ec)
 
894
                {
 
895
                        if (label == null)
 
896
                                throw new InternalErrorException ("goto emitted before target resolved");
 
897
                        Label l = label.LabelTarget (ec);
 
898
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
 
899
                }
 
900
                
 
901
                public override object Accept (StructuralVisitor visitor)
 
902
                {
 
903
                        return visitor.Visit (this);
 
904
                }
 
905
        }
 
906
 
 
907
        public class LabeledStatement : Statement {
 
908
                string name;
 
909
                bool defined;
 
910
                bool referenced;
 
911
                Label label;
 
912
                Block block;
 
913
 
 
914
                FlowBranching.UsageVector vectors;
 
915
                
 
916
                public LabeledStatement (string name, Block block, Location l)
 
917
                {
 
918
                        this.name = name;
 
919
                        this.block = block;
 
920
                        this.loc = l;
 
921
                }
 
922
 
 
923
                public Label LabelTarget (EmitContext ec)
 
924
                {
 
925
                        if (defined)
 
926
                                return label;
 
927
 
 
928
                        label = ec.DefineLabel ();
 
929
                        defined = true;
 
930
                        return label;
 
931
                }
 
932
 
 
933
                public Block Block {
 
934
                        get {
 
935
                                return block;
 
936
                        }
 
937
                }
 
938
 
 
939
                public string Name {
 
940
                        get { return name; }
 
941
                }
 
942
 
 
943
                public bool IsDefined {
 
944
                        get { return defined; }
 
945
                }
 
946
 
 
947
                public bool HasBeenReferenced {
 
948
                        get { return referenced; }
 
949
                }
 
950
 
 
951
                public FlowBranching.UsageVector JumpOrigins {
 
952
                        get { return vectors; }
 
953
                }
 
954
 
 
955
                public void AddUsageVector (FlowBranching.UsageVector vector)
 
956
                {
 
957
                        vector = vector.Clone ();
 
958
                        vector.Next = vectors;
 
959
                        vectors = vector;
 
960
                }
 
961
 
 
962
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
963
                {
 
964
                        // nothing to clone
 
965
                }
 
966
 
 
967
                public override bool Resolve (BlockContext ec)
 
968
                {
 
969
                        // this flow-branching will be terminated when the surrounding block ends
 
970
                        ec.StartFlowBranching (this);
 
971
                        return true;
 
972
                }
 
973
 
 
974
                protected override void DoEmit (EmitContext ec)
 
975
                {
 
976
                        if (!HasBeenReferenced)
 
977
                                ec.Report.Warning (164, 2, loc, "This label has not been referenced");
 
978
 
 
979
                        LabelTarget (ec);
 
980
                        ec.MarkLabel (label);
 
981
                }
 
982
 
 
983
                public void AddReference ()
 
984
                {
 
985
                        referenced = true;
 
986
                }
 
987
                
 
988
                public override object Accept (StructuralVisitor visitor)
 
989
                {
 
990
                        return visitor.Visit (this);
 
991
                }
 
992
        }
 
993
        
 
994
 
 
995
        /// <summary>
 
996
        ///   `goto default' statement
 
997
        /// </summary>
 
998
        public class GotoDefault : Statement {
 
999
                
 
1000
                public GotoDefault (Location l)
 
1001
                {
 
1002
                        loc = l;
 
1003
                }
 
1004
 
 
1005
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
1006
                {
 
1007
                        // nothing to clone
 
1008
                }
 
1009
 
 
1010
                public override bool Resolve (BlockContext ec)
 
1011
                {
 
1012
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1013
 
 
1014
                        if (ec.Switch == null) {
 
1015
                                ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
 
1016
                                return false;
 
1017
                        }
 
1018
 
 
1019
                        if (!ec.Switch.GotDefault) {
 
1020
                                FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
 
1021
                                return false;
 
1022
                        }
 
1023
 
 
1024
                        return true;
 
1025
                }
 
1026
 
 
1027
                protected override void DoEmit (EmitContext ec)
 
1028
                {
 
1029
                        ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
 
1030
                }
 
1031
                
 
1032
                public override object Accept (StructuralVisitor visitor)
 
1033
                {
 
1034
                        return visitor.Visit (this);
 
1035
                }
 
1036
        }
 
1037
 
 
1038
        /// <summary>
 
1039
        ///   `goto case' statement
 
1040
        /// </summary>
 
1041
        public class GotoCase : Statement {
 
1042
                Expression expr;
 
1043
                SwitchLabel sl;
 
1044
                
 
1045
                public GotoCase (Expression e, Location l)
 
1046
                {
 
1047
                        expr = e;
 
1048
                        loc = l;
 
1049
                }
 
1050
                
 
1051
                public Expression Expr {
 
1052
                        get { return this.expr; }
 
1053
                }
 
1054
                
 
1055
                public override bool Resolve (BlockContext ec)
 
1056
                {
 
1057
                        if (ec.Switch == null){
 
1058
                                ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
 
1059
                                return false;
 
1060
                        }
 
1061
 
 
1062
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1063
 
 
1064
                        expr = expr.Resolve (ec);
 
1065
                        if (expr == null)
 
1066
                                return false;
 
1067
 
 
1068
                        Constant c = expr as Constant;
 
1069
                        if (c == null) {
 
1070
                                ec.Report.Error (150, expr.Location, "A constant value is expected");
 
1071
                                return false;
 
1072
                        }
 
1073
 
 
1074
                        Constant res;
 
1075
                        if (ec.Switch.IsNullable && c is NullLiteral) {
 
1076
                                res = c;
 
1077
                        } else {
 
1078
                                TypeSpec type = ec.Switch.SwitchType;
 
1079
                                res = c.TryReduce (ec, type, c.Location);
 
1080
                                if (res == null) {
 
1081
                                        c.Error_ValueCannotBeConverted (ec, loc, type, true);
 
1082
                                        return false;
 
1083
                                }
 
1084
 
 
1085
                                if (!Convert.ImplicitStandardConversionExists (c, type))
 
1086
                                        ec.Report.Warning (469, 2, loc,
 
1087
                                                "The `goto case' value is not implicitly convertible to type `{0}'",
 
1088
                                                TypeManager.CSharpName (type));
 
1089
 
 
1090
                        }
 
1091
 
 
1092
                        sl = ec.Switch.ResolveGotoCase (ec, res);
 
1093
                        return true;
 
1094
                }
 
1095
 
 
1096
                protected override void DoEmit (EmitContext ec)
 
1097
                {
 
1098
                        ec.Emit (OpCodes.Br, sl.GetILLabel (ec));
 
1099
                }
 
1100
 
 
1101
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
1102
                {
 
1103
                        GotoCase target = (GotoCase) t;
 
1104
 
 
1105
                        target.expr = expr.Clone (clonectx);
 
1106
                }
 
1107
                
 
1108
                public override object Accept (StructuralVisitor visitor)
 
1109
                {
 
1110
                        return visitor.Visit (this);
 
1111
                }
 
1112
        }
 
1113
        
 
1114
        public class Throw : Statement {
 
1115
                Expression expr;
 
1116
                
 
1117
                public Throw (Expression expr, Location l)
 
1118
                {
 
1119
                        this.expr = expr;
 
1120
                        loc = l;
 
1121
                }
 
1122
                
 
1123
                public Expression Expr {
 
1124
                        get { return this.expr; }
 
1125
                }
 
1126
                
 
1127
                public override bool Resolve (BlockContext ec)
 
1128
                {
 
1129
                        if (expr == null) {
 
1130
                                ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1131
                                return ec.CurrentBranching.CheckRethrow (loc);
 
1132
                        }
 
1133
 
 
1134
                        expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
 
1135
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1136
 
 
1137
                        if (expr == null)
 
1138
                                return false;
 
1139
 
 
1140
                        var et = ec.BuiltinTypes.Exception;
 
1141
                        if (Convert.ImplicitConversionExists (ec, expr, et))
 
1142
                                expr = Convert.ImplicitConversion (ec, expr, et, loc);
 
1143
                        else
 
1144
                                ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
 
1145
 
 
1146
                        return true;
 
1147
                }
 
1148
                        
 
1149
                protected override void DoEmit (EmitContext ec)
 
1150
                {
 
1151
                        if (expr == null)
 
1152
                                ec.Emit (OpCodes.Rethrow);
 
1153
                        else {
 
1154
                                expr.Emit (ec);
 
1155
 
 
1156
                                ec.Emit (OpCodes.Throw);
 
1157
                        }
 
1158
                }
 
1159
 
 
1160
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
1161
                {
 
1162
                        Throw target = (Throw) t;
 
1163
 
 
1164
                        if (expr != null)
 
1165
                                target.expr = expr.Clone (clonectx);
 
1166
                }
 
1167
                
 
1168
                public override object Accept (StructuralVisitor visitor)
 
1169
                {
 
1170
                        return visitor.Visit (this);
 
1171
                }
 
1172
        }
 
1173
 
 
1174
        public class Break : Statement {
 
1175
                
 
1176
                public Break (Location l)
 
1177
                {
 
1178
                        loc = l;
 
1179
                }
 
1180
 
 
1181
                bool unwind_protect;
 
1182
 
 
1183
                public override bool Resolve (BlockContext ec)
 
1184
                {
 
1185
                        unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
 
1186
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1187
                        return true;
 
1188
                }
 
1189
 
 
1190
                protected override void DoEmit (EmitContext ec)
 
1191
                {
 
1192
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
 
1193
                }
 
1194
 
 
1195
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
1196
                {
 
1197
                        // nothing needed
 
1198
                }
 
1199
                
 
1200
                public override object Accept (StructuralVisitor visitor)
 
1201
                {
 
1202
                        return visitor.Visit (this);
 
1203
                }
 
1204
        }
 
1205
 
 
1206
        public class Continue : Statement {
 
1207
                
 
1208
                public Continue (Location l)
 
1209
                {
 
1210
                        loc = l;
 
1211
                }
 
1212
 
 
1213
                bool unwind_protect;
 
1214
 
 
1215
                public override bool Resolve (BlockContext ec)
 
1216
                {
 
1217
                        unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
 
1218
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
1219
                        return true;
 
1220
                }
 
1221
 
 
1222
                protected override void DoEmit (EmitContext ec)
 
1223
                {
 
1224
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
 
1225
                }
 
1226
 
 
1227
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
1228
                {
 
1229
                        // nothing needed.
 
1230
                }
 
1231
                
 
1232
                public override object Accept (StructuralVisitor visitor)
 
1233
                {
 
1234
                        return visitor.Visit (this);
 
1235
                }
 
1236
        }
 
1237
 
 
1238
        public interface ILocalVariable
 
1239
        {
 
1240
                void Emit (EmitContext ec);
 
1241
                void EmitAssign (EmitContext ec);
 
1242
                void EmitAddressOf (EmitContext ec);
 
1243
        }
 
1244
 
 
1245
        public interface INamedBlockVariable
 
1246
        {
 
1247
                Block Block { get; }
 
1248
                Expression CreateReferenceExpression (ResolveContext rc, Location loc);
 
1249
                bool IsDeclared { get; }
 
1250
                Location Location { get; }
 
1251
        }
 
1252
 
 
1253
        public class BlockVariableDeclaration : Statement
 
1254
        {
 
1255
                public class Declarator
 
1256
                {
 
1257
                        LocalVariable li;
 
1258
                        Expression initializer;
 
1259
 
 
1260
                        public Declarator (LocalVariable li, Expression initializer)
 
1261
                        {
 
1262
                                if (li.Type != null)
 
1263
                                        throw new ArgumentException ("Expected null variable type");
 
1264
 
 
1265
                                this.li = li;
 
1266
                                this.initializer = initializer;
 
1267
                        }
 
1268
 
 
1269
                        public Declarator (Declarator clone, Expression initializer)
 
1270
                        {
 
1271
                                this.li = clone.li;
 
1272
                                this.initializer = initializer;
 
1273
                        }
 
1274
 
 
1275
                        #region Properties
 
1276
 
 
1277
                        public LocalVariable Variable {
 
1278
                                get {
 
1279
                                        return li;
 
1280
                                }
 
1281
                        }
 
1282
 
 
1283
                        public Expression Initializer {
 
1284
                                get {
 
1285
                                        return initializer;
 
1286
                                }
 
1287
                                set {
 
1288
                                        initializer = value;
 
1289
                                }
 
1290
                        }
 
1291
 
 
1292
                        #endregion
 
1293
                }
 
1294
 
 
1295
                Expression initializer;
 
1296
                protected FullNamedExpression type_expr;
 
1297
                protected LocalVariable li;
 
1298
                protected List<Declarator> declarators;
 
1299
 
 
1300
                public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
 
1301
                {
 
1302
                        this.type_expr = type;
 
1303
                        this.li = li;
 
1304
                        this.loc = type_expr.Location;
 
1305
                }
 
1306
 
 
1307
                protected BlockVariableDeclaration (LocalVariable li)
 
1308
                {
 
1309
                        this.li = li;
 
1310
                }
 
1311
 
 
1312
                #region Properties
 
1313
 
 
1314
                public List<Declarator> Declarators {
 
1315
                        get {
 
1316
                                return declarators;
 
1317
                        }
 
1318
                }
 
1319
 
 
1320
                public Expression Initializer {
 
1321
                        get {
 
1322
                                return initializer;
 
1323
                        }
 
1324
                        set {
 
1325
                                initializer = value;
 
1326
                        }
 
1327
                }
 
1328
 
 
1329
                public FullNamedExpression TypeExpression {
 
1330
                        get {
 
1331
                                return type_expr;
 
1332
                        }
 
1333
                }
 
1334
 
 
1335
                public LocalVariable Variable {
 
1336
                        get {
 
1337
                                return li;
 
1338
                        }
 
1339
                }
 
1340
 
 
1341
                #endregion
 
1342
 
 
1343
                public void AddDeclarator (Declarator decl)
 
1344
                {
 
1345
                        if (declarators == null)
 
1346
                                declarators = new List<Declarator> ();
 
1347
 
 
1348
                        declarators.Add (decl);
 
1349
                }
 
1350
 
 
1351
                void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
 
1352
                {
 
1353
                        var container = bc.CurrentMemberDefinition.Parent;
 
1354
 
 
1355
                        Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
 
1356
                                new MemberName (li.Name, li.Location), null);
 
1357
 
 
1358
                        container.AddField (f);
 
1359
                        f.Define ();
 
1360
 
 
1361
                        li.HoistedVariant = new HoistedEvaluatorVariable (f);
 
1362
                        li.SetIsUsed ();
 
1363
                }
 
1364
 
 
1365
                public override bool Resolve (BlockContext bc)
 
1366
                {
 
1367
                        if (li.Type == null) {
 
1368
                                TypeSpec type = null;
 
1369
                                var vexpr = type_expr as VarExpr;
 
1370
 
 
1371
                                //
 
1372
                                // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
 
1373
                                // same name exists or as a keyword when no type was found
 
1374
                                //
 
1375
                                if (vexpr != null && !vexpr.IsPossibleTypeOrNamespace (bc)) {
 
1376
                                        if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
 
1377
                                                bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
 
1378
 
 
1379
                                        if (li.IsFixed) {
 
1380
                                                bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
 
1381
                                                return false;
 
1382
                                        }
 
1383
 
 
1384
                                        if (li.IsConstant) {
 
1385
                                                bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
 
1386
                                                return false;
 
1387
                                        }
 
1388
 
 
1389
                                        if (Initializer == null) {
 
1390
                                                bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
 
1391
                                                return false;
 
1392
                                        }
 
1393
 
 
1394
                                        if (declarators != null) {
 
1395
                                                bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
 
1396
                                                declarators = null;
 
1397
                                        }
 
1398
 
 
1399
                                        Initializer = Initializer.Resolve (bc);
 
1400
                                        if (Initializer != null) {
 
1401
                                                ((VarExpr) type_expr).InferType (bc, Initializer);
 
1402
                                                type = type_expr.Type;
 
1403
                                        }
 
1404
                                }
 
1405
 
 
1406
                                if (type == null) {
 
1407
                                        type = type_expr.ResolveAsType (bc);
 
1408
                                        if (type == null)
 
1409
                                                return false;
 
1410
 
 
1411
                                        if (li.IsConstant && !type.IsConstantCompatible) {
 
1412
                                                Const.Error_InvalidConstantType (type, loc, bc.Report);
 
1413
                                        }
 
1414
                                }
 
1415
 
 
1416
                                if (type.IsStatic)
 
1417
                                        FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
 
1418
 
 
1419
                                li.Type = type;
 
1420
                        }
 
1421
 
 
1422
                        bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
 
1423
                        if (eval_global) {
 
1424
                                CreateEvaluatorVariable (bc, li);
 
1425
                        } else {
 
1426
                                li.PrepareForFlowAnalysis (bc);
 
1427
                        }
 
1428
 
 
1429
                        if (initializer != null) {
 
1430
                                initializer = ResolveInitializer (bc, li, initializer);
 
1431
                                // li.Variable.DefinitelyAssigned 
 
1432
                        }
 
1433
 
 
1434
                        if (declarators != null) {
 
1435
                                foreach (var d in declarators) {
 
1436
                                        d.Variable.Type = li.Type;
 
1437
                                        if (eval_global) {
 
1438
                                                CreateEvaluatorVariable (bc, d.Variable);
 
1439
                                        } else {
 
1440
                                                d.Variable.PrepareForFlowAnalysis (bc);
 
1441
                                        }
 
1442
 
 
1443
                                        if (d.Initializer != null) {
 
1444
                                                d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
 
1445
                                                // d.Variable.DefinitelyAssigned 
 
1446
                                        }
 
1447
                                }
 
1448
                        }
 
1449
 
 
1450
                        return true;
 
1451
                }
 
1452
 
 
1453
                protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
 
1454
                {
 
1455
                        var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
 
1456
                        return a.ResolveStatement (bc);
 
1457
                }
 
1458
 
 
1459
                protected override void DoEmit (EmitContext ec)
 
1460
                {
 
1461
                        if (li.IsConstant)
 
1462
                                return;
 
1463
 
 
1464
                        li.CreateBuilder (ec);
 
1465
 
 
1466
                        if (Initializer != null)
 
1467
                                ((ExpressionStatement) Initializer).EmitStatement (ec);
 
1468
 
 
1469
                        if (declarators != null) {
 
1470
                                foreach (var d in declarators) {
 
1471
                                        d.Variable.CreateBuilder (ec);
 
1472
                                        if (d.Initializer != null)
 
1473
                                                ((ExpressionStatement) d.Initializer).EmitStatement (ec);
 
1474
                                }
 
1475
                        }
 
1476
                }
 
1477
 
 
1478
                protected override void CloneTo (CloneContext clonectx, Statement target)
 
1479
                {
 
1480
                        BlockVariableDeclaration t = (BlockVariableDeclaration) target;
 
1481
 
 
1482
                        if (type_expr != null)
 
1483
                                t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
 
1484
 
 
1485
                        if (initializer != null)
 
1486
                                t.initializer = initializer.Clone (clonectx);
 
1487
 
 
1488
                        if (declarators != null) {
 
1489
                                t.declarators = null;
 
1490
                                foreach (var d in declarators)
 
1491
                                        t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
 
1492
                        }
 
1493
                }
 
1494
 
 
1495
                public override object Accept (StructuralVisitor visitor)
 
1496
                {
 
1497
                        return visitor.Visit (this);
 
1498
                }
 
1499
        }
 
1500
 
 
1501
        public class BlockConstantDeclaration : BlockVariableDeclaration
 
1502
        {
 
1503
                public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
 
1504
                        : base (type, li)
 
1505
                {
 
1506
                }
 
1507
 
 
1508
                protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
 
1509
                {
 
1510
                        initializer = initializer.Resolve (bc);
 
1511
                        if (initializer == null)
 
1512
                                return null;
 
1513
 
 
1514
                        var c = initializer as Constant;
 
1515
                        if (c == null) {
 
1516
                                initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
 
1517
                                return null;
 
1518
                        }
 
1519
 
 
1520
                        c = c.ConvertImplicitly (li.Type);
 
1521
                        if (c == null) {
 
1522
                                if (TypeSpec.IsReferenceType (li.Type))
 
1523
                                        initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
 
1524
                                else
 
1525
                                        initializer.Error_ValueCannotBeConverted (bc, initializer.Location, li.Type, false);
 
1526
 
 
1527
                                return null;
 
1528
                        }
 
1529
 
 
1530
                        li.ConstantValue = c;
 
1531
                        return initializer;
 
1532
                }
 
1533
                
 
1534
                public override object Accept (StructuralVisitor visitor)
 
1535
                {
 
1536
                        return visitor.Visit (this);
 
1537
                }
 
1538
        }
 
1539
 
 
1540
        //
 
1541
        // The information about a user-perceived local variable
 
1542
        //
 
1543
        public class LocalVariable : INamedBlockVariable, ILocalVariable
 
1544
        {
 
1545
                [Flags]
 
1546
                public enum Flags
 
1547
                {
 
1548
                        Used = 1,
 
1549
                        IsThis = 1 << 1,
 
1550
                        AddressTaken = 1 << 2,
 
1551
                        CompilerGenerated = 1 << 3,
 
1552
                        Constant = 1 << 4,
 
1553
                        ForeachVariable = 1 << 5,
 
1554
                        FixedVariable = 1 << 6,
 
1555
                        UsingVariable = 1 << 7,
 
1556
//                      DefinitelyAssigned = 1 << 8,
 
1557
                        IsLocked = 1 << 9,
 
1558
 
 
1559
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
 
1560
                }
 
1561
 
 
1562
                TypeSpec type;
 
1563
                readonly string name;
 
1564
                readonly Location loc;
 
1565
                readonly Block block;
 
1566
                Flags flags;
 
1567
                Constant const_value;
 
1568
 
 
1569
                public VariableInfo VariableInfo;
 
1570
                HoistedVariable hoisted_variant;
 
1571
 
 
1572
                LocalBuilder builder;
 
1573
 
 
1574
                public LocalVariable (Block block, string name, Location loc)
 
1575
                {
 
1576
                        this.block = block;
 
1577
                        this.name = name;
 
1578
                        this.loc = loc;
 
1579
                }
 
1580
 
 
1581
                public LocalVariable (Block block, string name, Flags flags, Location loc)
 
1582
                        : this (block, name, loc)
 
1583
                {
 
1584
                        this.flags = flags;
 
1585
                }
 
1586
 
 
1587
                //
 
1588
                // Used by variable declarators
 
1589
                //
 
1590
                public LocalVariable (LocalVariable li, string name, Location loc)
 
1591
                        : this (li.block, name, li.flags, loc)
 
1592
                {
 
1593
                }
 
1594
 
 
1595
                #region Properties
 
1596
 
 
1597
                public bool AddressTaken {
 
1598
                        get { return (flags & Flags.AddressTaken) != 0; }
 
1599
                        set { flags |= Flags.AddressTaken; }
 
1600
                }
 
1601
 
 
1602
                public Block Block {
 
1603
                        get {
 
1604
                                return block;
 
1605
                        }
 
1606
                }
 
1607
 
 
1608
                public Constant ConstantValue {
 
1609
                        get {
 
1610
                                return const_value;
 
1611
                        }
 
1612
                        set {
 
1613
                                const_value = value;
 
1614
                        }
 
1615
                }
 
1616
 
 
1617
                //
 
1618
                // Hoisted local variable variant
 
1619
                //
 
1620
                public HoistedVariable HoistedVariant {
 
1621
                        get {
 
1622
                                return hoisted_variant;
 
1623
                        }
 
1624
                        set {
 
1625
                                hoisted_variant = value;
 
1626
                        }
 
1627
                }
 
1628
 
 
1629
                public bool IsDeclared {
 
1630
                        get {
 
1631
                                return type != null;
 
1632
                        }
 
1633
                }
 
1634
 
 
1635
                public bool IsConstant {
 
1636
                        get {
 
1637
                                return (flags & Flags.Constant) != 0;
 
1638
                        }
 
1639
                }
 
1640
 
 
1641
                public bool IsLocked {
 
1642
                        get {
 
1643
                                return (flags & Flags.IsLocked) != 0;
 
1644
                        }
 
1645
                        set {
 
1646
                                flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
 
1647
                        }
 
1648
                }
 
1649
 
 
1650
                public bool IsThis {
 
1651
                        get {
 
1652
                                return (flags & Flags.IsThis) != 0;
 
1653
                        }
 
1654
                }
 
1655
 
 
1656
                public bool IsFixed {
 
1657
                        get {
 
1658
                                return (flags & Flags.FixedVariable) != 0;
 
1659
                        }
 
1660
                }
 
1661
 
 
1662
                public bool IsReadonly {
 
1663
                        get {
 
1664
                                return (flags & Flags.ReadonlyMask) != 0;
 
1665
                        }
 
1666
                }
 
1667
 
 
1668
                public Location Location {
 
1669
                        get {
 
1670
                                return loc;
 
1671
                        }
 
1672
                }
 
1673
 
 
1674
                public string Name {
 
1675
                        get {
 
1676
                                return name;
 
1677
                        }
 
1678
                }
 
1679
 
 
1680
                public TypeSpec Type {
 
1681
                    get {
 
1682
                                return type;
 
1683
                        }
 
1684
                    set {
 
1685
                                type = value;
 
1686
                        }
 
1687
                }
 
1688
 
 
1689
                #endregion
 
1690
 
 
1691
                public void CreateBuilder (EmitContext ec)
 
1692
                {
 
1693
                        if ((flags & Flags.Used) == 0) {
 
1694
                                if (VariableInfo == null) {
 
1695
                                        // Missing flow analysis or wrong variable flags
 
1696
                                        throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
 
1697
                                }
 
1698
 
 
1699
                                if (VariableInfo.IsEverAssigned)
 
1700
                                        ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
 
1701
                                else
 
1702
                                        ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
 
1703
                        }
 
1704
 
 
1705
                        if (HoistedVariant != null)
 
1706
                                return;
 
1707
 
 
1708
                        if (builder != null) {
 
1709
                                if ((flags & Flags.CompilerGenerated) != 0)
 
1710
                                        return;
 
1711
 
 
1712
                                // To avoid Used warning duplicates
 
1713
                                throw new InternalErrorException ("Already created variable `{0}'", name);
 
1714
                        }
 
1715
 
 
1716
                        //
 
1717
                        // All fixed variabled are pinned, a slot has to be alocated
 
1718
                        //
 
1719
                        builder = ec.DeclareLocal (Type, IsFixed);
 
1720
                        if (SymbolWriter.HasSymbolWriter)
 
1721
                                ec.DefineLocalVariable (name, builder);
 
1722
                }
 
1723
 
 
1724
                public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
 
1725
                {
 
1726
                        LocalVariable li = new LocalVariable (block, "<$$>", Flags.CompilerGenerated | Flags.Used, loc);
 
1727
                        li.Type = type;
 
1728
                        return li;
 
1729
                }
 
1730
 
 
1731
                public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
 
1732
                {
 
1733
                        if (IsConstant && const_value != null)
 
1734
                                return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
 
1735
 
 
1736
                        return new LocalVariableReference (this, loc);
 
1737
                }
 
1738
 
 
1739
                public void Emit (EmitContext ec)
 
1740
                {
 
1741
                        // TODO: Need something better for temporary variables
 
1742
                        if ((flags & Flags.CompilerGenerated) != 0)
 
1743
                                CreateBuilder (ec);
 
1744
 
 
1745
                        ec.Emit (OpCodes.Ldloc, builder);
 
1746
                }
 
1747
 
 
1748
                public void EmitAssign (EmitContext ec)
 
1749
                {
 
1750
                        // TODO: Need something better for temporary variables
 
1751
                        if ((flags & Flags.CompilerGenerated) != 0)
 
1752
                                CreateBuilder (ec);
 
1753
 
 
1754
                        ec.Emit (OpCodes.Stloc, builder);
 
1755
                }
 
1756
 
 
1757
                public void EmitAddressOf (EmitContext ec)
 
1758
                {
 
1759
                        ec.Emit (OpCodes.Ldloca, builder);
 
1760
                }
 
1761
 
 
1762
                public string GetReadOnlyContext ()
 
1763
                {
 
1764
                        switch (flags & Flags.ReadonlyMask) {
 
1765
                        case Flags.FixedVariable:
 
1766
                                return "fixed variable";
 
1767
                        case Flags.ForeachVariable:
 
1768
                                return "foreach iteration variable";
 
1769
                        case Flags.UsingVariable:
 
1770
                                return "using variable";
 
1771
                        }
 
1772
 
 
1773
                        throw new InternalErrorException ("Variable is not readonly");
 
1774
                }
 
1775
 
 
1776
                public bool IsThisAssigned (BlockContext ec, Block block)
 
1777
                {
 
1778
                        if (VariableInfo == null)
 
1779
                                throw new Exception ();
 
1780
 
 
1781
                        if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
 
1782
                                return true;
 
1783
 
 
1784
                        return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
 
1785
                }
 
1786
 
 
1787
                public bool IsAssigned (BlockContext ec)
 
1788
                {
 
1789
                        if (VariableInfo == null)
 
1790
                                throw new Exception ();
 
1791
 
 
1792
                        return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
 
1793
                }
 
1794
 
 
1795
                public void PrepareForFlowAnalysis (BlockContext bc)
 
1796
                {
 
1797
                        //
 
1798
                        // No need for definitely assigned check for these guys
 
1799
                        //
 
1800
                        if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
 
1801
                                return;
 
1802
 
 
1803
                        VariableInfo = new VariableInfo (this, bc.FlowOffset);
 
1804
                        bc.FlowOffset += VariableInfo.Length;
 
1805
                }
 
1806
 
 
1807
                //
 
1808
                // Mark the variables as referenced in the user code
 
1809
                //
 
1810
                public void SetIsUsed ()
 
1811
                {
 
1812
                        flags |= Flags.Used;
 
1813
                }
 
1814
 
 
1815
                public override string ToString ()
 
1816
                {
 
1817
                        return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
 
1818
                }
 
1819
        }
 
1820
 
 
1821
        /// <summary>
 
1822
        ///   Block represents a C# block.
 
1823
        /// </summary>
 
1824
        ///
 
1825
        /// <remarks>
 
1826
        ///   This class is used in a number of places: either to represent
 
1827
        ///   explicit blocks that the programmer places or implicit blocks.
 
1828
        ///
 
1829
        ///   Implicit blocks are used as labels or to introduce variable
 
1830
        ///   declarations.
 
1831
        ///
 
1832
        ///   Top-level blocks derive from Block, and they are called ToplevelBlock
 
1833
        ///   they contain extra information that is not necessary on normal blocks.
 
1834
        /// </remarks>
 
1835
        public class Block : Statement {
 
1836
                [Flags]
 
1837
                public enum Flags
 
1838
                {
 
1839
                        Unchecked = 1,
 
1840
                        HasRet = 8,
 
1841
                        Unsafe = 16,
 
1842
                        IsIterator = 32,
 
1843
                        HasCapturedVariable = 64,
 
1844
                        HasCapturedThis = 1 << 7,
 
1845
                        IsExpressionTree = 1 << 8,
 
1846
                        CompilerGenerated = 1 << 9
 
1847
                }
 
1848
 
 
1849
                public Block Parent;
 
1850
                public Location StartLocation;
 
1851
                public Location EndLocation;
 
1852
 
 
1853
                public ExplicitBlock Explicit;
 
1854
                public ParametersBlock ParametersBlock;
 
1855
 
 
1856
                protected Flags flags;
 
1857
 
 
1858
                //
 
1859
                // The statements in this block
 
1860
                //
 
1861
                protected List<Statement> statements;
 
1862
 
 
1863
                protected List<Statement> scope_initializers;
 
1864
 
 
1865
                int? resolving_init_idx;
 
1866
 
 
1867
                protected Block original;
 
1868
 
 
1869
#if DEBUG
 
1870
                static int id;
 
1871
                public int ID = id++;
 
1872
 
 
1873
                static int clone_id_counter;
 
1874
                int clone_id;
 
1875
#endif
 
1876
 
 
1877
//              int assignable_slots;
 
1878
                bool unreachable_shown;
 
1879
                bool unreachable;
 
1880
                
 
1881
                public Block (Block parent, Location start, Location end)
 
1882
                        : this (parent, 0, start, end)
 
1883
                {
 
1884
                }
 
1885
 
 
1886
                public Block (Block parent, Flags flags, Location start, Location end)
 
1887
                {
 
1888
                        if (parent != null) {
 
1889
                                // the appropriate constructors will fixup these fields
 
1890
                                ParametersBlock = parent.ParametersBlock;
 
1891
                                Explicit = parent.Explicit;
 
1892
                        }
 
1893
                        
 
1894
                        this.Parent = parent;
 
1895
                        this.flags = flags;
 
1896
                        this.StartLocation = start;
 
1897
                        this.EndLocation = end;
 
1898
                        this.loc = start;
 
1899
                        statements = new List<Statement> (4);
 
1900
 
 
1901
                        this.original = this;
 
1902
                }
 
1903
 
 
1904
                #region Properties
 
1905
 
 
1906
                public bool HasRet {
 
1907
                        get { return (flags & Flags.HasRet) != 0; }
 
1908
                }
 
1909
 
 
1910
                public Block Original {
 
1911
                        get {
 
1912
                                return original;
 
1913
                        }
 
1914
                }
 
1915
 
 
1916
                public bool IsCompilerGenerated {
 
1917
                        get { return (flags & Flags.CompilerGenerated) != 0; }
 
1918
                        set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
 
1919
                }
 
1920
 
 
1921
                public bool Unchecked {
 
1922
                        get { return (flags & Flags.Unchecked) != 0; }
 
1923
                        set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
 
1924
                }
 
1925
 
 
1926
                public bool Unsafe {
 
1927
                        get { return (flags & Flags.Unsafe) != 0; }
 
1928
                        set { flags |= Flags.Unsafe; }
 
1929
                }
 
1930
                
 
1931
                public List<Statement> Statements {
 
1932
                        get { return this.statements; }
 
1933
                }
 
1934
                #endregion
 
1935
 
 
1936
                public Block CreateSwitchBlock (Location start)
 
1937
                {
 
1938
                        // FIXME: Only explicit block should be created
 
1939
                        var new_block = new Block (this, start, start);
 
1940
                        new_block.IsCompilerGenerated = true;
 
1941
                        return new_block;
 
1942
                }
 
1943
 
 
1944
                public void SetEndLocation (Location loc)
 
1945
                {
 
1946
                        EndLocation = loc;
 
1947
                }
 
1948
 
 
1949
                public void AddLabel (LabeledStatement target)
 
1950
                {
 
1951
                        ParametersBlock.TopBlock.AddLabel (target.Name, target);
 
1952
                }
 
1953
 
 
1954
                public void AddLocalName (LocalVariable li)
 
1955
                {
 
1956
                        AddLocalName (li.Name, li);
 
1957
                }
 
1958
 
 
1959
                public virtual void AddLocalName (string name, INamedBlockVariable li)
 
1960
                {
 
1961
                        ParametersBlock.TopBlock.AddLocalName (name, li);
 
1962
                }
 
1963
 
 
1964
                public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
 
1965
                {
 
1966
                        if (reason == null) {
 
1967
                                Error_AlreadyDeclared (name, variable);
 
1968
                                return;
 
1969
                        }
 
1970
 
 
1971
                        ParametersBlock.TopBlock.Report.Error (136, variable.Location,
 
1972
                                "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
 
1973
                                "to `{0}', which is already used in a `{1}' scope to denote something else",
 
1974
                                name, reason);
 
1975
                }
 
1976
 
 
1977
                public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
 
1978
                {
 
1979
                        var pi = variable as ParametersBlock.ParameterInfo;
 
1980
                        if (pi != null) {
 
1981
                                var p = pi.Parameter;
 
1982
                                ParametersBlock.TopBlock.Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
 
1983
                        }
 
1984
 
 
1985
                        ParametersBlock.TopBlock.Report.Error (128, variable.Location,
 
1986
                                "A local variable named `{0}' is already defined in this scope", name);
 
1987
                }
 
1988
                                        
 
1989
                public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
 
1990
                {
 
1991
                        ParametersBlock.TopBlock.Report.Error (412, loc,
 
1992
                                "The type parameter name `{0}' is the same as local variable or parameter name",
 
1993
                                name);
 
1994
                }
 
1995
 
 
1996
                //
 
1997
                // It should be used by expressions which require to
 
1998
                // register a statement during resolve process.
 
1999
                //
 
2000
                public void AddScopeStatement (Statement s)
 
2001
                {
 
2002
                        if (scope_initializers == null)
 
2003
                                scope_initializers = new List<Statement> ();
 
2004
 
 
2005
                        //
 
2006
                        // Simple recursive helper, when resolve scope initializer another
 
2007
                        // new scope initializer can be added, this ensures it's initialized
 
2008
                        // before existing one. For now this can happen with expression trees
 
2009
                        // in base ctor initializer only
 
2010
                        //
 
2011
                        if (resolving_init_idx.HasValue) {
 
2012
                                scope_initializers.Insert (resolving_init_idx.Value, s);
 
2013
                                ++resolving_init_idx;
 
2014
                        } else {
 
2015
                                scope_initializers.Add (s);
 
2016
                        }
 
2017
                }
 
2018
                
 
2019
                public void AddStatement (Statement s)
 
2020
                {
 
2021
                        statements.Add (s);
 
2022
                }
 
2023
 
 
2024
                public int AssignableSlots {
 
2025
                        get {
 
2026
                                // FIXME: HACK, we don't know the block available variables count now, so set this high enough
 
2027
                                return 4096;
 
2028
//                              return assignable_slots;
 
2029
                        }
 
2030
                }
 
2031
 
 
2032
                public LabeledStatement LookupLabel (string name)
 
2033
                {
 
2034
                        return ParametersBlock.TopBlock.GetLabel (name, this);
 
2035
                }
 
2036
 
 
2037
                public override bool Resolve (BlockContext ec)
 
2038
                {
 
2039
                        Block prev_block = ec.CurrentBlock;
 
2040
                        bool ok = true;
 
2041
 
 
2042
                        ec.CurrentBlock = this;
 
2043
                        ec.StartFlowBranching (this);
 
2044
 
 
2045
                        //
 
2046
                        // Compiler generated scope statements
 
2047
                        //
 
2048
                        if (scope_initializers != null) {
 
2049
                                for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
 
2050
                                        scope_initializers[resolving_init_idx.Value].Resolve (ec);
 
2051
                                }
 
2052
 
 
2053
                                resolving_init_idx = null;
 
2054
                        }
 
2055
 
 
2056
                        //
 
2057
                        // This flag is used to notate nested statements as unreachable from the beginning of this block.
 
2058
                        // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
 
2059
                        // from the beginning of the function.  The outer Resolve() that detected the unreachability is
 
2060
                        // responsible for handling the situation.
 
2061
                        //
 
2062
                        int statement_count = statements.Count;
 
2063
                        for (int ix = 0; ix < statement_count; ix++){
 
2064
                                Statement s = statements [ix];
 
2065
 
 
2066
                                //
 
2067
                                // Warn if we detect unreachable code.
 
2068
                                //
 
2069
                                if (unreachable) {
 
2070
                                        if (s is EmptyStatement)
 
2071
                                                continue;
 
2072
 
 
2073
                                        if (!unreachable_shown && !(s is LabeledStatement)) {
 
2074
                                                ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
 
2075
                                                unreachable_shown = true;
 
2076
                                        }
 
2077
 
 
2078
                                        Block c_block = s as Block;
 
2079
                                        if (c_block != null)
 
2080
                                                c_block.unreachable = c_block.unreachable_shown = true;
 
2081
                                }
 
2082
 
 
2083
                                //
 
2084
                                // Note that we're not using ResolveUnreachable() for unreachable
 
2085
                                // statements here.  ResolveUnreachable() creates a temporary
 
2086
                                // flow branching and kills it afterwards.  This leads to problems
 
2087
                                // if you have two unreachable statements where the first one
 
2088
                                // assigns a variable and the second one tries to access it.
 
2089
                                //
 
2090
 
 
2091
                                if (!s.Resolve (ec)) {
 
2092
                                        ok = false;
 
2093
                                        if (ec.IsInProbingMode)
 
2094
                                                break;
 
2095
 
 
2096
                                        statements [ix] = new EmptyStatement (s.loc);
 
2097
                                        continue;
 
2098
                                }
 
2099
 
 
2100
                                if (unreachable && !(s is LabeledStatement) && !(s is Block))
 
2101
                                        statements [ix] = new EmptyStatement (s.loc);
 
2102
 
 
2103
                                unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
2104
                                if (unreachable && s is LabeledStatement)
 
2105
                                        throw new InternalErrorException ("should not happen");
 
2106
                        }
 
2107
 
 
2108
                        while (ec.CurrentBranching is FlowBranchingLabeled)
 
2109
                                ec.EndFlowBranching ();
 
2110
 
 
2111
                        bool flow_unreachable = ec.EndFlowBranching ();
 
2112
 
 
2113
                        ec.CurrentBlock = prev_block;
 
2114
 
 
2115
                        if (flow_unreachable)
 
2116
                                flags |= Flags.HasRet;
 
2117
 
 
2118
                        // If we're a non-static `struct' constructor which doesn't have an
 
2119
                        // initializer, then we must initialize all of the struct's fields.
 
2120
                        if (this == ParametersBlock.TopBlock && !ParametersBlock.TopBlock.IsThisAssigned (ec) && !flow_unreachable)
 
2121
                                ok = false;
 
2122
 
 
2123
                        return ok;
 
2124
                }
 
2125
 
 
2126
                public override bool ResolveUnreachable (BlockContext ec, bool warn)
 
2127
                {
 
2128
                        unreachable_shown = true;
 
2129
                        unreachable = true;
 
2130
 
 
2131
                        if (warn)
 
2132
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
 
2133
 
 
2134
                        ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
 
2135
                        bool ok = Resolve (ec);
 
2136
                        ec.KillFlowBranching ();
 
2137
 
 
2138
                        return ok;
 
2139
                }
 
2140
                
 
2141
                protected override void DoEmit (EmitContext ec)
 
2142
                {
 
2143
                        for (int ix = 0; ix < statements.Count; ix++){
 
2144
                                statements [ix].Emit (ec);
 
2145
                        }
 
2146
                }
 
2147
 
 
2148
                public override void Emit (EmitContext ec)
 
2149
                {
 
2150
                        if (scope_initializers != null)
 
2151
                                EmitScopeInitializers (ec);
 
2152
 
 
2153
                        ec.Mark (StartLocation);
 
2154
                        DoEmit (ec);
 
2155
 
 
2156
                        if (SymbolWriter.HasSymbolWriter)
 
2157
                                EmitSymbolInfo (ec);
 
2158
                }
 
2159
 
 
2160
                protected void EmitScopeInitializers (EmitContext ec)
 
2161
                {
 
2162
                        SymbolWriter.OpenCompilerGeneratedBlock (ec);
 
2163
 
 
2164
                        using (ec.With (EmitContext.Options.OmitDebugInfo, true)) {
 
2165
                                foreach (Statement s in scope_initializers)
 
2166
                                        s.Emit (ec);
 
2167
                        }
 
2168
 
 
2169
                        SymbolWriter.CloseCompilerGeneratedBlock (ec);
 
2170
                }
 
2171
 
 
2172
                protected virtual void EmitSymbolInfo (EmitContext ec)
 
2173
                {
 
2174
                }
 
2175
 
 
2176
#if DEBUG
 
2177
                public override string ToString ()
 
2178
                {
 
2179
                        return String.Format ("{0} ({1}:{2})", GetType (), ID, StartLocation);
 
2180
                }
 
2181
#endif
 
2182
 
 
2183
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
2184
                {
 
2185
                        Block target = (Block) t;
 
2186
#if DEBUG
 
2187
                        target.clone_id = clone_id_counter++;
 
2188
#endif
 
2189
 
 
2190
                        clonectx.AddBlockMap (this, target);
 
2191
                        if (original != this)
 
2192
                                clonectx.AddBlockMap (original, target);
 
2193
 
 
2194
                        target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
 
2195
                        target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
 
2196
 
 
2197
                        if (Parent != null)
 
2198
                                target.Parent = clonectx.RemapBlockCopy (Parent);
 
2199
 
 
2200
                        target.statements = new List<Statement> (statements.Count);
 
2201
                        foreach (Statement s in statements)
 
2202
                                target.statements.Add (s.Clone (clonectx));
 
2203
                }
 
2204
                public override object Accept (StructuralVisitor visitor)
 
2205
                {
 
2206
                        return visitor.Visit (this);
 
2207
                }
 
2208
        }
 
2209
 
 
2210
        public class ExplicitBlock : Block
 
2211
        {
 
2212
                protected AnonymousMethodStorey am_storey;
 
2213
 
 
2214
                public ExplicitBlock (Block parent, Location start, Location end)
 
2215
                        : this (parent, (Flags) 0, start, end)
 
2216
                {
 
2217
                }
 
2218
 
 
2219
                public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
 
2220
                        : base (parent, flags, start, end)
 
2221
                {
 
2222
                        this.Explicit = this;
 
2223
                }
 
2224
 
 
2225
                #region Properties
 
2226
 
 
2227
                public AnonymousMethodStorey AnonymousMethodStorey {
 
2228
                        get {
 
2229
                                return am_storey;
 
2230
                        }
 
2231
                }
 
2232
 
 
2233
                public bool HasCapturedThis {
 
2234
                        set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
 
2235
                        get {
 
2236
                                return (flags & Flags.HasCapturedThis) != 0;
 
2237
                        }
 
2238
                }
 
2239
 
 
2240
                public bool HasCapturedVariable {
 
2241
                        set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
 
2242
                        get {
 
2243
                                return (flags & Flags.HasCapturedVariable) != 0;
 
2244
                        }
 
2245
                }
 
2246
 
 
2247
                #endregion
 
2248
 
 
2249
                //
 
2250
                // Creates anonymous method storey in current block
 
2251
                //
 
2252
                public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
 
2253
                {
 
2254
                        //
 
2255
                        // An iterator has only 1 storey block
 
2256
                        //
 
2257
                        if (ec.CurrentIterator != null)
 
2258
                            return ec.CurrentIterator.Storey;
 
2259
 
 
2260
                        //
 
2261
                        // When referencing a variable in iterator storey from children anonymous method
 
2262
                        //
 
2263
                        if (ParametersBlock.am_storey is IteratorStorey) {
 
2264
                                return ParametersBlock.am_storey;
 
2265
                        }
 
2266
 
 
2267
                        if (am_storey == null) {
 
2268
                                MemberBase mc = ec.MemberContext as MemberBase;
 
2269
 
 
2270
                                //
 
2271
                                // Creates anonymous method storey for this block
 
2272
                                //
 
2273
                                am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey");
 
2274
                        }
 
2275
 
 
2276
                        return am_storey;
 
2277
                }
 
2278
 
 
2279
                public override void Emit (EmitContext ec)
 
2280
                {
 
2281
                        if (am_storey != null) {
 
2282
                                DefineAnonymousStorey (ec);
 
2283
                                am_storey.EmitStoreyInstantiation (ec, this);
 
2284
                        }
 
2285
 
 
2286
                        bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
 
2287
                        if (emit_debug_info)
 
2288
                                ec.BeginScope ();
 
2289
 
 
2290
                        base.Emit (ec);
 
2291
 
 
2292
                        if (emit_debug_info)
 
2293
                                ec.EndScope ();
 
2294
                }
 
2295
 
 
2296
                void DefineAnonymousStorey (EmitContext ec)
 
2297
                {
 
2298
                        //
 
2299
                        // Creates anonymous method storey
 
2300
                        //
 
2301
                        if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
 
2302
                                //
 
2303
                                // Creates parent storey reference when hoisted this is accessible
 
2304
                                //
 
2305
                                if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
 
2306
                                        ExplicitBlock parent = am_storey.OriginalSourceBlock.Explicit.Parent.Explicit;
 
2307
 
 
2308
                                        //
 
2309
                                        // Hoisted this exists in top-level parent storey only
 
2310
                                        //
 
2311
                                        while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
 
2312
                                                parent = parent.Parent.Explicit;
 
2313
 
 
2314
                                        am_storey.AddParentStoreyReference (ec, parent.am_storey);
 
2315
                                }
 
2316
 
 
2317
                                am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
 
2318
 
 
2319
                                // TODO MemberCache: Review
 
2320
                                am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
 
2321
                        }
 
2322
 
 
2323
                        am_storey.CreateType ();
 
2324
                        am_storey.DefineType ();
 
2325
                        am_storey.ResolveTypeParameters ();
 
2326
 
 
2327
                        var ref_blocks = am_storey.ReferencesFromChildrenBlock;
 
2328
                        if (ref_blocks != null) {
 
2329
                                foreach (ExplicitBlock ref_block in ref_blocks) {
 
2330
                                        for (ExplicitBlock b = ref_block.Explicit; b.am_storey != am_storey; b = b.Parent.Explicit) {
 
2331
                                                if (b.am_storey != null) {
 
2332
                                                        b.am_storey.AddParentStoreyReference (ec, am_storey);
 
2333
 
 
2334
                                                        // Stop propagation inside same top block
 
2335
                                                        if (b.ParametersBlock.Original == ParametersBlock.Original)
 
2336
                                                                break;
 
2337
 
 
2338
                                                        b = b.ParametersBlock;
 
2339
                                                }
 
2340
 
 
2341
                                                b.HasCapturedVariable = true;
 
2342
                                        }
 
2343
                                }
 
2344
                        }
 
2345
 
 
2346
                        am_storey.Define ();
 
2347
                        am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
 
2348
                }
 
2349
 
 
2350
                public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
 
2351
                {
 
2352
                        tryBlock.statements = statements;
 
2353
                        statements = new List<Statement> (1);
 
2354
                        statements.Add (tf);
 
2355
                }
 
2356
        }
 
2357
 
 
2358
        //
 
2359
        // ParametersBlock was introduced to support anonymous methods
 
2360
        // and lambda expressions
 
2361
        // 
 
2362
        public class ParametersBlock : ExplicitBlock
 
2363
        {
 
2364
                public class ParameterInfo : INamedBlockVariable
 
2365
                {
 
2366
                        readonly ParametersBlock block;
 
2367
                        readonly int index;
 
2368
                        public VariableInfo VariableInfo;
 
2369
                        bool is_locked;
 
2370
 
 
2371
                        public ParameterInfo (ParametersBlock block, int index)
 
2372
                        {
 
2373
                                this.block = block;
 
2374
                                this.index = index;
 
2375
                        }
 
2376
 
 
2377
                        #region Properties
 
2378
 
 
2379
                        public Block Block {
 
2380
                                get {
 
2381
                                        return block;
 
2382
                                }
 
2383
                        }
 
2384
 
 
2385
                        public bool IsDeclared {
 
2386
                                get {
 
2387
                                        return true;
 
2388
                                }
 
2389
                        }
 
2390
 
 
2391
                        public bool IsLocked {
 
2392
                                get {
 
2393
                                        return is_locked;
 
2394
                                }
 
2395
                                set {
 
2396
                                        is_locked = value;
 
2397
                                }
 
2398
                        }
 
2399
 
 
2400
                        public Location Location {
 
2401
                                get {
 
2402
                                        return Parameter.Location;
 
2403
                                }
 
2404
                        }
 
2405
 
 
2406
                        public Parameter Parameter {
 
2407
                                get {
 
2408
                                        return block.Parameters [index];
 
2409
                                }
 
2410
                        }
 
2411
 
 
2412
                        public TypeSpec ParameterType {
 
2413
                                get {
 
2414
                                        return Parameter.Type;
 
2415
                                }
 
2416
                        }
 
2417
 
 
2418
                        #endregion
 
2419
 
 
2420
                        public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
 
2421
                        {
 
2422
                                return new ParameterReference (this, loc);
 
2423
                        }
 
2424
                }
 
2425
 
 
2426
                // 
 
2427
                // Block is converted to an expression
 
2428
                //
 
2429
                sealed class BlockScopeExpression : Expression
 
2430
                {
 
2431
                        Expression child;
 
2432
                        readonly ParametersBlock block;
 
2433
 
 
2434
                        public BlockScopeExpression (Expression child, ParametersBlock block)
 
2435
                        {
 
2436
                                this.child = child;
 
2437
                                this.block = block;
 
2438
                        }
 
2439
 
 
2440
                        public override Expression CreateExpressionTree (ResolveContext ec)
 
2441
                        {
 
2442
                                throw new NotSupportedException ();
 
2443
                        }
 
2444
 
 
2445
                        protected override Expression DoResolve (ResolveContext ec)
 
2446
                        {
 
2447
                                if (child == null)
 
2448
                                        return null;
 
2449
 
 
2450
                                child = child.Resolve (ec);
 
2451
                                if (child == null)
 
2452
                                        return null;
 
2453
 
 
2454
                                eclass = child.eclass;
 
2455
                                type = child.Type;
 
2456
                                return this;
 
2457
                        }
 
2458
 
 
2459
                        public override void Emit (EmitContext ec)
 
2460
                        {
 
2461
                                block.EmitScopeInitializers (ec);
 
2462
                                child.Emit (ec);
 
2463
                        }
 
2464
                }
 
2465
 
 
2466
                protected ParametersCompiled parameters;
 
2467
                protected ParameterInfo[] parameter_info;
 
2468
                bool resolved;
 
2469
                protected bool unreachable;
 
2470
                protected ToplevelBlock top_block;
 
2471
 
 
2472
                public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
 
2473
                        : base (parent, 0, start, start)
 
2474
                {
 
2475
                        if (parameters == null)
 
2476
                                throw new ArgumentNullException ("parameters");
 
2477
 
 
2478
                        this.parameters = parameters;
 
2479
                        ParametersBlock = this;
 
2480
 
 
2481
                        this.top_block = parent.ParametersBlock.top_block;
 
2482
                        ProcessParameters ();
 
2483
                }
 
2484
 
 
2485
                protected ParametersBlock (ParametersCompiled parameters, Location start)
 
2486
                        : base (null, 0, start, start)
 
2487
                {
 
2488
                        if (parameters == null)
 
2489
                                throw new ArgumentNullException ("parameters");
 
2490
 
 
2491
                        this.parameters = parameters;
 
2492
                        ParametersBlock = this;
 
2493
                }
 
2494
 
 
2495
                //
 
2496
                // It's supposed to be used by method body implementation of anonymous methods
 
2497
                //
 
2498
                protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
 
2499
                        : base (null, 0, source.StartLocation, source.EndLocation)
 
2500
                {
 
2501
                        this.parameters = parameters;
 
2502
                        this.statements = source.statements;
 
2503
                        this.scope_initializers = source.scope_initializers;
 
2504
 
 
2505
                        this.resolved = true;
 
2506
                        this.unreachable = source.unreachable;
 
2507
                        this.am_storey = source.am_storey;
 
2508
 
 
2509
                        ParametersBlock = this;
 
2510
 
 
2511
                        //
 
2512
                        // Overwrite original for comparison purposes when linking cross references
 
2513
                        // between anonymous methods
 
2514
                        //
 
2515
                        original = source;
 
2516
                }
 
2517
 
 
2518
                #region Properties
 
2519
 
 
2520
                //
 
2521
                // Block has been converted to expression tree
 
2522
                //
 
2523
                public bool IsExpressionTree {
 
2524
                        get {
 
2525
                                return (flags & Flags.IsExpressionTree) != 0;
 
2526
                        }
 
2527
                }
 
2528
 
 
2529
                //
 
2530
                // The parameters for the block.
 
2531
                //
 
2532
                public ParametersCompiled Parameters {
 
2533
                        get {
 
2534
                                return parameters;
 
2535
                        }
 
2536
                }
 
2537
 
 
2538
                public ToplevelBlock TopBlock {
 
2539
                        get {
 
2540
                                return top_block;
 
2541
                        }
 
2542
                }
 
2543
 
 
2544
                public bool Resolved {
 
2545
                        get {
 
2546
                                return resolved;
 
2547
                        }
 
2548
                }
 
2549
 
 
2550
                #endregion
 
2551
 
 
2552
                // <summary>
 
2553
                //   Check whether all `out' parameters have been assigned.
 
2554
                // </summary>
 
2555
                public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
 
2556
                {
 
2557
                        if (vector.IsUnreachable)
 
2558
                                return;
 
2559
 
 
2560
                        int n = parameter_info == null ? 0 : parameter_info.Length;
 
2561
 
 
2562
                        for (int i = 0; i < n; i++) {
 
2563
                                VariableInfo var = parameter_info[i].VariableInfo;
 
2564
 
 
2565
                                if (var == null)
 
2566
                                        continue;
 
2567
 
 
2568
                                if (vector.IsAssigned (var, false))
 
2569
                                        continue;
 
2570
 
 
2571
                                TopBlock.Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
 
2572
                                        var.Name);
 
2573
                        }
 
2574
                }
 
2575
 
 
2576
                public override Expression CreateExpressionTree (ResolveContext ec)
 
2577
                {
 
2578
                        if (statements.Count == 1) {
 
2579
                                Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
 
2580
                                if (scope_initializers != null)
 
2581
                                        expr = new BlockScopeExpression (expr, this);
 
2582
 
 
2583
                                return expr;
 
2584
                        }
 
2585
 
 
2586
                        return base.CreateExpressionTree (ec);
 
2587
                }
 
2588
 
 
2589
                public ParameterInfo GetParameterInfo (Parameter p)
 
2590
                {
 
2591
                        for (int i = 0; i < parameters.Count; ++i) {
 
2592
                                if (parameters[i] == p)
 
2593
                                        return parameter_info[i];
 
2594
                        }
 
2595
 
 
2596
                        throw new ArgumentException ("Invalid parameter");
 
2597
                }
 
2598
 
 
2599
                public Expression GetParameterReference (int index, Location loc)
 
2600
                {
 
2601
                        return new ParameterReference (parameter_info[index], loc);
 
2602
                }
 
2603
 
 
2604
                public Statement PerformClone ()
 
2605
                {
 
2606
                        CloneContext clonectx = new CloneContext ();
 
2607
                        return Clone (clonectx);
 
2608
                }
 
2609
 
 
2610
                protected void ProcessParameters ()
 
2611
                {
 
2612
                        if (parameters.Count == 0)
 
2613
                                return;
 
2614
 
 
2615
                        parameter_info = new ParameterInfo[parameters.Count];
 
2616
                        for (int i = 0; i < parameter_info.Length; ++i) {
 
2617
                                var p = parameters.FixedParameters[i];
 
2618
                                if (p == null)
 
2619
                                        continue;
 
2620
 
 
2621
                                // TODO: Should use Parameter only and more block there
 
2622
                                parameter_info[i] = new ParameterInfo (this, i);
 
2623
                                if (p.Name != null)
 
2624
                                        AddLocalName (p.Name, parameter_info[i]);
 
2625
                        }
 
2626
                }
 
2627
 
 
2628
                public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md)
 
2629
                {
 
2630
                        if (resolved)
 
2631
                                return true;
 
2632
 
 
2633
                        resolved = true;
 
2634
 
 
2635
                        if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
 
2636
                                flags |= Flags.IsExpressionTree;
 
2637
 
 
2638
                        try {
 
2639
                                ResolveMeta (rc);
 
2640
 
 
2641
                                using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
 
2642
                                        FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
 
2643
 
 
2644
                                        if (!Resolve (rc))
 
2645
                                                return false;
 
2646
 
 
2647
                                        unreachable = top_level.End ();
 
2648
                                }
 
2649
                        } catch (Exception e) {
 
2650
                                if (e is CompletionResult || rc.Report.IsDisabled)
 
2651
                                        throw;
 
2652
 
 
2653
                                if (rc.CurrentBlock != null) {
 
2654
                                        rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
 
2655
                                } else {
 
2656
                                        rc.Report.Error (587, "Internal compiler error: {0}", e.Message);
 
2657
                                }
 
2658
 
 
2659
                                if (rc.Module.Compiler.Settings.DebugFlags > 0)
 
2660
                                        throw;
 
2661
                        }
 
2662
 
 
2663
                        if (rc.ReturnType.Kind != MemberKind.Void && !unreachable) {
 
2664
                                if (rc.CurrentAnonymousMethod == null) {
 
2665
                                        // FIXME: Missing FlowAnalysis for generated iterator MoveNext method
 
2666
                                        if (md is IteratorMethod) {
 
2667
                                                unreachable = true;
 
2668
                                        } else {
 
2669
                                                rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
 
2670
                                                return false;
 
2671
                                        }
 
2672
                                } else {
 
2673
                                        rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
 
2674
                                                          rc.CurrentAnonymousMethod.GetSignatureForError ());
 
2675
                                        return false;
 
2676
                                }
 
2677
                        }
 
2678
 
 
2679
                        return true;
 
2680
                }
 
2681
 
 
2682
                void ResolveMeta (BlockContext ec)
 
2683
                {
 
2684
                        int orig_count = parameters.Count;
 
2685
 
 
2686
                        for (int i = 0; i < orig_count; ++i) {
 
2687
                                Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
 
2688
 
 
2689
                                if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
 
2690
                                        continue;
 
2691
 
 
2692
                                VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
 
2693
                                parameter_info[i].VariableInfo = vi;
 
2694
                                ec.FlowOffset += vi.Length;
 
2695
                        }
 
2696
                }
 
2697
 
 
2698
                public void WrapIntoIterator (IMethodData method, TypeContainer host, TypeSpec iterator_type, bool is_enumerable)
 
2699
                {
 
2700
                        ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
 
2701
                        pb.EndLocation = EndLocation;
 
2702
                        pb.statements = statements;
 
2703
 
 
2704
                        var iterator = new Iterator (pb, method, host, iterator_type, is_enumerable);
 
2705
                        am_storey = new IteratorStorey (iterator);
 
2706
 
 
2707
                        statements = new List<Statement> (1);
 
2708
                        AddStatement (new Return (iterator, iterator.Location));
 
2709
                }
 
2710
        }
 
2711
 
 
2712
        //
 
2713
        //
 
2714
        //
 
2715
        public class ToplevelBlock : ParametersBlock
 
2716
        {
 
2717
                LocalVariable this_variable;
 
2718
                CompilerContext compiler;
 
2719
                Dictionary<string, object> names;
 
2720
                Dictionary<string, object> labels;
 
2721
 
 
2722
                public HoistedVariable HoistedThisVariable;
 
2723
 
 
2724
                public Report Report {
 
2725
                        get { return compiler.Report; }
 
2726
                }
 
2727
 
 
2728
                public ToplevelBlock (CompilerContext ctx, Location loc)
 
2729
                        : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
 
2730
                {
 
2731
                }
 
2732
 
 
2733
                public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start)
 
2734
                        : base (parameters, start)
 
2735
                {
 
2736
                        this.compiler = ctx;
 
2737
                        top_block = this;
 
2738
 
 
2739
                        ProcessParameters ();
 
2740
                }
 
2741
 
 
2742
                //
 
2743
                // Recreates a top level block from parameters block. Used for
 
2744
                // compiler generated methods where the original block comes from
 
2745
                // explicit child block. This works for already resolved blocks
 
2746
                // only to ensure we resolve them in the correct flow order
 
2747
                //
 
2748
                public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
 
2749
                        : base (source, parameters)
 
2750
                {
 
2751
                        this.compiler = source.TopBlock.compiler;
 
2752
                        top_block = this;
 
2753
                }
 
2754
 
 
2755
                public override void AddLocalName (string name, INamedBlockVariable li)
 
2756
                {
 
2757
                        if (names == null)
 
2758
                                names = new Dictionary<string, object> ();
 
2759
 
 
2760
                        object value;
 
2761
                        if (!names.TryGetValue (name, out value)) {
 
2762
                                names.Add (name, li);
 
2763
                                return;
 
2764
                        }
 
2765
 
 
2766
                        INamedBlockVariable existing = value as INamedBlockVariable;
 
2767
                        List<INamedBlockVariable> existing_list;
 
2768
                        if (existing != null) {
 
2769
                                existing_list = new List<INamedBlockVariable> ();
 
2770
                                existing_list.Add (existing);
 
2771
                                names[name] = existing_list;
 
2772
                        } else {
 
2773
                                existing_list = (List<INamedBlockVariable>) value;
 
2774
                        }
 
2775
 
 
2776
                        //
 
2777
                        // A collision checking between local names
 
2778
                        //
 
2779
                        for (int i = 0; i < existing_list.Count; ++i) {
 
2780
                                existing = existing_list[i];
 
2781
                                Block b = existing.Block;
 
2782
 
 
2783
                                // Collision at same level
 
2784
                                if (li.Block == b) {
 
2785
                                        li.Block.Error_AlreadyDeclared (name, li);
 
2786
                                        break;
 
2787
                                }
 
2788
 
 
2789
                                // Collision with parent
 
2790
                                b = li.Block;
 
2791
                                while ((b = b.Parent) != null) {
 
2792
                                        if (existing.Block == b) {
 
2793
                                                li.Block.Error_AlreadyDeclared (name, li, "parent or current");
 
2794
                                                i = existing_list.Count;
 
2795
                                                break;
 
2796
                                        }
 
2797
                                }
 
2798
 
 
2799
                                // Collision with with children
 
2800
                                b = existing.Block;
 
2801
                                while ((b = b.Parent) != null) {
 
2802
                                        if (li.Block == b) {
 
2803
                                                li.Block.Error_AlreadyDeclared (name, li, "child");
 
2804
                                                i = existing_list.Count;
 
2805
                                                break;
 
2806
                                        }
 
2807
                                }
 
2808
                        }
 
2809
 
 
2810
                        existing_list.Add (li);
 
2811
                }
 
2812
 
 
2813
                public void AddLabel (string name, LabeledStatement label)
 
2814
                {
 
2815
                        if (labels == null)
 
2816
                                labels = new Dictionary<string, object> ();
 
2817
 
 
2818
                        object value;
 
2819
                        if (!labels.TryGetValue (name, out value)) {
 
2820
                                labels.Add (name, label);
 
2821
                                return;
 
2822
                        }
 
2823
 
 
2824
                        LabeledStatement existing = value as LabeledStatement;
 
2825
                        List<LabeledStatement> existing_list;
 
2826
                        if (existing != null) {
 
2827
                                existing_list = new List<LabeledStatement> ();
 
2828
                                existing_list.Add (existing);
 
2829
                                labels[name] = existing_list;
 
2830
                        } else {
 
2831
                                existing_list = (List<LabeledStatement>) value;
 
2832
                        }
 
2833
 
 
2834
                        //
 
2835
                        // A collision checking between labels
 
2836
                        //
 
2837
                        for (int i = 0; i < existing_list.Count; ++i) {
 
2838
                                existing = existing_list[i];
 
2839
                                Block b = existing.Block;
 
2840
 
 
2841
                                // Collision at same level
 
2842
                                if (label.Block == b) {
 
2843
                                        Report.SymbolRelatedToPreviousError (existing.loc, name);
 
2844
                                        Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
 
2845
                                        break;
 
2846
                                }
 
2847
 
 
2848
                                // Collision with parent
 
2849
                                b = label.Block;
 
2850
                                while ((b = b.Parent) != null) {
 
2851
                                        if (existing.Block == b) {
 
2852
                                                Report.Error (158, label.loc,
 
2853
                                                        "The label `{0}' shadows another label by the same name in a contained scope", name);
 
2854
                                                i = existing_list.Count;
 
2855
                                                break;
 
2856
                                        }
 
2857
                                }
 
2858
 
 
2859
                                // Collision with with children
 
2860
                                b = existing.Block;
 
2861
                                while ((b = b.Parent) != null) {
 
2862
                                        if (label.Block == b) {
 
2863
                                                Report.Error (158, label.loc,
 
2864
                                                        "The label `{0}' shadows another label by the same name in a contained scope", name);
 
2865
                                                i = existing_list.Count;
 
2866
                                                break;
 
2867
                                        }
 
2868
                                }
 
2869
                        }
 
2870
 
 
2871
                        existing_list.Add (label);
 
2872
                }
 
2873
 
 
2874
                //
 
2875
                // Creates an arguments set from all parameters, useful for method proxy calls
 
2876
                //
 
2877
                public Arguments GetAllParametersArguments ()
 
2878
                {
 
2879
                        int count = parameters.Count;
 
2880
                        Arguments args = new Arguments (count);
 
2881
                        for (int i = 0; i < count; ++i) {
 
2882
                                var arg_expr = GetParameterReference (i, parameter_info[i].Location);
 
2883
                                args.Add (new Argument (arg_expr));
 
2884
                        }
 
2885
 
 
2886
                        return args;
 
2887
                }
 
2888
 
 
2889
                //
 
2890
                // Lookup inside a block, the returned value can represent 3 states
 
2891
                //
 
2892
                // true+variable: A local name was found and it's valid
 
2893
                // false+variable: A local name was found in a child block only
 
2894
                // false+null: No local name was found
 
2895
                //
 
2896
                public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
 
2897
                {
 
2898
                        if (names == null)
 
2899
                                return false;
 
2900
 
 
2901
                        object value;
 
2902
                        if (!names.TryGetValue (name, out value))
 
2903
                                return false;
 
2904
 
 
2905
                        variable = value as INamedBlockVariable;
 
2906
                        Block b = block;
 
2907
                        if (variable != null) {
 
2908
                                do {
 
2909
                                        if (variable.Block == b.Original)
 
2910
                                                return true;
 
2911
 
 
2912
                                        b = b.Parent;
 
2913
                                } while (b != null);
 
2914
 
 
2915
                                b = variable.Block;
 
2916
                                do {
 
2917
                                        if (block == b)
 
2918
                                                return false;
 
2919
 
 
2920
                                        b = b.Parent;
 
2921
                                } while (b != null);
 
2922
                        } else {
 
2923
                                List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
 
2924
                                for (int i = 0; i < list.Count; ++i) {
 
2925
                                        variable = list[i];
 
2926
                                        do {
 
2927
                                                if (variable.Block == b.Original)
 
2928
                                                        return true;
 
2929
 
 
2930
                                                b = b.Parent;
 
2931
                                        } while (b != null);
 
2932
 
 
2933
                                        b = variable.Block;
 
2934
                                        do {
 
2935
                                                if (block == b)
 
2936
                                                        return false;
 
2937
 
 
2938
                                                b = b.Parent;
 
2939
                                        } while (b != null);
 
2940
 
 
2941
                                        b = block;
 
2942
                                }
 
2943
                        }
 
2944
 
 
2945
                        variable = null;
 
2946
                        return false;
 
2947
                }
 
2948
 
 
2949
                public LabeledStatement GetLabel (string name, Block block)
 
2950
                {
 
2951
                        if (labels == null)
 
2952
                                return null;
 
2953
 
 
2954
                        object value;
 
2955
                        if (!labels.TryGetValue (name, out value)) {
 
2956
                                return null;
 
2957
                        }
 
2958
 
 
2959
                        var label = value as LabeledStatement;
 
2960
                        Block b = block;
 
2961
                        if (label != null) {
 
2962
                                if (label.Block == b.Original)
 
2963
                                        return label;
 
2964
 
 
2965
                                // TODO: Temporary workaround for the switch block implicit label block
 
2966
                                if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
 
2967
                                        return label;
 
2968
                        } else {
 
2969
                                List<LabeledStatement> list = (List<LabeledStatement>) value;
 
2970
                                for (int i = 0; i < list.Count; ++i) {
 
2971
                                        label = list[i];
 
2972
                                        if (label.Block == b.Original)
 
2973
                                                return label;
 
2974
 
 
2975
                                        // TODO: Temporary workaround for the switch block implicit label block
 
2976
                                        if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
 
2977
                                                return label;
 
2978
                                }
 
2979
                        }
 
2980
                                
 
2981
                        return null;
 
2982
                }
 
2983
 
 
2984
                // <summary>
 
2985
                //   Returns the "this" instance variable of this block.
 
2986
                //   See AddThisVariable() for more information.
 
2987
                // </summary>
 
2988
                public LocalVariable ThisVariable {
 
2989
                        get { return this_variable; }
 
2990
                }
 
2991
 
 
2992
                // <summary>
 
2993
                //   This is used by non-static `struct' constructors which do not have an
 
2994
                //   initializer - in this case, the constructor must initialize all of the
 
2995
                //   struct's fields.  To do this, we add a "this" variable and use the flow
 
2996
                //   analysis code to ensure that it's been fully initialized before control
 
2997
                //   leaves the constructor.
 
2998
                // </summary>
 
2999
                public LocalVariable AddThisVariable (BlockContext bc, TypeContainer ds, Location l)
 
3000
                {
 
3001
                        if (this_variable == null) {
 
3002
                                this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, l);
 
3003
                                this_variable.Type = ds.CurrentType;
 
3004
                                this_variable.PrepareForFlowAnalysis (bc);
 
3005
                        }
 
3006
 
 
3007
                        return this_variable;
 
3008
                }
 
3009
 
 
3010
                public bool IsIterator {
 
3011
                        get { return (flags & Flags.IsIterator) != 0; }
 
3012
                        set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
 
3013
                }
 
3014
 
 
3015
                public bool IsThisAssigned (BlockContext ec)
 
3016
                {
 
3017
                        return this_variable == null || this_variable.IsThisAssigned (ec, this);
 
3018
                }
 
3019
 
 
3020
                public override void Emit (EmitContext ec)
 
3021
                {
 
3022
                        if (Report.Errors > 0)
 
3023
                                return;
 
3024
 
 
3025
#if PRODUCTION
 
3026
                        try {
 
3027
#endif
 
3028
                        if (ec.HasReturnLabel)
 
3029
                                ec.ReturnLabel = ec.DefineLabel ();
 
3030
 
 
3031
                        base.Emit (ec);
 
3032
 
 
3033
                        ec.Mark (EndLocation);
 
3034
 
 
3035
                        if (ec.HasReturnLabel)
 
3036
                                ec.MarkLabel (ec.ReturnLabel);
 
3037
 
 
3038
                        if (ec.return_value != null) {
 
3039
                                ec.Emit (OpCodes.Ldloc, ec.return_value);
 
3040
                                ec.Emit (OpCodes.Ret);
 
3041
                        } else {
 
3042
                                //
 
3043
                                // If `HasReturnLabel' is set, then we already emitted a
 
3044
                                // jump to the end of the method, so we must emit a `ret'
 
3045
                                // there.
 
3046
                                //
 
3047
                                // Unfortunately, System.Reflection.Emit automatically emits
 
3048
                                // a leave to the end of a finally block.  This is a problem
 
3049
                                // if no code is following the try/finally block since we may
 
3050
                                // jump to a point after the end of the method.
 
3051
                                // As a workaround, we're always creating a return label in
 
3052
                                // this case.
 
3053
                                //
 
3054
 
 
3055
                                if (ec.HasReturnLabel || !unreachable) {
 
3056
                                        if (ec.ReturnType.Kind != MemberKind.Void)
 
3057
                                                ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
 
3058
                                        ec.Emit (OpCodes.Ret);
 
3059
                                }
 
3060
                        }
 
3061
 
 
3062
#if PRODUCTION
 
3063
                        } catch (Exception e){
 
3064
                                Console.WriteLine ("Exception caught by the compiler while emitting:");
 
3065
                                Console.WriteLine ("   Block that caused the problem begin at: " + block.loc);
 
3066
                                        
 
3067
                                Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
 
3068
                                throw;
 
3069
                        }
 
3070
#endif
 
3071
                }
 
3072
 
 
3073
                protected override void EmitSymbolInfo (EmitContext ec)
 
3074
                {
 
3075
                        AnonymousExpression ae = ec.CurrentAnonymousMethod;
 
3076
                        if ((ae != null) && (ae.Storey != null))
 
3077
                                SymbolWriter.DefineScopeVariable (ae.Storey.ID);
 
3078
 
 
3079
                        base.EmitSymbolInfo (ec);
 
3080
                }
 
3081
        }
 
3082
        
 
3083
        public class SwitchLabel {
 
3084
                Expression label;
 
3085
                Constant converted;
 
3086
                readonly Location loc;
 
3087
 
 
3088
                Label? il_label;
 
3089
 
 
3090
                //
 
3091
                // if expr == null, then it is the default case.
 
3092
                //
 
3093
                public SwitchLabel (Expression expr, Location l)
 
3094
                {
 
3095
                        label = expr;
 
3096
                        loc = l;
 
3097
                }
 
3098
 
 
3099
                public bool IsDefault {
 
3100
                        get {
 
3101
                                return label == null;
 
3102
                        }
 
3103
                }
 
3104
 
 
3105
                public Expression Label {
 
3106
                        get {
 
3107
                                return label;
 
3108
                        }
 
3109
                }
 
3110
 
 
3111
                public Location Location {
 
3112
                        get {
 
3113
                                return loc;
 
3114
                        }
 
3115
                }
 
3116
 
 
3117
                public Constant Converted {
 
3118
                        get {
 
3119
                                return converted;
 
3120
                        }
 
3121
                        set {
 
3122
                                converted = value;
 
3123
                        }
 
3124
                }
 
3125
 
 
3126
                public Label GetILLabel (EmitContext ec)
 
3127
                {
 
3128
                        if (il_label == null){
 
3129
                                il_label = ec.DefineLabel ();
 
3130
                        }
 
3131
 
 
3132
                        return il_label.Value;
 
3133
                }
 
3134
 
 
3135
                //
 
3136
                // Resolves the expression, reduces it to a literal if possible
 
3137
                // and then converts it to the requested type.
 
3138
                //
 
3139
                public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
 
3140
                {       
 
3141
                        Expression e = label.Resolve (ec);
 
3142
 
 
3143
                        if (e == null)
 
3144
                                return false;
 
3145
 
 
3146
                        Constant c = e as Constant;
 
3147
                        if (c == null){
 
3148
                                ec.Report.Error (150, loc, "A constant value is expected");
 
3149
                                return false;
 
3150
                        }
 
3151
 
 
3152
                        if (allow_nullable && c is NullLiteral) {
 
3153
                                converted = c;
 
3154
                                return true;
 
3155
                        }
 
3156
 
 
3157
                        converted = c.ImplicitConversionRequired (ec, required_type, loc);
 
3158
                        return converted != null;
 
3159
                }
 
3160
 
 
3161
                public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
 
3162
                {
 
3163
                        string label;
 
3164
                        if (converted == null)
 
3165
                                label = "default";
 
3166
                        else
 
3167
                                label = converted.GetValueAsLiteral ();
 
3168
                        
 
3169
                        ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
 
3170
                        ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
 
3171
                }
 
3172
 
 
3173
                public SwitchLabel Clone (CloneContext clonectx)
 
3174
                {
 
3175
                        if (label == null)
 
3176
                                return this;
 
3177
 
 
3178
                        return new SwitchLabel (label.Clone (clonectx), loc);
 
3179
                }
 
3180
        }
 
3181
 
 
3182
        public class SwitchSection {
 
3183
                public readonly List<SwitchLabel> Labels;
 
3184
                public readonly Block Block;
 
3185
                
 
3186
                public SwitchSection (List<SwitchLabel> labels, Block block)
 
3187
                {
 
3188
                        Labels = labels;
 
3189
                        Block = block;
 
3190
                }
 
3191
 
 
3192
                public SwitchSection Clone (CloneContext clonectx)
 
3193
                {
 
3194
                        var cloned_labels = new List<SwitchLabel> ();
 
3195
 
 
3196
                        foreach (SwitchLabel sl in Labels)
 
3197
                                cloned_labels.Add (sl.Clone (clonectx));
 
3198
                        
 
3199
                        return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
 
3200
                }
 
3201
        }
 
3202
        
 
3203
        public class Switch : Statement
 
3204
        {
 
3205
                // structure used to hold blocks of keys while calculating table switch
 
3206
                sealed class LabelsRange : IComparable<LabelsRange>
 
3207
                {
 
3208
                        public readonly long min;
 
3209
                        public long max;
 
3210
                        public readonly List<long> label_values;
 
3211
 
 
3212
                        public LabelsRange (long value)
 
3213
                        {
 
3214
                                min = max = value;
 
3215
                                label_values = new List<long> ();
 
3216
                                label_values.Add (value);
 
3217
                        }
 
3218
 
 
3219
                        public LabelsRange (long min, long max, ICollection<long> values)
 
3220
                        {
 
3221
                                this.min = min;
 
3222
                                this.max = max;
 
3223
                                this.label_values = new List<long> (values);
 
3224
                        }
 
3225
 
 
3226
                        public long Range {
 
3227
                                get {
 
3228
                                        return max - min + 1;
 
3229
                                }
 
3230
                        }
 
3231
 
 
3232
                        public bool AddValue (long value)
 
3233
                        {
 
3234
                                var gap = value - min + 1;
 
3235
                                // Ensure the range has > 50% occupancy
 
3236
                                if (gap > 2 * (label_values.Count + 1) || gap <= 0)
 
3237
                                        return false;
 
3238
 
 
3239
                                max = value;
 
3240
                                label_values.Add (value);
 
3241
                                return true;
 
3242
                        }
 
3243
 
 
3244
                        public int CompareTo (LabelsRange other)
 
3245
                        {
 
3246
                                int nLength = label_values.Count;
 
3247
                                int nLengthOther = other.label_values.Count;
 
3248
                                if (nLengthOther == nLength)
 
3249
                                        return (int) (other.min - min);
 
3250
 
 
3251
                                return nLength - nLengthOther;
 
3252
                        }
 
3253
                }
 
3254
 
 
3255
                public List<SwitchSection> Sections;
 
3256
                public Expression Expr;
 
3257
 
 
3258
                //
 
3259
                // Mapping of all labels to their SwitchLabels
 
3260
                //
 
3261
                Dictionary<long, SwitchLabel> labels;
 
3262
                Dictionary<string, SwitchLabel> string_labels;
 
3263
 
 
3264
                /// <summary>
 
3265
                ///   The governing switch type
 
3266
                /// </summary>
 
3267
                public TypeSpec SwitchType;
 
3268
 
 
3269
                //
 
3270
                // Computed
 
3271
                //
 
3272
                Label default_target;
 
3273
                Label null_target;
 
3274
                Expression new_expr;
 
3275
                bool is_constant;
 
3276
 
 
3277
                SwitchSection constant_section;
 
3278
                SwitchSection default_section;
 
3279
                SwitchLabel null_section;
 
3280
 
 
3281
                ExpressionStatement string_dictionary;
 
3282
                FieldExpr switch_cache_field;
 
3283
                static int unique_counter;
 
3284
                ExplicitBlock block;
 
3285
 
 
3286
                //
 
3287
                // Nullable Types support
 
3288
                //
 
3289
                Nullable.Unwrap unwrap;
 
3290
 
 
3291
                public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
 
3292
                {
 
3293
                        Expr = e;
 
3294
                        this.block = block;
 
3295
                        Sections = sects;
 
3296
                        loc = l;
 
3297
                }
 
3298
 
 
3299
                public ExplicitBlock Block {
 
3300
                        get {
 
3301
                                return block;
 
3302
                        }
 
3303
                }
 
3304
 
 
3305
                public Label DefaultLabel {
 
3306
                        get {
 
3307
                                return default_target;
 
3308
                        }
 
3309
                }
 
3310
 
 
3311
                public bool GotDefault {
 
3312
                        get {
 
3313
                                return default_section != null;
 
3314
                        }
 
3315
                }
 
3316
 
 
3317
                public bool IsNullable {
 
3318
                        get {
 
3319
                                return unwrap != null;
 
3320
                        }
 
3321
                }
 
3322
 
 
3323
                //
 
3324
                // Determines the governing type for a switch.  The returned
 
3325
                // expression might be the expression from the switch, or an
 
3326
                // expression that includes any potential conversions to
 
3327
                //
 
3328
                Expression SwitchGoverningType (ResolveContext ec, Expression expr)
 
3329
                {
 
3330
                        switch (expr.Type.BuiltinType) {
 
3331
                        case BuiltinTypeSpec.Type.Byte:
 
3332
                        case BuiltinTypeSpec.Type.SByte:
 
3333
                        case BuiltinTypeSpec.Type.UShort:
 
3334
                        case BuiltinTypeSpec.Type.Short:
 
3335
                        case BuiltinTypeSpec.Type.UInt:
 
3336
                        case BuiltinTypeSpec.Type.Int:
 
3337
                        case BuiltinTypeSpec.Type.ULong:
 
3338
                        case BuiltinTypeSpec.Type.Long:
 
3339
                        case BuiltinTypeSpec.Type.Char:
 
3340
                        case BuiltinTypeSpec.Type.String:
 
3341
                        case BuiltinTypeSpec.Type.Bool:
 
3342
                                return expr;
 
3343
                        }
 
3344
 
 
3345
                        if (expr.Type.IsEnum)
 
3346
                                return expr;
 
3347
 
 
3348
                        //
 
3349
                        // Try to find a *user* defined implicit conversion.
 
3350
                        //
 
3351
                        // If there is no implicit conversion, or if there are multiple
 
3352
                        // conversions, we have to report an error
 
3353
                        //
 
3354
                        Expression converted = null;
 
3355
                        foreach (TypeSpec tt in ec.BuiltinTypes.SwitchUserTypes) {
 
3356
                                Expression e;
 
3357
                                
 
3358
                                e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
 
3359
                                if (e == null)
 
3360
                                        continue;
 
3361
 
 
3362
                                //
 
3363
                                // Ignore over-worked ImplicitUserConversions that do
 
3364
                                // an implicit conversion in addition to the user conversion.
 
3365
                                // 
 
3366
                                if (!(e is UserCast))
 
3367
                                        continue;
 
3368
 
 
3369
                                if (converted != null){
 
3370
                                        ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
 
3371
                                        return null;
 
3372
                                }
 
3373
 
 
3374
                                converted = e;
 
3375
                        }
 
3376
                        return converted;
 
3377
                }
 
3378
 
 
3379
                public static TypeSpec[] CreateSwitchUserTypes (BuiltinTypes types)
 
3380
                {
 
3381
                        // LAMESPEC: For some reason it does not contain bool which looks like csc bug
 
3382
                        return new[] {
 
3383
                                types.SByte,
 
3384
                                types.Byte,
 
3385
                                types.Short,
 
3386
                                types.UShort,
 
3387
                                types.Int,
 
3388
                                types.UInt,
 
3389
                                types.Long,
 
3390
                                types.ULong,
 
3391
                                types.Char,
 
3392
                                types.String
 
3393
                        };
 
3394
                }
 
3395
 
 
3396
                //
 
3397
                // Performs the basic sanity checks on the switch statement
 
3398
                // (looks for duplicate keys and non-constant expressions).
 
3399
                //
 
3400
                // It also returns a hashtable with the keys that we will later
 
3401
                // use to compute the switch tables
 
3402
                //
 
3403
                bool CheckSwitch (ResolveContext ec)
 
3404
                {
 
3405
                        bool error = false;
 
3406
                        if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String)
 
3407
                                string_labels = new Dictionary<string, SwitchLabel> (Sections.Count + 1);
 
3408
                        else
 
3409
                                labels = new Dictionary<long, SwitchLabel> (Sections.Count + 1);
 
3410
                                
 
3411
                        foreach (SwitchSection ss in Sections){
 
3412
                                foreach (SwitchLabel sl in ss.Labels){
 
3413
                                        if (sl.IsDefault){
 
3414
                                                if (default_section != null){
 
3415
                                                        sl.Error_AlreadyOccurs (ec, SwitchType, default_section.Labels [0]);
 
3416
                                                        error = true;
 
3417
                                                }
 
3418
                                                default_section = ss;
 
3419
                                                continue;
 
3420
                                        }
 
3421
 
 
3422
                                        if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
 
3423
                                                error = true;
 
3424
                                                continue;
 
3425
                                        }
 
3426
                                        
 
3427
                                        try {
 
3428
                                                if (string_labels != null) {
 
3429
                                                        string s = sl.Converted.GetValue () as string;
 
3430
                                                        if (s == null)
 
3431
                                                                null_section = sl;
 
3432
                                                        else
 
3433
                                                                string_labels.Add (s, sl);
 
3434
                                                } else {
 
3435
                                                        if (sl.Converted is NullLiteral) {
 
3436
                                                                null_section = sl;
 
3437
                                                        } else {
 
3438
                                                                labels.Add (sl.Converted.GetValueAsLong (), sl);
 
3439
                                                        }
 
3440
                                                }
 
3441
                                        } catch (ArgumentException) {
 
3442
                                                if (string_labels != null)
 
3443
                                                        sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
 
3444
                                                else
 
3445
                                                        sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
 
3446
 
 
3447
                                                error = true;
 
3448
                                        }
 
3449
                                }
 
3450
                        }
 
3451
                        return !error;
 
3452
                }
 
3453
                
 
3454
                //
 
3455
                // This method emits code for a lookup-based switch statement (non-string)
 
3456
                // Basically it groups the cases into blocks that are at least half full,
 
3457
                // and then spits out individual lookup opcodes for each block.
 
3458
                // It emits the longest blocks first, and short blocks are just
 
3459
                // handled with direct compares.
 
3460
                //
 
3461
                void EmitTableSwitch (EmitContext ec, Expression val)
 
3462
                {
 
3463
                        Label lbl_default = default_target;
 
3464
 
 
3465
                        if (labels.Count > 0) {
 
3466
                                List<LabelsRange> ranges;
 
3467
                                if (string_labels != null) {
 
3468
                                        // We have done all hard work for string already
 
3469
                                        // setup single range only
 
3470
                                        ranges = new List<LabelsRange> (1);
 
3471
                                        ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
 
3472
                                } else {
 
3473
                                        var element_keys = new long[labels.Count];
 
3474
                                        labels.Keys.CopyTo (element_keys, 0);
 
3475
                                        Array.Sort (element_keys);
 
3476
 
 
3477
                                        //
 
3478
                                        // Build possible ranges of switch labes to reduce number
 
3479
                                        // of comparisons
 
3480
                                        //
 
3481
                                        ranges = new List<LabelsRange> (element_keys.Length);
 
3482
                                        var range = new LabelsRange (element_keys[0]);
 
3483
                                        ranges.Add (range);
 
3484
                                        for (int i = 1; i < element_keys.Length; ++i) {
 
3485
                                                var l = element_keys[i];
 
3486
                                                if (range.AddValue (l))
 
3487
                                                        continue;
 
3488
 
 
3489
                                                range = new LabelsRange (l);
 
3490
                                                ranges.Add (range);
 
3491
                                        }
 
3492
 
 
3493
                                        // sort the blocks so we can tackle the largest ones first
 
3494
                                        ranges.Sort ();
 
3495
                                }
 
3496
 
 
3497
                                TypeSpec compare_type = TypeManager.IsEnumType (SwitchType) ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
 
3498
 
 
3499
                                for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
 
3500
                                        LabelsRange kb = ranges[range_index];
 
3501
                                        lbl_default = (range_index == 0) ? default_target : ec.DefineLabel ();
 
3502
 
 
3503
                                        // Optimize small ranges using simple equality check
 
3504
                                        if (kb.Range <= 2) {
 
3505
                                                foreach (var key in kb.label_values) {
 
3506
                                                        SwitchLabel sl = labels[key];
 
3507
                                                        if (sl.Converted.IsDefaultValue) {
 
3508
                                                                val.EmitBranchable (ec, sl.GetILLabel (ec), false);
 
3509
                                                        } else {
 
3510
                                                                val.Emit (ec);
 
3511
                                                                sl.Converted.Emit (ec);
 
3512
                                                                ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
 
3513
                                                        }
 
3514
                                                }
 
3515
                                        } else {
 
3516
                                                // TODO: if all the keys in the block are the same and there are
 
3517
                                                //       no gaps/defaults then just use a range-check.
 
3518
                                                if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
 
3519
                                                        // TODO: optimize constant/I4 cases
 
3520
 
 
3521
                                                        // check block range (could be > 2^31)
 
3522
                                                        val.Emit (ec);
 
3523
                                                        ec.EmitLong (kb.min);
 
3524
                                                        ec.Emit (OpCodes.Blt, lbl_default);
 
3525
 
 
3526
                                                        val.Emit (ec);
 
3527
                                                        ec.EmitLong (kb.max);
 
3528
                                                        ec.Emit (OpCodes.Bgt, lbl_default);
 
3529
 
 
3530
                                                        // normalize range
 
3531
                                                        val.Emit (ec);
 
3532
                                                        if (kb.min != 0) {
 
3533
                                                                ec.EmitLong (kb.min);
 
3534
                                                                ec.Emit (OpCodes.Sub);
 
3535
                                                        }
 
3536
 
 
3537
                                                        ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
 
3538
                                                } else {
 
3539
                                                        // normalize range
 
3540
                                                        val.Emit (ec);
 
3541
                                                        int first = (int) kb.min;
 
3542
                                                        if (first > 0) {
 
3543
                                                                ec.EmitInt (first);
 
3544
                                                                ec.Emit (OpCodes.Sub);
 
3545
                                                        } else if (first < 0) {
 
3546
                                                                ec.EmitInt (-first);
 
3547
                                                                ec.Emit (OpCodes.Add);
 
3548
                                                        }
 
3549
                                                }
 
3550
 
 
3551
                                                // first, build the list of labels for the switch
 
3552
                                                int iKey = 0;
 
3553
                                                long cJumps = kb.Range;
 
3554
                                                Label[] switch_labels = new Label[cJumps];
 
3555
                                                for (int iJump = 0; iJump < cJumps; iJump++) {
 
3556
                                                        var key = kb.label_values[iKey];
 
3557
                                                        if (key == kb.min + iJump) {
 
3558
                                                                switch_labels[iJump] = labels[key].GetILLabel (ec);
 
3559
                                                                iKey++;
 
3560
                                                        } else {
 
3561
                                                                switch_labels[iJump] = lbl_default;
 
3562
                                                        }
 
3563
                                                }
 
3564
 
 
3565
                                                // emit the switch opcode
 
3566
                                                ec.Emit (OpCodes.Switch, switch_labels);
 
3567
                                        }
 
3568
 
 
3569
                                        // mark the default for this block
 
3570
                                        if (range_index != 0)
 
3571
                                                ec.MarkLabel (lbl_default);
 
3572
                                }
 
3573
 
 
3574
                                // the last default just goes to the end
 
3575
                                if (ranges.Count > 0)
 
3576
                                        ec.Emit (OpCodes.Br, lbl_default);
 
3577
                        }
 
3578
 
 
3579
                        // now emit the code for the sections
 
3580
                        bool found_default = false;
 
3581
 
 
3582
                        foreach (SwitchSection ss in Sections) {
 
3583
                                foreach (SwitchLabel sl in ss.Labels) {
 
3584
                                        if (sl.IsDefault) {
 
3585
                                                ec.MarkLabel (lbl_default);
 
3586
                                                found_default = true;
 
3587
                                                if (null_section == null)
 
3588
                                                        ec.MarkLabel (null_target);
 
3589
                                        } else if (sl.Converted.IsNull) {
 
3590
                                                ec.MarkLabel (null_target);
 
3591
                                        }
 
3592
 
 
3593
                                        ec.MarkLabel (sl.GetILLabel (ec));
 
3594
                                }
 
3595
 
 
3596
                                ss.Block.Emit (ec);
 
3597
                        }
 
3598
                        
 
3599
                        if (!found_default) {
 
3600
                                ec.MarkLabel (lbl_default);
 
3601
                                if (null_section == null) {
 
3602
                                        ec.MarkLabel (null_target);
 
3603
                                }
 
3604
                        }
 
3605
                }
 
3606
 
 
3607
                SwitchLabel FindLabel (Constant value)
 
3608
                {
 
3609
                        SwitchLabel sl = null;
 
3610
 
 
3611
                        if (string_labels != null) {
 
3612
                                string s = value.GetValue () as string;
 
3613
                                if (s == null) {
 
3614
                                        if (null_section != null)
 
3615
                                                sl = null_section;
 
3616
                                        else if (default_section != null)
 
3617
                                                sl = default_section.Labels[0];
 
3618
                                } else {
 
3619
                                        string_labels.TryGetValue (s, out sl);
 
3620
                                }
 
3621
                        } else {
 
3622
                                if (value is NullLiteral) {
 
3623
                                        sl = null_section;
 
3624
                                } else {
 
3625
                                        labels.TryGetValue (value.GetValueAsLong (), out sl);
 
3626
                                }
 
3627
                        }
 
3628
 
 
3629
                        return sl;
 
3630
                }
 
3631
 
 
3632
                SwitchSection FindSection (SwitchLabel label)
 
3633
                {
 
3634
                        foreach (SwitchSection ss in Sections){
 
3635
                                foreach (SwitchLabel sl in ss.Labels){
 
3636
                                        if (label == sl)
 
3637
                                                return ss;
 
3638
                                }
 
3639
                        }
 
3640
 
 
3641
                        return null;
 
3642
                }
 
3643
 
 
3644
                public static void Reset ()
 
3645
                {
 
3646
                        unique_counter = 0;
 
3647
                }
 
3648
 
 
3649
                public override bool Resolve (BlockContext ec)
 
3650
                {
 
3651
                        Expr = Expr.Resolve (ec);
 
3652
                        if (Expr == null)
 
3653
                                return false;
 
3654
 
 
3655
                        new_expr = SwitchGoverningType (ec, Expr);
 
3656
 
 
3657
                        if (new_expr == null && Expr.Type.IsNullableType) {
 
3658
                                unwrap = Nullable.Unwrap.Create (Expr, false);
 
3659
                                if (unwrap == null)
 
3660
                                        return false;
 
3661
 
 
3662
                                new_expr = SwitchGoverningType (ec, unwrap);
 
3663
                        }
 
3664
 
 
3665
                        if (new_expr == null){
 
3666
                                ec.Report.Error (151, loc,
 
3667
                                        "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
 
3668
                                        TypeManager.CSharpName (Expr.Type));
 
3669
                                return false;
 
3670
                        }
 
3671
 
 
3672
                        // Validate switch.
 
3673
                        SwitchType = new_expr.Type;
 
3674
 
 
3675
                        if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
 
3676
                                ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
 
3677
                                return false;
 
3678
                        }
 
3679
 
 
3680
                        if (!CheckSwitch (ec))
 
3681
                                return false;
 
3682
 
 
3683
                        Switch old_switch = ec.Switch;
 
3684
                        ec.Switch = this;
 
3685
                        ec.Switch.SwitchType = SwitchType;
 
3686
 
 
3687
                        ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
 
3688
 
 
3689
                        var constant = new_expr as Constant;
 
3690
                        if (constant != null) {
 
3691
                                is_constant = true;
 
3692
                                SwitchLabel label = FindLabel (constant);
 
3693
                                if (label != null)
 
3694
                                        constant_section = FindSection (label);
 
3695
 
 
3696
                                if (constant_section == null)
 
3697
                                        constant_section = default_section;
 
3698
                        }
 
3699
 
 
3700
                        bool first = true;
 
3701
                        bool ok = true;
 
3702
                        foreach (SwitchSection ss in Sections){
 
3703
                                if (!first)
 
3704
                                        ec.CurrentBranching.CreateSibling (
 
3705
                                                null, FlowBranching.SiblingType.SwitchSection);
 
3706
                                else
 
3707
                                        first = false;
 
3708
 
 
3709
                                if (is_constant && (ss != constant_section)) {
 
3710
                                        // If we're a constant switch, we're only emitting
 
3711
                                        // one single section - mark all the others as
 
3712
                                        // unreachable.
 
3713
                                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
3714
                                        if (!ss.Block.ResolveUnreachable (ec, true)) {
 
3715
                                                ok = false;
 
3716
                                        }
 
3717
                                } else {
 
3718
                                        if (!ss.Block.Resolve (ec))
 
3719
                                                ok = false;
 
3720
                                }
 
3721
                        }
 
3722
 
 
3723
                        if (default_section == null)
 
3724
                                ec.CurrentBranching.CreateSibling (
 
3725
                                        null, FlowBranching.SiblingType.SwitchSection);
 
3726
 
 
3727
                        ec.EndFlowBranching ();
 
3728
                        ec.Switch = old_switch;
 
3729
 
 
3730
                        if (!ok)
 
3731
                                return false;
 
3732
 
 
3733
                        if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && !is_constant) {
 
3734
                                // TODO: Optimize single case, and single+default case
 
3735
                                ResolveStringSwitchMap (ec);
 
3736
                        }
 
3737
 
 
3738
                        return true;
 
3739
                }
 
3740
 
 
3741
                public SwitchLabel ResolveGotoCase (ResolveContext rc, Constant value)
 
3742
                {
 
3743
                        var sl = FindLabel (value);
 
3744
 
 
3745
                        if (sl == null) {
 
3746
                                FlowBranchingBlock.Error_UnknownLabel (loc, "case " + value.GetValueAsLiteral (), rc.Report);
 
3747
                        }
 
3748
 
 
3749
                        return sl;
 
3750
                }
 
3751
 
 
3752
                void ResolveStringSwitchMap (ResolveContext ec)
 
3753
                {
 
3754
                        FullNamedExpression string_dictionary_type;
 
3755
                        if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
 
3756
                                string_dictionary_type = new TypeExpression (
 
3757
                                        ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
 
3758
                                                new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
 
3759
                                        loc);
 
3760
                        } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
 
3761
                                string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
 
3762
                        } else {
 
3763
                                ec.Module.PredefinedTypes.Dictionary.Resolve ();
 
3764
                                return;
 
3765
                        }
 
3766
 
 
3767
                        var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
 
3768
                        Field field = new Field (ctype, string_dictionary_type,
 
3769
                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
 
3770
                                new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
 
3771
                        if (!field.Define ())
 
3772
                                return;
 
3773
                        ctype.AddField (field);
 
3774
 
 
3775
                        var init = new List<Expression> ();
 
3776
                        int counter = 0;
 
3777
                        labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
 
3778
                        string value = null;
 
3779
                        foreach (SwitchSection section in Sections) {
 
3780
                                bool contains_label = false;
 
3781
                                foreach (SwitchLabel sl in section.Labels) {
 
3782
                                        if (sl.IsDefault || sl.Converted.IsNull)
 
3783
                                                continue;
 
3784
 
 
3785
                                        if (!contains_label) {
 
3786
                                                labels.Add (counter, sl);
 
3787
                                                contains_label = true;
 
3788
                                        }
 
3789
 
 
3790
                                        value = (string) sl.Converted.GetValue ();
 
3791
                                        var init_args = new List<Expression> (2);
 
3792
                                        init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
 
3793
 
 
3794
                                        sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
 
3795
                                        init_args.Add (sl.Converted);
 
3796
 
 
3797
                                        init.Add (new CollectionElementInitializer (init_args, loc));
 
3798
                                }
 
3799
 
 
3800
                                //
 
3801
                                // Don't add empty sections
 
3802
                                //
 
3803
                                if (contains_label)
 
3804
                                        ++counter;
 
3805
                        }
 
3806
 
 
3807
                        Arguments args = new Arguments (1);
 
3808
                        args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
 
3809
                        Expression initializer = new NewInitialize (string_dictionary_type, args,
 
3810
                                new CollectionOrObjectInitializers (init, loc), loc);
 
3811
 
 
3812
                        switch_cache_field = new FieldExpr (field, loc);
 
3813
                        string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
 
3814
                }
 
3815
 
 
3816
                void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
 
3817
                {
 
3818
                        Label l_initialized = ec.DefineLabel ();
 
3819
 
 
3820
                        //
 
3821
                        // Skip initialization when value is null
 
3822
                        //
 
3823
                        value.EmitBranchable (ec, null_target, false);
 
3824
 
 
3825
                        //
 
3826
                        // Check if string dictionary is initialized and initialize
 
3827
                        //
 
3828
                        switch_cache_field.EmitBranchable (ec, l_initialized, true);
 
3829
                        string_dictionary.EmitStatement (ec);
 
3830
                        ec.MarkLabel (l_initialized);
 
3831
 
 
3832
                        LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
 
3833
 
 
3834
                        ResolveContext rc = new ResolveContext (ec.MemberContext);
 
3835
 
 
3836
                        if (switch_cache_field.Type.IsGeneric) {
 
3837
                                Arguments get_value_args = new Arguments (2);
 
3838
                                get_value_args.Add (new Argument (value));
 
3839
                                get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
 
3840
                                Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
 
3841
                                if (get_item == null)
 
3842
                                        return;
 
3843
 
 
3844
                                //
 
3845
                                // A value was not found, go to default case
 
3846
                                //
 
3847
                                get_item.EmitBranchable (ec, default_target, false);
 
3848
                        } else {
 
3849
                                Arguments get_value_args = new Arguments (1);
 
3850
                                get_value_args.Add (new Argument (value));
 
3851
 
 
3852
                                Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
 
3853
                                if (get_item == null)
 
3854
                                        return;
 
3855
 
 
3856
                                LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
 
3857
                                get_item_object.EmitAssign (ec, get_item, true, false);
 
3858
                                ec.Emit (OpCodes.Brfalse, default_target);
 
3859
 
 
3860
                                ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
 
3861
                                        new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
 
3862
 
 
3863
                                get_item_int.EmitStatement (ec);
 
3864
                                get_item_object.Release (ec);
 
3865
                        }
 
3866
 
 
3867
                        EmitTableSwitch (ec, string_switch_variable);
 
3868
                        string_switch_variable.Release (ec);
 
3869
                }
 
3870
                
 
3871
                protected override void DoEmit (EmitContext ec)
 
3872
                {
 
3873
                        //
 
3874
                        // Needed to emit anonymous storey initialization
 
3875
                        // Otherwise it does not contain any statements for now
 
3876
                        //
 
3877
                        block.Emit (ec);
 
3878
 
 
3879
                        default_target = ec.DefineLabel ();
 
3880
                        null_target = ec.DefineLabel ();
 
3881
 
 
3882
                        // Store variable for comparission purposes
 
3883
                        // TODO: Don't duplicate non-captured VariableReference
 
3884
                        LocalTemporary value;
 
3885
                        if (IsNullable) {
 
3886
                                value = new LocalTemporary (SwitchType);
 
3887
                                unwrap.EmitCheck (ec);
 
3888
                                ec.Emit (OpCodes.Brfalse, null_target);
 
3889
                                new_expr.Emit (ec);
 
3890
                                value.Store (ec);
 
3891
                        } else if (!is_constant) {
 
3892
                                value = new LocalTemporary (SwitchType);
 
3893
                                new_expr.Emit (ec);
 
3894
                                value.Store (ec);
 
3895
                        } else
 
3896
                                value = null;
 
3897
 
 
3898
                        //
 
3899
                        // Setup the codegen context
 
3900
                        //
 
3901
                        Label old_end = ec.LoopEnd;
 
3902
                        Switch old_switch = ec.Switch;
 
3903
                        
 
3904
                        ec.LoopEnd = ec.DefineLabel ();
 
3905
                        ec.Switch = this;
 
3906
 
 
3907
                        // Emit Code.
 
3908
                        if (is_constant) {
 
3909
                                if (constant_section != null)
 
3910
                                        constant_section.Block.Emit (ec);
 
3911
                        } else if (string_dictionary != null) {
 
3912
                                DoEmitStringSwitch (value, ec);
 
3913
                        } else {
 
3914
                                EmitTableSwitch (ec, value);
 
3915
                        }
 
3916
 
 
3917
                        if (value != null)
 
3918
                                value.Release (ec);
 
3919
 
 
3920
                        // Restore context state. 
 
3921
                        ec.MarkLabel (ec.LoopEnd);
 
3922
 
 
3923
                        //
 
3924
                        // Restore the previous context
 
3925
                        //
 
3926
                        ec.LoopEnd = old_end;
 
3927
                        ec.Switch = old_switch;
 
3928
                }
 
3929
 
 
3930
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
3931
                {
 
3932
                        Switch target = (Switch) t;
 
3933
 
 
3934
                        target.Expr = Expr.Clone (clonectx);
 
3935
                        target.Sections = new List<SwitchSection> ();
 
3936
                        foreach (SwitchSection ss in Sections){
 
3937
                                target.Sections.Add (ss.Clone (clonectx));
 
3938
                        }
 
3939
                }
 
3940
                
 
3941
                public override object Accept (StructuralVisitor visitor)
 
3942
                {
 
3943
                        return visitor.Visit (this);
 
3944
                }
 
3945
        }
 
3946
 
 
3947
        // A place where execution can restart in an iterator
 
3948
        public abstract class ResumableStatement : Statement
 
3949
        {
 
3950
                bool prepared;
 
3951
                protected Label resume_point;
 
3952
 
 
3953
                public Label PrepareForEmit (EmitContext ec)
 
3954
                {
 
3955
                        if (!prepared) {
 
3956
                                prepared = true;
 
3957
                                resume_point = ec.DefineLabel ();
 
3958
                        }
 
3959
                        return resume_point;
 
3960
                }
 
3961
 
 
3962
                public virtual Label PrepareForDispose (EmitContext ec, Label end)
 
3963
                {
 
3964
                        return end;
 
3965
                }
 
3966
                public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
 
3967
                {
 
3968
                }
 
3969
        }
 
3970
 
 
3971
        // Base class for statements that are implemented in terms of try...finally
 
3972
        public abstract class ExceptionStatement : ResumableStatement
 
3973
        {
 
3974
                bool code_follows;
 
3975
                Iterator iter;
 
3976
                List<ResumableStatement> resume_points;
 
3977
                int first_resume_pc;
 
3978
                protected Statement stmt;
 
3979
                Label dispose_try_block;
 
3980
                bool prepared_for_dispose, emitted_dispose;
 
3981
 
 
3982
                protected ExceptionStatement (Statement stmt, Location loc)
 
3983
                {
 
3984
                        this.stmt = stmt;
 
3985
                        this.loc = loc;
 
3986
                }
 
3987
 
 
3988
                #region Properties
 
3989
 
 
3990
                public Statement Statement {
 
3991
                        get {
 
3992
                                return stmt;
 
3993
                        }
 
3994
                }
 
3995
 
 
3996
                #endregion
 
3997
 
 
3998
                protected abstract void EmitPreTryBody (EmitContext ec);
 
3999
                protected abstract void EmitTryBody (EmitContext ec);
 
4000
                protected abstract void EmitFinallyBody (EmitContext ec);
 
4001
 
 
4002
                protected sealed override void DoEmit (EmitContext ec)
 
4003
                {
 
4004
                        EmitPreTryBody (ec);
 
4005
 
 
4006
                        if (resume_points != null) {
 
4007
                                ec.EmitInt ((int) Iterator.State.Running);
 
4008
                                ec.Emit (OpCodes.Stloc, iter.CurrentPC);
 
4009
                        }
 
4010
 
 
4011
                        ec.BeginExceptionBlock ();
 
4012
 
 
4013
                        if (resume_points != null) {
 
4014
                                ec.MarkLabel (resume_point);
 
4015
 
 
4016
                                // For normal control flow, we want to fall-through the Switch
 
4017
                                // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
 
4018
                                ec.Emit (OpCodes.Ldloc, iter.CurrentPC);
 
4019
                                ec.EmitInt (first_resume_pc);
 
4020
                                ec.Emit (OpCodes.Sub);
 
4021
 
 
4022
                                Label [] labels = new Label [resume_points.Count];
 
4023
                                for (int i = 0; i < resume_points.Count; ++i)
 
4024
                                        labels [i] = resume_points [i].PrepareForEmit (ec);
 
4025
                                ec.Emit (OpCodes.Switch, labels);
 
4026
                        }
 
4027
 
 
4028
                        EmitTryBody (ec);
 
4029
 
 
4030
                        ec.BeginFinallyBlock ();
 
4031
 
 
4032
                        Label start_finally = ec.DefineLabel ();
 
4033
                        if (resume_points != null) {
 
4034
                                ec.Emit (OpCodes.Ldloc, iter.SkipFinally);
 
4035
                                ec.Emit (OpCodes.Brfalse_S, start_finally);
 
4036
                                ec.Emit (OpCodes.Endfinally);
 
4037
                        }
 
4038
 
 
4039
                        ec.MarkLabel (start_finally);
 
4040
                        EmitFinallyBody (ec);
 
4041
 
 
4042
                        ec.EndExceptionBlock ();
 
4043
                }
 
4044
 
 
4045
                public void SomeCodeFollows ()
 
4046
                {
 
4047
                        code_follows = true;
 
4048
                }
 
4049
 
 
4050
                public override bool Resolve (BlockContext ec)
 
4051
                {
 
4052
                        // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
 
4053
                        // So, ensure there's some IL code after this statement.
 
4054
                        if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
 
4055
                                ec.NeedReturnLabel ();
 
4056
 
 
4057
                        iter = ec.CurrentIterator;
 
4058
                        return true;
 
4059
                }
 
4060
 
 
4061
                public void AddResumePoint (ResumableStatement stmt, int pc)
 
4062
                {
 
4063
                        if (resume_points == null) {
 
4064
                                resume_points = new List<ResumableStatement> ();
 
4065
                                first_resume_pc = pc;
 
4066
                        }
 
4067
 
 
4068
                        if (pc != first_resume_pc + resume_points.Count)
 
4069
                                throw new InternalErrorException ("missed an intervening AddResumePoint?");
 
4070
 
 
4071
                        resume_points.Add (stmt);
 
4072
                }
 
4073
 
 
4074
                public override Label PrepareForDispose (EmitContext ec, Label end)
 
4075
                {
 
4076
                        if (!prepared_for_dispose) {
 
4077
                                prepared_for_dispose = true;
 
4078
                                dispose_try_block = ec.DefineLabel ();
 
4079
                        }
 
4080
                        return dispose_try_block;
 
4081
                }
 
4082
 
 
4083
                public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
 
4084
                {
 
4085
                        if (emitted_dispose)
 
4086
                                return;
 
4087
 
 
4088
                        emitted_dispose = true;
 
4089
 
 
4090
                        Label end_of_try = ec.DefineLabel ();
 
4091
 
 
4092
                        // Ensure that the only way we can get into this code is through a dispatcher
 
4093
                        if (have_dispatcher)
 
4094
                                ec.Emit (OpCodes.Br, end);
 
4095
 
 
4096
                        ec.BeginExceptionBlock ();
 
4097
 
 
4098
                        ec.MarkLabel (dispose_try_block);
 
4099
 
 
4100
                        Label [] labels = null;
 
4101
                        for (int i = 0; i < resume_points.Count; ++i) {
 
4102
                                ResumableStatement s = (ResumableStatement) resume_points [i];
 
4103
                                Label ret = s.PrepareForDispose (ec, end_of_try);
 
4104
                                if (ret.Equals (end_of_try) && labels == null)
 
4105
                                        continue;
 
4106
                                if (labels == null) {
 
4107
                                        labels = new Label [resume_points.Count];
 
4108
                                        for (int j = 0; j < i; ++j)
 
4109
                                                labels [j] = end_of_try;
 
4110
                                }
 
4111
                                labels [i] = ret;
 
4112
                        }
 
4113
 
 
4114
                        if (labels != null) {
 
4115
                                int j;
 
4116
                                for (j = 1; j < labels.Length; ++j)
 
4117
                                        if (!labels [0].Equals (labels [j]))
 
4118
                                                break;
 
4119
                                bool emit_dispatcher = j < labels.Length;
 
4120
 
 
4121
                                if (emit_dispatcher) {
 
4122
                                        //SymbolWriter.StartIteratorDispatcher (ec.ig);
 
4123
                                        ec.Emit (OpCodes.Ldloc, iterator.CurrentPC);
 
4124
                                        ec.EmitInt (first_resume_pc);
 
4125
                                        ec.Emit (OpCodes.Sub);
 
4126
                                        ec.Emit (OpCodes.Switch, labels);
 
4127
                                        //SymbolWriter.EndIteratorDispatcher (ec.ig);
 
4128
                                }
 
4129
 
 
4130
                                foreach (ResumableStatement s in resume_points)
 
4131
                                        s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
 
4132
                        }
 
4133
 
 
4134
                        ec.MarkLabel (end_of_try);
 
4135
 
 
4136
                        ec.BeginFinallyBlock ();
 
4137
 
 
4138
                        EmitFinallyBody (ec);
 
4139
 
 
4140
                        ec.EndExceptionBlock ();
 
4141
                }
 
4142
        }
 
4143
 
 
4144
        public class Lock : ExceptionStatement {
 
4145
                Expression expr;
 
4146
                TemporaryVariableReference expr_copy;
 
4147
                TemporaryVariableReference lock_taken;
 
4148
                        
 
4149
                public Lock (Expression expr, Statement stmt, Location loc)
 
4150
                        : base (stmt, loc)
 
4151
                {
 
4152
                        this.expr = expr;
 
4153
                }
 
4154
                
 
4155
                public Expression Expr {
 
4156
                        get { return this.expr; }
 
4157
                }
 
4158
                
 
4159
                public override bool Resolve (BlockContext ec)
 
4160
                {
 
4161
                        expr = expr.Resolve (ec);
 
4162
                        if (expr == null)
 
4163
                                return false;
 
4164
 
 
4165
                        if (!TypeSpec.IsReferenceType (expr.Type)) {
 
4166
                                ec.Report.Error (185, loc,
 
4167
                                        "`{0}' is not a reference type as required by the lock statement",
 
4168
                                        expr.Type.GetSignatureForError ());
 
4169
                        }
 
4170
 
 
4171
                        if (expr.Type.IsGenericParameter) {
 
4172
                                expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
 
4173
                        }
 
4174
 
 
4175
                        VariableReference lv = expr as VariableReference;
 
4176
                        bool locked;
 
4177
                        if (lv != null) {
 
4178
                                locked = lv.IsLockedByStatement;
 
4179
                                lv.IsLockedByStatement = true;
 
4180
                        } else {
 
4181
                                lv = null;
 
4182
                                locked = false;
 
4183
                        }
 
4184
 
 
4185
                        ec.StartFlowBranching (this);
 
4186
                        Statement.Resolve (ec);
 
4187
                        ec.EndFlowBranching ();
 
4188
 
 
4189
                        if (lv != null) {
 
4190
                                lv.IsLockedByStatement = locked;
 
4191
                        }
 
4192
 
 
4193
                        base.Resolve (ec);
 
4194
 
 
4195
                        //
 
4196
                        // Have to keep original lock value around to unlock same location
 
4197
                        // in the case the original has changed or is null
 
4198
                        //
 
4199
                        expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock.Parent, loc);
 
4200
                        expr_copy.Resolve (ec);
 
4201
 
 
4202
                        //
 
4203
                        // Ensure Monitor methods are available
 
4204
                        //
 
4205
                        if (ResolvePredefinedMethods (ec) > 1) {
 
4206
                                lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock.Parent, loc);
 
4207
                                lock_taken.Resolve (ec);
 
4208
                        }
 
4209
 
 
4210
                        return true;
 
4211
                }
 
4212
                
 
4213
                protected override void EmitPreTryBody (EmitContext ec)
 
4214
                {
 
4215
                        expr_copy.EmitAssign (ec, expr);
 
4216
 
 
4217
                        if (lock_taken != null) {
 
4218
                                //
 
4219
                                // Initialize ref variable
 
4220
                                //
 
4221
                                lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
 
4222
                        } else {
 
4223
                                //
 
4224
                                // Monitor.Enter (expr_copy)
 
4225
                                //
 
4226
                                expr_copy.Emit (ec);
 
4227
                                ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
 
4228
                        }
 
4229
                }
 
4230
 
 
4231
                protected override void EmitTryBody (EmitContext ec)
 
4232
                {
 
4233
                        //
 
4234
                        // Monitor.Enter (expr_copy, ref lock_taken)
 
4235
                        //
 
4236
                        if (lock_taken != null) {
 
4237
                                expr_copy.Emit (ec);
 
4238
                                lock_taken.LocalInfo.CreateBuilder (ec);
 
4239
                                lock_taken.AddressOf (ec, AddressOp.Load);
 
4240
                                ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
 
4241
                        }
 
4242
 
 
4243
                        Statement.Emit (ec);
 
4244
                }
 
4245
 
 
4246
                protected override void EmitFinallyBody (EmitContext ec)
 
4247
                {
 
4248
                        //
 
4249
                        // if (lock_taken) Monitor.Exit (expr_copy)
 
4250
                        //
 
4251
                        Label skip = ec.DefineLabel ();
 
4252
 
 
4253
                        if (lock_taken != null) {
 
4254
                                lock_taken.Emit (ec);
 
4255
                                ec.Emit (OpCodes.Brfalse_S, skip);
 
4256
                        }
 
4257
 
 
4258
                        expr_copy.Emit (ec);
 
4259
                        var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
 
4260
                        if (m != null)
 
4261
                                ec.Emit (OpCodes.Call, m);
 
4262
 
 
4263
                        ec.MarkLabel (skip);
 
4264
                }
 
4265
 
 
4266
                int ResolvePredefinedMethods (ResolveContext rc)
 
4267
                {
 
4268
                        // Try 4.0 Monitor.Enter (object, ref bool) overload first
 
4269
                        var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
 
4270
                        if (m != null)
 
4271
                                return 4;
 
4272
 
 
4273
                        m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
 
4274
                        if (m != null)
 
4275
                                return 1;
 
4276
 
 
4277
                        rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
 
4278
                        return 0;
 
4279
                }
 
4280
 
 
4281
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4282
                {
 
4283
                        Lock target = (Lock) t;
 
4284
 
 
4285
                        target.expr = expr.Clone (clonectx);
 
4286
                        target.stmt = Statement.Clone (clonectx);
 
4287
                }
 
4288
                
 
4289
                public override object Accept (StructuralVisitor visitor)
 
4290
                {
 
4291
                        return visitor.Visit (this);
 
4292
                }
 
4293
 
 
4294
        }
 
4295
 
 
4296
        public class Unchecked : Statement {
 
4297
                public Block Block;
 
4298
                
 
4299
                public Unchecked (Block b, Location loc)
 
4300
                {
 
4301
                        Block = b;
 
4302
                        b.Unchecked = true;
 
4303
                        this.loc = loc;
 
4304
                }
 
4305
 
 
4306
                public override bool Resolve (BlockContext ec)
 
4307
                {
 
4308
                        using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
 
4309
                                return Block.Resolve (ec);
 
4310
                }
 
4311
                
 
4312
                protected override void DoEmit (EmitContext ec)
 
4313
                {
 
4314
                        using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
 
4315
                                Block.Emit (ec);
 
4316
                }
 
4317
 
 
4318
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4319
                {
 
4320
                        Unchecked target = (Unchecked) t;
 
4321
 
 
4322
                        target.Block = clonectx.LookupBlock (Block);
 
4323
                }
 
4324
                
 
4325
                public override object Accept (StructuralVisitor visitor)
 
4326
                {
 
4327
                        return visitor.Visit (this);
 
4328
                }
 
4329
        }
 
4330
 
 
4331
        public class Checked : Statement {
 
4332
                public Block Block;
 
4333
                
 
4334
                public Checked (Block b, Location loc)
 
4335
                {
 
4336
                        Block = b;
 
4337
                        b.Unchecked = false;
 
4338
                        this.loc = loc;
 
4339
                }
 
4340
 
 
4341
                public override bool Resolve (BlockContext ec)
 
4342
                {
 
4343
                        using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
 
4344
                                return Block.Resolve (ec);
 
4345
                }
 
4346
 
 
4347
                protected override void DoEmit (EmitContext ec)
 
4348
                {
 
4349
                        using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
 
4350
                                Block.Emit (ec);
 
4351
                }
 
4352
 
 
4353
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4354
                {
 
4355
                        Checked target = (Checked) t;
 
4356
 
 
4357
                        target.Block = clonectx.LookupBlock (Block);
 
4358
                }
 
4359
                
 
4360
                public override object Accept (StructuralVisitor visitor)
 
4361
                {
 
4362
                        return visitor.Visit (this);
 
4363
                }
 
4364
        }
 
4365
 
 
4366
        public class Unsafe : Statement {
 
4367
                public Block Block;
 
4368
 
 
4369
                public Unsafe (Block b, Location loc)
 
4370
                {
 
4371
                        Block = b;
 
4372
                        Block.Unsafe = true;
 
4373
                        this.loc = loc;
 
4374
                }
 
4375
 
 
4376
                public override bool Resolve (BlockContext ec)
 
4377
                {
 
4378
                        if (ec.CurrentIterator != null)
 
4379
                                ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
 
4380
 
 
4381
                        using (ec.Set (ResolveContext.Options.UnsafeScope))
 
4382
                                return Block.Resolve (ec);
 
4383
                }
 
4384
                
 
4385
                protected override void DoEmit (EmitContext ec)
 
4386
                {
 
4387
                        Block.Emit (ec);
 
4388
                }
 
4389
 
 
4390
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4391
                {
 
4392
                        Unsafe target = (Unsafe) t;
 
4393
 
 
4394
                        target.Block = clonectx.LookupBlock (Block);
 
4395
                }
 
4396
                
 
4397
                public override object Accept (StructuralVisitor visitor)
 
4398
                {
 
4399
                        return visitor.Visit (this);
 
4400
                }
 
4401
        }
 
4402
 
 
4403
        // 
 
4404
        // Fixed statement
 
4405
        //
 
4406
        public class Fixed : Statement
 
4407
        {
 
4408
                abstract class Emitter : ShimExpression
 
4409
                {
 
4410
                        protected LocalVariable vi;
 
4411
 
 
4412
                        protected Emitter (Expression expr, LocalVariable li)
 
4413
                                : base (expr)
 
4414
                        {
 
4415
                                vi = li;
 
4416
                        }
 
4417
 
 
4418
                        public abstract void EmitExit (EmitContext ec);
 
4419
                }
 
4420
 
 
4421
                class ExpressionEmitter : Emitter {
 
4422
                        public ExpressionEmitter (Expression converted, LocalVariable li) :
 
4423
                                base (converted, li)
 
4424
                        {
 
4425
                        }
 
4426
 
 
4427
                        protected override Expression DoResolve (ResolveContext rc)
 
4428
                        {
 
4429
                                throw new NotImplementedException ();
 
4430
                        }
 
4431
 
 
4432
                        public override void Emit (EmitContext ec) {
 
4433
                                //
 
4434
                                // Store pointer in pinned location
 
4435
                                //
 
4436
                                expr.Emit (ec);
 
4437
                                vi.EmitAssign (ec);
 
4438
                        }
 
4439
 
 
4440
                        public override void EmitExit (EmitContext ec)
 
4441
                        {
 
4442
                                ec.Emit (OpCodes.Ldc_I4_0);
 
4443
                                ec.Emit (OpCodes.Conv_U);
 
4444
                                vi.EmitAssign (ec);
 
4445
                        }
 
4446
                }
 
4447
 
 
4448
                class StringEmitter : Emitter
 
4449
                {
 
4450
                        LocalVariable pinned_string;
 
4451
 
 
4452
                        public StringEmitter (Expression expr, LocalVariable li, Location loc)
 
4453
                                : base (expr, li)
 
4454
                        {
 
4455
                        }
 
4456
 
 
4457
                        protected override Expression DoResolve (ResolveContext rc)
 
4458
                        {
 
4459
                                pinned_string = new LocalVariable (vi.Block, "$pinned",
 
4460
                                        LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
 
4461
                                        vi.Location);
 
4462
                                pinned_string.Type = rc.BuiltinTypes.String;
 
4463
 
 
4464
                                eclass = ExprClass.Variable;
 
4465
                                type = rc.BuiltinTypes.Int;
 
4466
                                return this;
 
4467
                        }
 
4468
 
 
4469
                        public override void Emit (EmitContext ec)
 
4470
                        {
 
4471
                                pinned_string.CreateBuilder (ec);
 
4472
 
 
4473
                                expr.Emit (ec);
 
4474
                                pinned_string.EmitAssign (ec);
 
4475
 
 
4476
                                // TODO: Should use Binary::Add
 
4477
                                pinned_string.Emit (ec);
 
4478
                                ec.Emit (OpCodes.Conv_I);
 
4479
 
 
4480
                                var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
 
4481
                                if (m == null)
 
4482
                                        return;
 
4483
 
 
4484
                                PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
 
4485
                                //pe.InstanceExpression = pinned_string;
 
4486
                                pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
 
4487
 
 
4488
                                ec.Emit (OpCodes.Add);
 
4489
                                vi.EmitAssign (ec);
 
4490
                        }
 
4491
 
 
4492
                        public override void EmitExit (EmitContext ec)
 
4493
                        {
 
4494
                                ec.Emit (OpCodes.Ldnull);
 
4495
                                pinned_string.EmitAssign (ec);
 
4496
                        }
 
4497
                }
 
4498
 
 
4499
 
 
4500
                public class VariableDeclaration : BlockVariableDeclaration
 
4501
                {
 
4502
                        public VariableDeclaration (FullNamedExpression type, LocalVariable li)
 
4503
                                : base (type, li)
 
4504
                        {
 
4505
                        }
 
4506
 
 
4507
                        protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
 
4508
                        {
 
4509
                                if (!Variable.Type.IsPointer && li == Variable) {
 
4510
                                        bc.Report.Error (209, TypeExpression.Location,
 
4511
                                                "The type of locals declared in a fixed statement must be a pointer type");
 
4512
                                        return null;
 
4513
                                }
 
4514
 
 
4515
                                //
 
4516
                                // The rules for the possible declarators are pretty wise,
 
4517
                                // but the production on the grammar is more concise.
 
4518
                                //
 
4519
                                // So we have to enforce these rules here.
 
4520
                                //
 
4521
                                // We do not resolve before doing the case 1 test,
 
4522
                                // because the grammar is explicit in that the token &
 
4523
                                // is present, so we need to test for this particular case.
 
4524
                                //
 
4525
 
 
4526
                                if (initializer is Cast) {
 
4527
                                        bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
 
4528
                                        return null;
 
4529
                                }
 
4530
 
 
4531
                                initializer = initializer.Resolve (bc);
 
4532
 
 
4533
                                if (initializer == null)
 
4534
                                        return null;
 
4535
 
 
4536
                                //
 
4537
                                // Case 1: Array
 
4538
                                //
 
4539
                                if (initializer.Type.IsArray) {
 
4540
                                        TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
 
4541
 
 
4542
                                        //
 
4543
                                        // Provided that array_type is unmanaged,
 
4544
                                        //
 
4545
                                        if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
 
4546
                                                return null;
 
4547
 
 
4548
                                        //
 
4549
                                        // and T* is implicitly convertible to the
 
4550
                                        // pointer type given in the fixed statement.
 
4551
                                        //
 
4552
                                        ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
 
4553
 
 
4554
                                        Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
 
4555
                                        if (converted == null)
 
4556
                                                return null;
 
4557
 
 
4558
                                        //
 
4559
                                        // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
 
4560
                                        //
 
4561
                                        converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
 
4562
                                                new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
 
4563
                                                new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc), loc), loc)),
 
4564
                                                        new NullLiteral (loc),
 
4565
                                                        converted, loc);
 
4566
 
 
4567
                                        converted = converted.Resolve (bc);
 
4568
 
 
4569
                                        return new ExpressionEmitter (converted, li);
 
4570
                                }
 
4571
 
 
4572
                                //
 
4573
                                // Case 2: string
 
4574
                                //
 
4575
                                if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
 
4576
                                        return new StringEmitter (initializer, li, loc).Resolve (bc);
 
4577
                                }
 
4578
 
 
4579
                                // Case 3: fixed buffer
 
4580
                                if (initializer is FixedBufferPtr) {
 
4581
                                        return new ExpressionEmitter (initializer, li);
 
4582
                                }
 
4583
 
 
4584
                                //
 
4585
                                // Case 4: & object.
 
4586
                                //
 
4587
                                bool already_fixed = true;
 
4588
                                Unary u = initializer as Unary;
 
4589
                                if (u != null && u.Oper == Unary.Operator.AddressOf) {
 
4590
                                        IVariableReference vr = u.Expr as IVariableReference;
 
4591
                                        if (vr == null || !vr.IsFixed) {
 
4592
                                                already_fixed = false;
 
4593
                                        }
 
4594
                                }
 
4595
 
 
4596
                                if (already_fixed) {
 
4597
                                        bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
 
4598
                                }
 
4599
 
 
4600
                                initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
 
4601
                                return new ExpressionEmitter (initializer, li);
 
4602
                        }
 
4603
                }
 
4604
 
 
4605
 
 
4606
                VariableDeclaration decl;
 
4607
                Statement statement;
 
4608
                bool has_ret;
 
4609
 
 
4610
                public Fixed (VariableDeclaration decl, Statement stmt, Location l)
 
4611
                {
 
4612
                        this.decl = decl;
 
4613
                        statement = stmt;
 
4614
                        loc = l;
 
4615
                }
 
4616
 
 
4617
                #region Properties
 
4618
 
 
4619
                public Statement Statement {
 
4620
                        get {
 
4621
                                return statement;
 
4622
                        }
 
4623
                }
 
4624
 
 
4625
                public BlockVariableDeclaration Variables {
 
4626
                        get {
 
4627
                                return decl;
 
4628
                        }
 
4629
                }
 
4630
 
 
4631
                #endregion
 
4632
 
 
4633
                public override bool Resolve (BlockContext ec)
 
4634
                {
 
4635
                        using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
 
4636
                                if (!decl.Resolve (ec))
 
4637
                                        return false;
 
4638
                        }
 
4639
 
 
4640
                        ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
 
4641
                        bool ok = statement.Resolve (ec);
 
4642
                        bool flow_unreachable = ec.EndFlowBranching ();
 
4643
                        has_ret = flow_unreachable;
 
4644
 
 
4645
                        return ok;
 
4646
                }
 
4647
                
 
4648
                protected override void DoEmit (EmitContext ec)
 
4649
                {
 
4650
                        decl.Variable.CreateBuilder (ec);
 
4651
                        decl.Initializer.Emit (ec);
 
4652
                        if (decl.Declarators != null) {
 
4653
                                foreach (var d in decl.Declarators) {
 
4654
                                        d.Variable.CreateBuilder (ec);
 
4655
                                        d.Initializer.Emit (ec);
 
4656
                                }
 
4657
                        }
 
4658
 
 
4659
                        statement.Emit (ec);
 
4660
 
 
4661
                        if (has_ret)
 
4662
                                return;
 
4663
 
 
4664
                        //
 
4665
                        // Clear the pinned variable
 
4666
                        //
 
4667
                        ((Emitter) decl.Initializer).EmitExit (ec);
 
4668
                        if (decl.Declarators != null) {
 
4669
                                foreach (var d in decl.Declarators) {
 
4670
                                        ((Emitter)d.Initializer).EmitExit (ec);
 
4671
                                }
 
4672
                        }
 
4673
                }
 
4674
 
 
4675
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4676
                {
 
4677
                        Fixed target = (Fixed) t;
 
4678
 
 
4679
                        target.decl = (VariableDeclaration) decl.Clone (clonectx);
 
4680
                        target.statement = statement.Clone (clonectx);
 
4681
                }
 
4682
                
 
4683
                public override object Accept (StructuralVisitor visitor)
 
4684
                {
 
4685
                        return visitor.Visit (this);
 
4686
                }
 
4687
        }
 
4688
 
 
4689
        public class Catch : Statement
 
4690
        {
 
4691
                Block block;
 
4692
                LocalVariable li;
 
4693
                FullNamedExpression type_expr;
 
4694
                CompilerAssign assign;
 
4695
                TypeSpec type;
 
4696
 
 
4697
                public Catch (Block block, Location loc)
 
4698
                {
 
4699
                        this.block = block;
 
4700
                        this.loc = loc;
 
4701
                }
 
4702
 
 
4703
                #region Properties
 
4704
 
 
4705
                public Block Block {
 
4706
                        get {
 
4707
                                return block;
 
4708
                        }
 
4709
                }
 
4710
 
 
4711
                public TypeSpec CatchType {
 
4712
                        get {
 
4713
                                return type;
 
4714
                        }
 
4715
                }
 
4716
 
 
4717
                public bool IsGeneral {
 
4718
                        get {
 
4719
                                return type_expr == null;
 
4720
                        }
 
4721
                }
 
4722
 
 
4723
                public FullNamedExpression TypeExpression {
 
4724
                        get {
 
4725
                                return type_expr;
 
4726
                        }
 
4727
                        set {
 
4728
                                type_expr = value;
 
4729
                        }
 
4730
                }
 
4731
 
 
4732
                public LocalVariable Variable {
 
4733
                        get {
 
4734
                                return li;
 
4735
                        }
 
4736
                        set {
 
4737
                                li = value;
 
4738
                        }
 
4739
                }
 
4740
 
 
4741
                #endregion
 
4742
 
 
4743
                protected override void DoEmit (EmitContext ec)
 
4744
                {
 
4745
                        if (IsGeneral)
 
4746
                                ec.BeginCatchBlock (ec.BuiltinTypes.Object);
 
4747
                        else
 
4748
                                ec.BeginCatchBlock (CatchType);
 
4749
 
 
4750
                        if (li != null) {
 
4751
                                li.CreateBuilder (ec);
 
4752
 
 
4753
                                //
 
4754
                                // Special case hoisted catch variable, we have to use a temporary variable
 
4755
                                // to pass via anonymous storey initialization with the value still on top
 
4756
                                // of the stack
 
4757
                                //
 
4758
                                if (li.HoistedVariant != null) {
 
4759
                                        LocalTemporary lt = new LocalTemporary (li.Type);
 
4760
                                        SymbolWriter.OpenCompilerGeneratedBlock (ec);
 
4761
                                        lt.Store (ec);
 
4762
                                        SymbolWriter.CloseCompilerGeneratedBlock (ec);
 
4763
 
 
4764
                                        // switch to assigning from the temporary variable and not from top of the stack
 
4765
                                        assign.UpdateSource (lt);
 
4766
                                }
 
4767
                        } else {
 
4768
                                SymbolWriter.OpenCompilerGeneratedBlock (ec);
 
4769
                                ec.Emit (OpCodes.Pop);
 
4770
                                SymbolWriter.CloseCompilerGeneratedBlock (ec);
 
4771
                        }
 
4772
 
 
4773
                        Block.Emit (ec);
 
4774
                }
 
4775
 
 
4776
                public override bool Resolve (BlockContext ec)
 
4777
                {
 
4778
                        using (ec.With (ResolveContext.Options.CatchScope, true)) {
 
4779
                                if (type_expr != null) {
 
4780
                                        type = type_expr.ResolveAsType (ec);
 
4781
                                        if (type == null)
 
4782
                                                return false;
 
4783
 
 
4784
                                        if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
 
4785
                                                ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
 
4786
                                        } else if (li != null) {
 
4787
                                                li.Type = type;
 
4788
                                                li.PrepareForFlowAnalysis (ec);
 
4789
 
 
4790
                                                // source variable is at the top of the stack
 
4791
                                                Expression source = new EmptyExpression (li.Type);
 
4792
                                                if (li.Type.IsGenericParameter)
 
4793
                                                        source = new UnboxCast (source, li.Type);
 
4794
 
 
4795
                                                assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc);
 
4796
                                                Block.AddScopeStatement (new StatementExpression (assign));
 
4797
                                        }
 
4798
                                }
 
4799
 
 
4800
                                return Block.Resolve (ec);
 
4801
                        }
 
4802
                }
 
4803
 
 
4804
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4805
                {
 
4806
                        Catch target = (Catch) t;
 
4807
 
 
4808
                        if (type_expr != null)
 
4809
                                target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
 
4810
 
 
4811
                        target.block = clonectx.LookupBlock (block);
 
4812
                }
 
4813
        }
 
4814
 
 
4815
        public class TryFinally : ExceptionStatement {
 
4816
                Block fini;
 
4817
                
 
4818
                public Statement Stmt {
 
4819
                        get { return this.stmt; }
 
4820
                }
 
4821
 
 
4822
                public Block Fini {
 
4823
                        get { return this.fini; }
 
4824
                }
 
4825
 
 
4826
                public TryFinally (Statement stmt, Block fini, Location loc)
 
4827
                         : base (stmt, loc)
 
4828
                {
 
4829
                        this.fini = fini;
 
4830
                }
 
4831
 
 
4832
                public override bool Resolve (BlockContext ec)
 
4833
                {
 
4834
                        bool ok = true;
 
4835
 
 
4836
                        ec.StartFlowBranching (this);
 
4837
 
 
4838
                        if (!stmt.Resolve (ec))
 
4839
                                ok = false;
 
4840
 
 
4841
                        if (ok)
 
4842
                                ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
 
4843
                        using (ec.With (ResolveContext.Options.FinallyScope, true)) {
 
4844
                                if (!fini.Resolve (ec))
 
4845
                                        ok = false;
 
4846
                        }
 
4847
 
 
4848
                        ec.EndFlowBranching ();
 
4849
 
 
4850
                        ok &= base.Resolve (ec);
 
4851
 
 
4852
                        return ok;
 
4853
                }
 
4854
 
 
4855
                protected override void EmitPreTryBody (EmitContext ec)
 
4856
                {
 
4857
                }
 
4858
 
 
4859
                protected override void EmitTryBody (EmitContext ec)
 
4860
                {
 
4861
                        stmt.Emit (ec);
 
4862
                }
 
4863
 
 
4864
                protected override void EmitFinallyBody (EmitContext ec)
 
4865
                {
 
4866
                        fini.Emit (ec);
 
4867
                }
 
4868
 
 
4869
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4870
                {
 
4871
                        TryFinally target = (TryFinally) t;
 
4872
 
 
4873
                        target.stmt = (Statement) stmt.Clone (clonectx);
 
4874
                        if (fini != null)
 
4875
                                target.fini = clonectx.LookupBlock (fini);
 
4876
                }
 
4877
                
 
4878
                public override object Accept (StructuralVisitor visitor)
 
4879
                {
 
4880
                        return visitor.Visit (this);
 
4881
                }
 
4882
        }
 
4883
 
 
4884
        public class TryCatch : Statement {
 
4885
                public Block Block;
 
4886
                public List<Catch> Specific;
 
4887
                public Catch General;
 
4888
                bool inside_try_finally, code_follows;
 
4889
 
 
4890
                public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
 
4891
                {
 
4892
                        this.Block = block;
 
4893
                        this.Specific = catch_clauses;
 
4894
                        this.inside_try_finally = inside_try_finally;
 
4895
 
 
4896
                        Catch c = catch_clauses [0];
 
4897
                        if (c.IsGeneral) {
 
4898
                                this.General = c;                       
 
4899
                                catch_clauses.RemoveAt (0);
 
4900
                        }
 
4901
 
 
4902
                        loc = l;
 
4903
                }
 
4904
 
 
4905
                public override bool Resolve (BlockContext ec)
 
4906
                {
 
4907
                        bool ok = true;
 
4908
 
 
4909
                        ec.StartFlowBranching (this);
 
4910
 
 
4911
                        if (!Block.Resolve (ec))
 
4912
                                ok = false;
 
4913
 
 
4914
                        TypeSpec[] prev_catches = new TypeSpec [Specific.Count];
 
4915
                        int last_index = 0;
 
4916
                        foreach (Catch c in Specific){
 
4917
                                ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
 
4918
 
 
4919
                                if (!c.Resolve (ec)) {
 
4920
                                        ok = false;
 
4921
                                        continue;
 
4922
                                }
 
4923
 
 
4924
                                TypeSpec resolved_type = c.CatchType;
 
4925
                                for (int ii = 0; ii < last_index; ++ii) {
 
4926
                                        if (resolved_type == prev_catches[ii] || TypeSpec.IsBaseClass (resolved_type, prev_catches[ii], true)) {
 
4927
                                                ec.Report.Error (160, c.loc,
 
4928
                                                        "A previous catch clause already catches all exceptions of this or a super type `{0}'",
 
4929
                                                        TypeManager.CSharpName (prev_catches [ii]));
 
4930
                                                ok = false;
 
4931
                                        }
 
4932
                                }
 
4933
 
 
4934
                                prev_catches [last_index++] = resolved_type;
 
4935
                        }
 
4936
 
 
4937
                        if (General != null) {
 
4938
                                foreach (Catch c in Specific) {
 
4939
                                        if (c.CatchType.BuiltinType != BuiltinTypeSpec.Type.Exception)
 
4940
                                                continue;
 
4941
 
 
4942
                                        if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
 
4943
                                                continue;
 
4944
 
 
4945
                                        if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
 
4946
                                                continue;
 
4947
 
 
4948
                                        ec.Report.Warning (1058, 1, c.loc,
 
4949
                                                "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
 
4950
                                }
 
4951
 
 
4952
                                ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
 
4953
 
 
4954
                                if (!General.Resolve (ec))
 
4955
                                        ok = false;
 
4956
                        }
 
4957
 
 
4958
                        ec.EndFlowBranching ();
 
4959
 
 
4960
                        // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
 
4961
                        // So, ensure there's some IL code after this statement
 
4962
                        if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
 
4963
                                ec.NeedReturnLabel ();
 
4964
 
 
4965
                        return ok;
 
4966
                }
 
4967
 
 
4968
                public void SomeCodeFollows ()
 
4969
                {
 
4970
                        code_follows = true;
 
4971
                }
 
4972
                
 
4973
                protected override void DoEmit (EmitContext ec)
 
4974
                {
 
4975
                        if (!inside_try_finally)
 
4976
                                ec.BeginExceptionBlock ();
 
4977
 
 
4978
                        Block.Emit (ec);
 
4979
 
 
4980
                        foreach (Catch c in Specific)
 
4981
                                c.Emit (ec);
 
4982
 
 
4983
                        if (General != null)
 
4984
                                General.Emit (ec);
 
4985
 
 
4986
                        if (!inside_try_finally)
 
4987
                                ec.EndExceptionBlock ();
 
4988
                }
 
4989
 
 
4990
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
4991
                {
 
4992
                        TryCatch target = (TryCatch) t;
 
4993
 
 
4994
                        target.Block = clonectx.LookupBlock (Block);
 
4995
                        if (General != null)
 
4996
                                target.General = (Catch) General.Clone (clonectx);
 
4997
                        if (Specific != null){
 
4998
                                target.Specific = new List<Catch> ();
 
4999
                                foreach (Catch c in Specific)
 
5000
                                        target.Specific.Add ((Catch) c.Clone (clonectx));
 
5001
                        }
 
5002
                }
 
5003
                public override object Accept (StructuralVisitor visitor)
 
5004
                {
 
5005
                        return visitor.Visit (this);
 
5006
                }
 
5007
        }
 
5008
 
 
5009
        public class Using : ExceptionStatement
 
5010
        {
 
5011
                public class VariableDeclaration : BlockVariableDeclaration
 
5012
                {
 
5013
                        Statement dispose_call;
 
5014
 
 
5015
                        public VariableDeclaration (FullNamedExpression type, LocalVariable li)
 
5016
                                : base (type, li)
 
5017
                        {
 
5018
                        }
 
5019
 
 
5020
                        public VariableDeclaration (LocalVariable li, Location loc)
 
5021
                                : base (li)
 
5022
                        {
 
5023
                                this.loc = loc;
 
5024
                        }
 
5025
 
 
5026
                        public VariableDeclaration (Expression expr)
 
5027
                                : base (null)
 
5028
                        {
 
5029
                                loc = expr.Location;
 
5030
                                Initializer = expr;
 
5031
                        }
 
5032
 
 
5033
                        #region Properties
 
5034
 
 
5035
                        public bool IsNested { get; private set; }
 
5036
 
 
5037
                        #endregion
 
5038
 
 
5039
                        public void EmitDispose (EmitContext ec)
 
5040
                        {
 
5041
                                dispose_call.Emit (ec);
 
5042
                        }
 
5043
 
 
5044
                        public override bool Resolve (BlockContext bc)
 
5045
                        {
 
5046
                                if (IsNested)
 
5047
                                        return true;
 
5048
 
 
5049
                                return base.Resolve (bc);
 
5050
                        }
 
5051
 
 
5052
                        public Expression ResolveExpression (BlockContext bc)
 
5053
                        {
 
5054
                                var e = Initializer.Resolve (bc);
 
5055
                                if (e == null)
 
5056
                                        return null;
 
5057
 
 
5058
                                li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
 
5059
                                Initializer = ResolveInitializer (bc, Variable, e);
 
5060
                                return e;
 
5061
                        }
 
5062
 
 
5063
                        protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
 
5064
                        {
 
5065
                                if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 
5066
                                        initializer = initializer.Resolve (bc);
 
5067
                                        if (initializer == null)
 
5068
                                                return null;
 
5069
 
 
5070
                                        // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
 
5071
                                        Arguments args = new Arguments (1);
 
5072
                                        args.Add (new Argument (initializer));
 
5073
                                        initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
 
5074
                                        if (initializer == null)
 
5075
                                                return null;
 
5076
 
 
5077
                                        var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
 
5078
                                        dispose_call = CreateDisposeCall (bc, var);
 
5079
                                        dispose_call.Resolve (bc);
 
5080
 
 
5081
                                        return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
 
5082
                                }
 
5083
 
 
5084
                                if (li == Variable) {
 
5085
                                        CheckIDiposableConversion (bc, li, initializer);
 
5086
                                        dispose_call = CreateDisposeCall (bc, li);
 
5087
                                        dispose_call.Resolve (bc);
 
5088
                                }
 
5089
 
 
5090
                                return base.ResolveInitializer (bc, li, initializer);
 
5091
                        }
 
5092
 
 
5093
                        protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
 
5094
                        {
 
5095
                                var type = li.Type;
 
5096
 
 
5097
                                if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
 
5098
                                        if (type.IsNullableType) {
 
5099
                                                // it's handled in CreateDisposeCall
 
5100
                                                return;
 
5101
                                        }
 
5102
 
 
5103
                                        bc.Report.SymbolRelatedToPreviousError (type);
 
5104
                                        var loc = type_expr == null ? initializer.Location : type_expr.Location;
 
5105
                                        bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
 
5106
                                                type.GetSignatureForError ());
 
5107
 
 
5108
                                        return;
 
5109
                                }
 
5110
                        }
 
5111
 
 
5112
                        protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
 
5113
                        {
 
5114
                                var lvr = lv.CreateReferenceExpression (bc, lv.Location);
 
5115
                                var type = lv.Type;
 
5116
                                var loc = lv.Location;
 
5117
 
 
5118
                                var idt = bc.BuiltinTypes.IDisposable;
 
5119
                                var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
 
5120
 
 
5121
                                var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
 
5122
                                dispose_mg.InstanceExpression = type.IsNullableType ?
 
5123
                                        new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
 
5124
                                        lvr;
 
5125
 
 
5126
                                Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
 
5127
 
 
5128
                                // Add conditional call when disposing possible null variable
 
5129
                                if (!type.IsStruct || type.IsNullableType)
 
5130
                                        dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, loc);
 
5131
 
 
5132
                                return dispose;
 
5133
                        }
 
5134
 
 
5135
                        public Statement RewriteForDeclarators (BlockContext bc, Statement stmt)
 
5136
                        {
 
5137
                                for (int i = declarators.Count - 1; i >= 0; --i) {
 
5138
                                        var d = declarators [i];
 
5139
                                        var vd = new VariableDeclaration (d.Variable, type_expr.Location);
 
5140
                                        vd.Initializer = d.Initializer;
 
5141
                                        vd.IsNested = true;
 
5142
                                        vd.dispose_call = CreateDisposeCall (bc, d.Variable);
 
5143
                                        vd.dispose_call.Resolve (bc);
 
5144
 
 
5145
                                        stmt = new Using (vd, stmt, d.Variable.Location);
 
5146
                                }
 
5147
 
 
5148
                                declarators = null;
 
5149
                                return stmt;
 
5150
                        }
 
5151
 
 
5152
                        public override object Accept (StructuralVisitor visitor)
 
5153
                        {
 
5154
                                return visitor.Visit (this);
 
5155
                        }       
 
5156
                }
 
5157
 
 
5158
                VariableDeclaration decl;
 
5159
 
 
5160
                public Using (VariableDeclaration decl, Statement stmt, Location loc)
 
5161
                        : base (stmt, loc)
 
5162
                {
 
5163
                        this.decl = decl;
 
5164
                }
 
5165
 
 
5166
                public Using (Expression expr, Statement stmt, Location loc)
 
5167
                        : base (stmt, loc)
 
5168
                {
 
5169
                        this.decl = new VariableDeclaration (expr);
 
5170
                }
 
5171
 
 
5172
                #region Properties
 
5173
 
 
5174
                public Expression Expression {
 
5175
                        get {
 
5176
                                return decl.Variable == null ? decl.Initializer : null;
 
5177
                        }
 
5178
                }
 
5179
 
 
5180
                public BlockVariableDeclaration Variables {
 
5181
                        get {
 
5182
                                return decl;
 
5183
                        }
 
5184
                }
 
5185
 
 
5186
                #endregion
 
5187
 
 
5188
                protected override void EmitPreTryBody (EmitContext ec)
 
5189
                {
 
5190
                        decl.Emit (ec);
 
5191
                }
 
5192
 
 
5193
                protected override void EmitTryBody (EmitContext ec)
 
5194
                {
 
5195
                        stmt.Emit (ec);
 
5196
                }
 
5197
 
 
5198
                protected override void EmitFinallyBody (EmitContext ec)
 
5199
                {
 
5200
                        decl.EmitDispose (ec);
 
5201
                }
 
5202
 
 
5203
                public override bool Resolve (BlockContext ec)
 
5204
                {
 
5205
                        VariableReference vr;
 
5206
                        bool vr_locked = false;
 
5207
 
 
5208
                        using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
 
5209
                                if (decl.Variable == null) {
 
5210
                                        vr = decl.ResolveExpression (ec) as VariableReference;
 
5211
                                        if (vr != null) {
 
5212
                                                vr_locked = vr.IsLockedByStatement;
 
5213
                                                vr.IsLockedByStatement = true;
 
5214
                                        }
 
5215
                                } else {
 
5216
                                        if (!decl.Resolve (ec))
 
5217
                                                return false;
 
5218
 
 
5219
                                        if (decl.Declarators != null) {
 
5220
                                                stmt = decl.RewriteForDeclarators (ec, stmt);
 
5221
                                        }
 
5222
 
 
5223
                                        vr = null;
 
5224
                                }
 
5225
                        }
 
5226
 
 
5227
                        ec.StartFlowBranching (this);
 
5228
 
 
5229
                        stmt.Resolve (ec);
 
5230
 
 
5231
                        ec.EndFlowBranching ();
 
5232
 
 
5233
                        if (vr != null)
 
5234
                                vr.IsLockedByStatement = vr_locked;
 
5235
 
 
5236
                        base.Resolve (ec);
 
5237
 
 
5238
                        return true;
 
5239
                }
 
5240
 
 
5241
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
5242
                {
 
5243
                        Using target = (Using) t;
 
5244
 
 
5245
                        target.decl = (VariableDeclaration) decl.Clone (clonectx);
 
5246
                        target.stmt = stmt.Clone (clonectx);
 
5247
                }
 
5248
                public override object Accept (StructuralVisitor visitor)
 
5249
                {
 
5250
                        return visitor.Visit (this);
 
5251
                }
 
5252
        }
 
5253
 
 
5254
        /// <summary>
 
5255
        ///   Implementation of the foreach C# statement
 
5256
        /// </summary>
 
5257
        public class Foreach : Statement {
 
5258
 
 
5259
                sealed class ArrayForeach : Statement
 
5260
                {
 
5261
                        readonly Foreach for_each;
 
5262
                        readonly Statement statement;
 
5263
 
 
5264
                        Expression conv;
 
5265
                        TemporaryVariableReference[] lengths;
 
5266
                        Expression [] length_exprs;
 
5267
                        StatementExpression[] counter;
 
5268
                        TemporaryVariableReference[] variables;
 
5269
 
 
5270
                        TemporaryVariableReference copy;
 
5271
                        Expression access;
 
5272
                        LocalVariableReference variable;
 
5273
 
 
5274
                        public ArrayForeach (Foreach @foreach, int rank)
 
5275
                        {
 
5276
                                for_each = @foreach;
 
5277
                                statement = for_each.statement;
 
5278
                                loc = @foreach.loc;
 
5279
                                variable = new LocalVariableReference (for_each.variable, loc);
 
5280
 
 
5281
                                counter = new StatementExpression[rank];
 
5282
                                variables = new TemporaryVariableReference[rank];
 
5283
                                length_exprs = new Expression [rank];
 
5284
 
 
5285
                                //
 
5286
                                // Only use temporary length variables when dealing with
 
5287
                                // multi-dimensional arrays
 
5288
                                //
 
5289
                                if (rank > 1)
 
5290
                                        lengths = new TemporaryVariableReference [rank];
 
5291
                        }
 
5292
 
 
5293
                        protected override void CloneTo (CloneContext clonectx, Statement target)
 
5294
                        {
 
5295
                                throw new NotImplementedException ();
 
5296
                        }
 
5297
 
 
5298
                        public override bool Resolve (BlockContext ec)
 
5299
                        {
 
5300
                                Block variables_block = variable.local_info.Block;
 
5301
                                copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
 
5302
                                copy.Resolve (ec);
 
5303
 
 
5304
                                int rank = length_exprs.Length;
 
5305
                                Arguments list = new Arguments (rank);
 
5306
                                for (int i = 0; i < rank; i++) {
 
5307
                                        var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
 
5308
                                        variables[i] = v;
 
5309
                                        counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
 
5310
                                        counter[i].Resolve (ec);
 
5311
 
 
5312
                                        if (rank == 1) {
 
5313
                                                length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
 
5314
                                        } else {
 
5315
                                                lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
 
5316
                                                lengths[i].Resolve (ec);
 
5317
 
 
5318
                                                Arguments args = new Arguments (1);
 
5319
                                                args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
 
5320
                                                length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
 
5321
                                        }
 
5322
 
 
5323
                                        list.Add (new Argument (v));
 
5324
                                }
 
5325
 
 
5326
                                access = new ElementAccess (copy, list, loc).Resolve (ec);
 
5327
                                if (access == null)
 
5328
                                        return false;
 
5329
 
 
5330
                                TypeSpec var_type;
 
5331
                                if (for_each.type is VarExpr) {
 
5332
                                        // Infer implicitly typed local variable from foreach array type
 
5333
                                        var_type = access.Type;
 
5334
                                } else {
 
5335
                                        var_type = for_each.type.ResolveAsType (ec);
 
5336
                                }
 
5337
 
 
5338
                                if (var_type == null)
 
5339
                                        return false;
 
5340
 
 
5341
                                conv = Convert.ExplicitConversion (ec, access, var_type, loc);
 
5342
                                if (conv == null)
 
5343
                                        return false;
 
5344
 
 
5345
                                bool ok = true;
 
5346
 
 
5347
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
5348
                                ec.CurrentBranching.CreateSibling ();
 
5349
 
 
5350
                                variable.local_info.Type = conv.Type;
 
5351
                                variable.Resolve (ec);
 
5352
 
 
5353
                                ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
 
5354
                                if (!statement.Resolve (ec))
 
5355
                                        ok = false;
 
5356
                                ec.EndFlowBranching ();
 
5357
 
 
5358
                                // There's no direct control flow from the end of the embedded statement to the end of the loop
 
5359
                                ec.CurrentBranching.CurrentUsageVector.Goto ();
 
5360
 
 
5361
                                ec.EndFlowBranching ();
 
5362
 
 
5363
                                return ok;
 
5364
                        }
 
5365
 
 
5366
                        protected override void DoEmit (EmitContext ec)
 
5367
                        {
 
5368
                                copy.EmitAssign (ec, for_each.expr);
 
5369
 
 
5370
                                int rank = length_exprs.Length;
 
5371
                                Label[] test = new Label [rank];
 
5372
                                Label[] loop = new Label [rank];
 
5373
 
 
5374
                                for (int i = 0; i < rank; i++) {
 
5375
                                        test [i] = ec.DefineLabel ();
 
5376
                                        loop [i] = ec.DefineLabel ();
 
5377
 
 
5378
                                        if (lengths != null)
 
5379
                                                lengths [i].EmitAssign (ec, length_exprs [i]);
 
5380
                                }
 
5381
 
 
5382
                                IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
 
5383
                                for (int i = 0; i < rank; i++) {
 
5384
                                        variables [i].EmitAssign (ec, zero);
 
5385
 
 
5386
                                        ec.Emit (OpCodes.Br, test [i]);
 
5387
                                        ec.MarkLabel (loop [i]);
 
5388
                                }
 
5389
 
 
5390
                                variable.local_info.CreateBuilder (ec);
 
5391
                                variable.EmitAssign (ec, conv, false, false);
 
5392
 
 
5393
                                statement.Emit (ec);
 
5394
 
 
5395
                                ec.MarkLabel (ec.LoopBegin);
 
5396
 
 
5397
                                for (int i = rank - 1; i >= 0; i--){
 
5398
                                        counter [i].Emit (ec);
 
5399
 
 
5400
                                        ec.MarkLabel (test [i]);
 
5401
                                        variables [i].Emit (ec);
 
5402
 
 
5403
                                        if (lengths != null)
 
5404
                                                lengths [i].Emit (ec);
 
5405
                                        else
 
5406
                                                length_exprs [i].Emit (ec);
 
5407
 
 
5408
                                        ec.Emit (OpCodes.Blt, loop [i]);
 
5409
                                }
 
5410
 
 
5411
                                ec.MarkLabel (ec.LoopEnd);
 
5412
                        }
 
5413
                }
 
5414
 
 
5415
                sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
 
5416
                {
 
5417
                        class Body : Statement
 
5418
                        {
 
5419
                                TypeSpec type;
 
5420
                                LocalVariableReference variable;
 
5421
                                Expression current, conv;
 
5422
                                Statement statement;
 
5423
 
 
5424
                                public Body (TypeSpec type, LocalVariable variable,
 
5425
                                                                   Expression current, Statement statement,
 
5426
                                                                   Location loc)
 
5427
                                {
 
5428
                                        this.type = type;
 
5429
                                        this.variable = new LocalVariableReference (variable, loc);
 
5430
                                        this.current = current;
 
5431
                                        this.statement = statement;
 
5432
                                        this.loc = loc;
 
5433
                                }
 
5434
 
 
5435
                                protected override void CloneTo (CloneContext clonectx, Statement target)
 
5436
                                {
 
5437
                                        throw new NotImplementedException ();
 
5438
                                }
 
5439
 
 
5440
                                public override bool Resolve (BlockContext ec)
 
5441
                                {
 
5442
                                        current = current.Resolve (ec);
 
5443
                                        if (current == null)
 
5444
                                                return false;
 
5445
 
 
5446
                                        conv = Convert.ExplicitConversion (ec, current, type, loc);
 
5447
                                        if (conv == null)
 
5448
                                                return false;
 
5449
 
 
5450
                                        variable.local_info.Type = conv.Type;
 
5451
                                        variable.Resolve (ec);
 
5452
 
 
5453
                                        if (!statement.Resolve (ec))
 
5454
                                                return false;
 
5455
 
 
5456
                                        return true;
 
5457
                                }
 
5458
 
 
5459
                                protected override void DoEmit (EmitContext ec)
 
5460
                                {
 
5461
                                        variable.local_info.CreateBuilder (ec);
 
5462
                                        variable.EmitAssign (ec, conv, false, false);
 
5463
 
 
5464
                                        statement.Emit (ec);
 
5465
                                }
 
5466
                        }
 
5467
 
 
5468
                        class RuntimeDispose : Using.VariableDeclaration
 
5469
                        {
 
5470
                                public RuntimeDispose (LocalVariable lv, Location loc)
 
5471
                                        : base (lv, loc)
 
5472
                                {
 
5473
                                }
 
5474
 
 
5475
                                protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
 
5476
                                {
 
5477
                                        // Defered to runtime check
 
5478
                                }
 
5479
 
 
5480
                                protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
 
5481
                                {
 
5482
                                        var idt = bc.BuiltinTypes.IDisposable;
 
5483
 
 
5484
                                        //
 
5485
                                        // Fabricates code like
 
5486
                                        //
 
5487
                                        // if ((temp = vr as IDisposable) != null) temp.Dispose ();
 
5488
                                        //
 
5489
 
 
5490
                                        var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
 
5491
 
 
5492
                                        var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
 
5493
                                                dispose_variable.CreateReferenceExpression (bc, loc),
 
5494
                                                new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
 
5495
                                                loc), new NullLiteral (loc), loc);
 
5496
 
 
5497
                                        var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
 
5498
 
 
5499
                                        var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
 
5500
                                        dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
 
5501
 
 
5502
                                        Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
 
5503
                                        return new If (idisaposable_test, dispose, loc);
 
5504
                                }
 
5505
                        }
 
5506
 
 
5507
                        LocalVariable variable;
 
5508
                        Expression expr;
 
5509
                        Statement statement;
 
5510
                        Expression var_type;
 
5511
                        ExpressionStatement init;
 
5512
                        TemporaryVariableReference enumerator_variable;
 
5513
                        bool ambiguous_getenumerator_name;
 
5514
 
 
5515
                        public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
 
5516
                        {
 
5517
                                this.var_type = var_type;
 
5518
                                this.variable = var;
 
5519
                                this.expr = expr;
 
5520
                                statement = stmt;
 
5521
                                loc = l;
 
5522
                        }
 
5523
 
 
5524
                        protected override void CloneTo (CloneContext clonectx, Statement target)
 
5525
                        {
 
5526
                                throw new NotImplementedException ();
 
5527
                        }
 
5528
 
 
5529
                        void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
 
5530
                        {
 
5531
                                rc.Report.SymbolRelatedToPreviousError (enumerator);
 
5532
                                rc.Report.Error (202, loc,
 
5533
                                        "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
 
5534
                                                enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
 
5535
                        }
 
5536
 
 
5537
                        MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
 
5538
                        {
 
5539
                                //
 
5540
                                // Option 1: Try to match by name GetEnumerator first
 
5541
                                //
 
5542
                                var mexpr = Expression.MemberLookup (rc, false, expr.Type,
 
5543
                                        "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
 
5544
 
 
5545
                                var mg = mexpr as MethodGroupExpr;
 
5546
                                if (mg != null) {
 
5547
                                        mg.InstanceExpression = expr;
 
5548
                                        Arguments args = new Arguments (0);
 
5549
                                        mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
 
5550
 
 
5551
                                        // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
 
5552
                                        if (ambiguous_getenumerator_name)
 
5553
                                                mg = null;
 
5554
 
 
5555
                                        if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
 
5556
                                                return mg;
 
5557
                                        }
 
5558
                                }
 
5559
 
 
5560
                                //
 
5561
                                // Option 2: Try to match using IEnumerable interfaces with preference of generic version
 
5562
                                //
 
5563
                                var t = expr.Type;
 
5564
                                PredefinedMember<MethodSpec> iface_candidate = null;
 
5565
                                var ptypes = rc.Module.PredefinedTypes;
 
5566
                                var gen_ienumerable = ptypes.IEnumerableGeneric;
 
5567
                                if (!gen_ienumerable.Define ())
 
5568
                                        gen_ienumerable = null;
 
5569
 
 
5570
                                do {
 
5571
                                        var ifaces = t.Interfaces;
 
5572
                                        if (ifaces != null) {
 
5573
                                                foreach (var iface in ifaces) {
 
5574
                                                        if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
 
5575
                                                                if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
 
5576
                                                                        rc.Report.SymbolRelatedToPreviousError (expr.Type);
 
5577
                                                                        rc.Report.Error (1640, loc,
 
5578
                                                                                "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
 
5579
                                                                                expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
 
5580
 
 
5581
                                                                        return null;
 
5582
                                                                }
 
5583
 
 
5584
                                                                // TODO: Cache this somehow
 
5585
                                                                iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
 
5586
                                                                        MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
 
5587
 
 
5588
                                                                continue;
 
5589
                                                        }
 
5590
 
 
5591
                                                        if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
 
5592
                                                                iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
 
5593
                                                        }
 
5594
                                                }
 
5595
                                        }
 
5596
 
 
5597
                                        if (t.IsGenericParameter)
 
5598
                                                t = t.BaseType;
 
5599
                                        else
 
5600
                                                t = null;
 
5601
 
 
5602
                                } while (t != null);
 
5603
 
 
5604
                                if (iface_candidate == null) {
 
5605
                                        rc.Report.Error (1579, loc,
 
5606
                                                "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
 
5607
                                                expr.Type.GetSignatureForError (), "GetEnumerator");
 
5608
 
 
5609
                                        return null;
 
5610
                                }
 
5611
 
 
5612
                                var method = iface_candidate.Resolve (loc);
 
5613
                                if (method == null)
 
5614
                                        return null;
 
5615
 
 
5616
                                mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
 
5617
                                mg.InstanceExpression = expr;
 
5618
                                return mg;
 
5619
                        }
 
5620
 
 
5621
                        MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
 
5622
                        {
 
5623
                                var ms = MemberCache.FindMember (enumerator.ReturnType,
 
5624
                                        MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
 
5625
                                        BindingRestriction.InstanceOnly) as MethodSpec;
 
5626
 
 
5627
                                if (ms == null || !ms.IsPublic) {
 
5628
                                        Error_WrongEnumerator (rc, enumerator);
 
5629
                                        return null;
 
5630
                                }
 
5631
 
 
5632
                                return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
 
5633
                        }
 
5634
 
 
5635
                        PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
 
5636
                        {
 
5637
                                var ps = MemberCache.FindMember (enumerator.ReturnType,
 
5638
                                        MemberFilter.Property ("Current", null),
 
5639
                                        BindingRestriction.InstanceOnly) as PropertySpec;
 
5640
 
 
5641
                                if (ps == null || !ps.IsPublic) {
 
5642
                                        Error_WrongEnumerator (rc, enumerator);
 
5643
                                        return null;
 
5644
                                }
 
5645
 
 
5646
                                return ps;
 
5647
                        }
 
5648
 
 
5649
                        public override bool Resolve (BlockContext ec)
 
5650
                        {
 
5651
                                bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
 
5652
 
 
5653
                                if (is_dynamic) {
 
5654
                                        expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
 
5655
                                } else if (expr.Type.IsNullableType) {
 
5656
                                        expr = new Nullable.UnwrapCall (expr).Resolve (ec);
 
5657
                                }
 
5658
 
 
5659
                                var get_enumerator_mg = ResolveGetEnumerator (ec);
 
5660
                                if (get_enumerator_mg == null) {
 
5661
                                        return false;
 
5662
                                }
 
5663
 
 
5664
                                var get_enumerator = get_enumerator_mg.BestCandidate;
 
5665
                                enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
 
5666
                                enumerator_variable.Resolve (ec);
 
5667
 
 
5668
                                // Prepare bool MoveNext ()
 
5669
                                var move_next_mg = ResolveMoveNext (ec, get_enumerator);
 
5670
                                if (move_next_mg == null) {
 
5671
                                        return false;
 
5672
                                }
 
5673
 
 
5674
                                move_next_mg.InstanceExpression = enumerator_variable;
 
5675
 
 
5676
                                // Prepare ~T~ Current { get; }
 
5677
                                var current_prop = ResolveCurrent (ec, get_enumerator);
 
5678
                                if (current_prop == null) {
 
5679
                                        return false;
 
5680
                                }
 
5681
 
 
5682
                                var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
 
5683
                                if (current_pe == null)
 
5684
                                        return false;
 
5685
 
 
5686
                                VarExpr ve = var_type as VarExpr;
 
5687
 
 
5688
                                if (ve != null) {
 
5689
                                        if (is_dynamic) {
 
5690
                                                // Source type is dynamic, set element type to dynamic too
 
5691
                                                variable.Type = ec.BuiltinTypes.Dynamic;
 
5692
                                        } else {
 
5693
                                                // Infer implicitly typed local variable from foreach enumerable type
 
5694
                                                variable.Type = current_pe.Type;
 
5695
                                        }
 
5696
                                } else {
 
5697
                                        if (is_dynamic) {
 
5698
                                                // Explicit cast of dynamic collection elements has to be done at runtime
 
5699
                                                current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
 
5700
                                        }
 
5701
 
 
5702
                                        variable.Type = var_type.ResolveAsType (ec);
 
5703
                                }
 
5704
 
 
5705
                                if (variable.Type == null)
 
5706
                                        return false;
 
5707
 
 
5708
                                var init = new Invocation (get_enumerator_mg, null);
 
5709
 
 
5710
                                statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
 
5711
                                        new Body (variable.Type, variable, current_pe, statement, loc), loc);
 
5712
 
 
5713
                                var enum_type = enumerator_variable.Type;
 
5714
 
 
5715
                                //
 
5716
                                // Add Dispose method call when enumerator can be IDisposable
 
5717
                                //
 
5718
                                if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
 
5719
                                        if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
 
5720
                                                //
 
5721
                                                // Runtime Dispose check
 
5722
                                                //
 
5723
                                                var vd = new RuntimeDispose (enumerator_variable.LocalInfo, loc);
 
5724
                                                vd.Initializer = init;
 
5725
                                                statement = new Using (vd, statement, loc);
 
5726
                                        } else {
 
5727
                                                //
 
5728
                                                // No Dispose call needed
 
5729
                                                //
 
5730
                                                this.init = new SimpleAssign (enumerator_variable, init);
 
5731
                                                this.init.Resolve (ec);
 
5732
                                        }
 
5733
                                } else {
 
5734
                                        //
 
5735
                                        // Static Dispose check
 
5736
                                        //
 
5737
                                        var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
 
5738
                                        vd.Initializer = init;
 
5739
                                        statement = new Using (vd, statement, loc);
 
5740
                                }
 
5741
 
 
5742
                                return statement.Resolve (ec);
 
5743
                        }
 
5744
 
 
5745
                        protected override void DoEmit (EmitContext ec)
 
5746
                        {
 
5747
                                enumerator_variable.LocalInfo.CreateBuilder (ec);
 
5748
 
 
5749
                                if (init != null)
 
5750
                                        init.EmitStatement (ec);
 
5751
 
 
5752
                                statement.Emit (ec);
 
5753
                        }
 
5754
 
 
5755
                        #region IErrorHandler Members
 
5756
 
 
5757
                        bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
 
5758
                        {
 
5759
                                ec.Report.SymbolRelatedToPreviousError (best);
 
5760
                                ec.Report.Warning (278, 2, loc,
 
5761
                                        "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
 
5762
                                        expr.Type.GetSignatureForError (), "enumerable",
 
5763
                                        best.GetSignatureForError (), ambiguous.GetSignatureForError ());
 
5764
 
 
5765
                                ambiguous_getenumerator_name = true;
 
5766
                                return true;
 
5767
                        }
 
5768
 
 
5769
                        bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
 
5770
                        {
 
5771
                                return false;
 
5772
                        }
 
5773
 
 
5774
                        bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
 
5775
                        {
 
5776
                                return false;
 
5777
                        }
 
5778
 
 
5779
                        bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
 
5780
                        {
 
5781
                                return false;
 
5782
                        }
 
5783
 
 
5784
                        #endregion
 
5785
                }
 
5786
 
 
5787
                Expression type;
 
5788
                LocalVariable variable;
 
5789
                Expression expr;
 
5790
                Statement statement;
 
5791
                
 
5792
                public Expression TypeExpr {
 
5793
                        get { return this.type; }
 
5794
                }
 
5795
 
 
5796
                public LocalVariable Variable {
 
5797
                        get { return this.variable; }
 
5798
                }
 
5799
 
 
5800
                public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
 
5801
                {
 
5802
                        this.type = type;
 
5803
                        this.variable = var;
 
5804
                        this.expr = expr;
 
5805
                        statement = stmt;
 
5806
                        loc = l;
 
5807
                }
 
5808
 
 
5809
                public Statement Statement {
 
5810
                        get { return statement; }
 
5811
                }
 
5812
 
 
5813
                public Expression Expr {
 
5814
                        get { return this.expr; }
 
5815
                }
 
5816
 
 
5817
                public override bool Resolve (BlockContext ec)
 
5818
                {
 
5819
                        expr = expr.Resolve (ec);
 
5820
                        if (expr == null)
 
5821
                                return false;
 
5822
 
 
5823
                        if (expr.IsNull) {
 
5824
                                ec.Report.Error (186, loc, "Use of null is not valid in this context");
 
5825
                                return false;
 
5826
                        }
 
5827
 
 
5828
                        if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
 
5829
                                statement = new ArrayForeach (this, 1);
 
5830
                        } else if (expr.Type is ArrayContainer) {
 
5831
                                statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
 
5832
                        } else {
 
5833
                                if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
 
5834
                                        ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
 
5835
                                                expr.ExprClassName);
 
5836
                                        return false;
 
5837
                                }
 
5838
 
 
5839
                                statement = new CollectionForeach (type, variable, expr, statement, loc);
 
5840
                        }
 
5841
 
 
5842
                        return statement.Resolve (ec);
 
5843
                }
 
5844
 
 
5845
                protected override void DoEmit (EmitContext ec)
 
5846
                {
 
5847
                        Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
 
5848
                        ec.LoopBegin = ec.DefineLabel ();
 
5849
                        ec.LoopEnd = ec.DefineLabel ();
 
5850
 
 
5851
                        statement.Emit (ec);
 
5852
 
 
5853
                        ec.LoopBegin = old_begin;
 
5854
                        ec.LoopEnd = old_end;
 
5855
                }
 
5856
 
 
5857
                protected override void CloneTo (CloneContext clonectx, Statement t)
 
5858
                {
 
5859
                        Foreach target = (Foreach) t;
 
5860
 
 
5861
                        target.type = type.Clone (clonectx);
 
5862
                        target.expr = expr.Clone (clonectx);
 
5863
                        target.statement = statement.Clone (clonectx);
 
5864
                }
 
5865
                
 
5866
                public override object Accept (StructuralVisitor visitor)
 
5867
                {
 
5868
                        return visitor.Visit (this);
 
5869
                }
 
5870
        }
 
5871
}