~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs

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