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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/nullable.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
// nullable.cs: Nullable types support
 
3
//
 
4
// Authors: Martin Baulig (martin@ximian.com)
 
5
//          Miguel de Icaza (miguel@ximian.com)
 
6
//          Marek Safar (marek.safar@gmail.com)
 
7
//
 
8
// Dual licensed under the terms of the MIT X11 or GNU GPL
 
9
//
 
10
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
 
11
// Copyright 2004-2008 Novell, Inc
 
12
// Copyright 2011 Xamarin Inc
 
13
//
 
14
 
 
15
using System;
 
16
 
 
17
#if STATIC
 
18
using IKVM.Reflection.Emit;
 
19
#else
 
20
using System.Reflection.Emit;
 
21
#endif
 
22
        
 
23
namespace Mono.CSharp.Nullable
 
24
{
 
25
        public class NullableType : TypeExpr
 
26
        {
 
27
                readonly TypeSpec underlying;
 
28
 
 
29
                public NullableType (TypeSpec type, Location loc)
 
30
                {
 
31
                        this.underlying = type;
 
32
                        this.loc = loc;
 
33
                }
 
34
 
 
35
                public override TypeSpec ResolveAsType (IMemberContext ec)
 
36
                {
 
37
                        eclass = ExprClass.Type;
 
38
 
 
39
                        var otype = ec.Module.PredefinedTypes.Nullable.Resolve ();
 
40
                        if (otype == null)
 
41
                                return null;
 
42
 
 
43
                        TypeArguments args = new TypeArguments (new TypeExpression (underlying, loc));
 
44
                        GenericTypeExpr ctype = new GenericTypeExpr (otype, args, loc);
 
45
                        
 
46
                        type = ctype.ResolveAsType (ec);
 
47
                        return type;
 
48
                }
 
49
        }
 
50
 
 
51
        static class NullableInfo
 
52
        {
 
53
                public static MethodSpec GetConstructor (TypeSpec nullableType)
 
54
                {
 
55
                        return (MethodSpec) MemberCache.FindMember (nullableType,
 
56
                                MemberFilter.Constructor (ParametersCompiled.CreateFullyResolved (GetUnderlyingType (nullableType))), BindingRestriction.DeclaredOnly);
 
57
                }
 
58
 
 
59
                public static MethodSpec GetHasValue (TypeSpec nullableType)
 
60
                {
 
61
                        return (MethodSpec) MemberCache.FindMember (nullableType,
 
62
                                MemberFilter.Method ("get_HasValue", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
 
63
                }
 
64
 
 
65
                public static MethodSpec GetGetValueOrDefault (TypeSpec nullableType)
 
66
                {
 
67
                        return (MethodSpec) MemberCache.FindMember (nullableType,
 
68
                                MemberFilter.Method ("GetValueOrDefault", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
 
69
                }
 
70
 
 
71
                //
 
72
                // Don't use unless really required for correctness, see Unwrap::Emit
 
73
                //
 
74
                public static MethodSpec GetValue (TypeSpec nullableType)
 
75
                {
 
76
                        return (MethodSpec) MemberCache.FindMember (nullableType,
 
77
                                MemberFilter.Method ("get_Value", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
 
78
                }
 
79
 
 
80
                public static TypeSpec GetUnderlyingType (TypeSpec nullableType)
 
81
                {
 
82
                        return ((InflatedTypeSpec) nullableType).TypeArguments[0];
 
83
                }
 
84
        }
 
85
 
 
86
        public class Unwrap : Expression, IMemoryLocation
 
87
        {
 
88
                Expression expr;
 
89
 
 
90
                LocalTemporary temp;
 
91
                readonly bool useDefaultValue;
 
92
 
 
93
                Unwrap (Expression expr, bool useDefaultValue)
 
94
                {
 
95
                        this.expr = expr;
 
96
                        this.loc = expr.Location;
 
97
                        this.useDefaultValue = useDefaultValue;
 
98
 
 
99
                        type = NullableInfo.GetUnderlyingType (expr.Type);
 
100
                        eclass = expr.eclass;
 
101
                }
 
102
 
 
103
                public override bool ContainsEmitWithAwait ()
 
104
                {
 
105
                        return expr.ContainsEmitWithAwait ();
 
106
                }
 
107
 
 
108
                public static Expression Create (Expression expr)
 
109
                {
 
110
                        //
 
111
                        // Avoid unwraping and wraping of same type
 
112
                        //
 
113
                        Wrap wrap = expr as Wrap;
 
114
                        if (wrap != null)
 
115
                                return wrap.Child;
 
116
 
 
117
                        return Create (expr, false);
 
118
                }
 
119
 
 
120
                public static Unwrap Create (Expression expr, bool useDefaultValue)
 
121
                {
 
122
                        return new Unwrap (expr, useDefaultValue);
 
123
                }
 
124
                
 
125
                public override Expression CreateExpressionTree (ResolveContext ec)
 
126
                {
 
127
                        return expr.CreateExpressionTree (ec);
 
128
                }
 
129
 
 
130
                protected override Expression DoResolve (ResolveContext ec)
 
131
                {
 
132
                        return this;
 
133
                }
 
134
 
 
135
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
 
136
                {
 
137
                        expr = expr.DoResolveLValue (ec, right_side);
 
138
                        return this;
 
139
                }
 
140
 
 
141
                public override void Emit (EmitContext ec)
 
142
                {
 
143
                        Store (ec);
 
144
 
 
145
                        var call = new CallEmitter ();
 
146
                        call.InstanceExpression = this;
 
147
 
 
148
                        //
 
149
                        // Using GetGetValueOrDefault is prefered because JIT can possibly
 
150
                        // inline it whereas Value property contains a throw which is very
 
151
                        // unlikely to be inlined
 
152
                        //
 
153
                        if (useDefaultValue)
 
154
                                call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
 
155
                        else
 
156
                                call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
 
157
                }
 
158
 
 
159
                public void EmitCheck (EmitContext ec)
 
160
                {
 
161
                        Store (ec);
 
162
 
 
163
                        var call = new CallEmitter ();
 
164
                        call.InstanceExpression = this;
 
165
 
 
166
                        call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
 
167
                }
 
168
 
 
169
                public override bool Equals (object obj)
 
170
                {
 
171
                        Unwrap uw = obj as Unwrap;
 
172
                        return uw != null && expr.Equals (uw.expr);
 
173
                }
 
174
 
 
175
                public Expression Original {
 
176
                        get {
 
177
                                return expr;
 
178
                        }
 
179
                }
 
180
                
 
181
                public override int GetHashCode ()
 
182
                {
 
183
                        return expr.GetHashCode ();
 
184
                }
 
185
 
 
186
                public override bool IsNull {
 
187
                        get {
 
188
                                return expr.IsNull;
 
189
                        }
 
190
                }
 
191
 
 
192
                void Store (EmitContext ec)
 
193
                {
 
194
                        if (temp != null)
 
195
                                return;
 
196
 
 
197
                        if (expr is VariableReference)
 
198
                                return;
 
199
 
 
200
                        expr.Emit (ec);
 
201
                        LocalVariable.Store (ec);
 
202
                }
 
203
 
 
204
                public void Load (EmitContext ec)
 
205
                {
 
206
                        if (expr is VariableReference)
 
207
                                expr.Emit (ec);
 
208
                        else
 
209
                                LocalVariable.Emit (ec);
 
210
                }
 
211
 
 
212
                public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
 
213
                {
 
214
                        return expr.MakeExpression (ctx);
 
215
                }
 
216
 
 
217
                public void AddressOf (EmitContext ec, AddressOp mode)
 
218
                {
 
219
                        IMemoryLocation ml = expr as VariableReference;
 
220
                        if (ml != null)
 
221
                                ml.AddressOf (ec, mode);
 
222
                        else
 
223
                                LocalVariable.AddressOf (ec, mode);
 
224
                }
 
225
 
 
226
                //
 
227
                // Keeps result of non-variable expression
 
228
                //
 
229
                LocalTemporary LocalVariable {
 
230
                        get {
 
231
                                if (temp == null)
 
232
                                        temp = new LocalTemporary (expr.Type);
 
233
                                return temp;
 
234
                        }
 
235
                }
 
236
        }
 
237
 
 
238
        //
 
239
        // Calls get_Value method on nullable expression
 
240
        //
 
241
        public class UnwrapCall : CompositeExpression
 
242
        {
 
243
                public UnwrapCall (Expression expr)
 
244
                        : base (expr)
 
245
                {
 
246
                }
 
247
 
 
248
                protected override Expression DoResolve (ResolveContext rc)
 
249
                {
 
250
                        base.DoResolve (rc);
 
251
 
 
252
                        if (type != null)
 
253
                                type = NullableInfo.GetUnderlyingType (type);
 
254
 
 
255
                        return this;
 
256
                }
 
257
 
 
258
                public override void Emit (EmitContext ec)
 
259
                {
 
260
                        var call = new CallEmitter ();
 
261
                        call.InstanceExpression = Child;
 
262
                        call.EmitPredefined (ec, NullableInfo.GetValue (Child.Type), null);
 
263
                }
 
264
        }
 
265
 
 
266
        public class Wrap : TypeCast
 
267
        {
 
268
                private Wrap (Expression expr, TypeSpec type)
 
269
                        : base (expr, type)
 
270
                {
 
271
                        eclass = ExprClass.Value;
 
272
                }
 
273
 
 
274
                public override Expression CreateExpressionTree (ResolveContext ec)
 
275
                {
 
276
                        TypeCast child_cast = child as TypeCast;
 
277
                        if (child_cast != null) {
 
278
                                child.Type = type;
 
279
                                return child_cast.CreateExpressionTree (ec);
 
280
                        }
 
281
 
 
282
                        return base.CreateExpressionTree (ec);
 
283
                }
 
284
 
 
285
                public static Expression Create (Expression expr, TypeSpec type)
 
286
                {
 
287
                        //
 
288
                        // Avoid unwraping and wraping of the same type
 
289
                        //
 
290
                        Unwrap unwrap = expr as Unwrap;
 
291
                        if (unwrap != null && expr.Type == NullableInfo.GetUnderlyingType (type))
 
292
                                return unwrap.Original;
 
293
                
 
294
                        return new Wrap (expr, type);
 
295
                }
 
296
                
 
297
                public override void Emit (EmitContext ec)
 
298
                {
 
299
                        child.Emit (ec);
 
300
                        ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
 
301
                }
 
302
        }
 
303
 
 
304
        //
 
305
        // Represents null literal lifted to nullable type
 
306
        //
 
307
        public class LiftedNull : NullConstant, IMemoryLocation
 
308
        {
 
309
                private LiftedNull (TypeSpec nullable_type, Location loc)
 
310
                        : base (nullable_type, loc)
 
311
                {
 
312
                        eclass = ExprClass.Value;
 
313
                }
 
314
 
 
315
                public static Constant Create (TypeSpec nullable, Location loc)
 
316
                {
 
317
                        return new LiftedNull (nullable, loc);
 
318
                }
 
319
 
 
320
                public static Constant CreateFromExpression (ResolveContext ec, Expression e)
 
321
                {
 
322
                        ec.Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
 
323
                                TypeManager.CSharpName (e.Type));
 
324
 
 
325
                        return ReducedExpression.Create (Create (e.Type, e.Location), e);
 
326
                }
 
327
 
 
328
                public override void Emit (EmitContext ec)
 
329
                {
 
330
                        // TODO: generate less temporary variables
 
331
                        LocalTemporary value_target = new LocalTemporary (type);
 
332
 
 
333
                        value_target.AddressOf (ec, AddressOp.Store);
 
334
                        ec.Emit (OpCodes.Initobj, type);
 
335
                        value_target.Emit (ec);
 
336
                        value_target.Release (ec);
 
337
                }
 
338
 
 
339
                public void AddressOf (EmitContext ec, AddressOp Mode)
 
340
                {
 
341
                        LocalTemporary value_target = new LocalTemporary (type);
 
342
                                
 
343
                        value_target.AddressOf (ec, AddressOp.Store);
 
344
                        ec.Emit (OpCodes.Initobj, type);
 
345
                        ((IMemoryLocation) value_target).AddressOf (ec, Mode);
 
346
                }
 
347
        }
 
348
 
 
349
        //
 
350
        // Generic lifting expression, supports all S/S? -> T/T? cases
 
351
        //
 
352
        public class Lifted : Expression, IMemoryLocation
 
353
        {
 
354
                Expression expr, null_value;
 
355
                Unwrap unwrap;
 
356
 
 
357
                public Lifted (Expression expr, Unwrap unwrap, TypeSpec type)
 
358
                {
 
359
                        this.expr = expr;
 
360
                        this.unwrap = unwrap;
 
361
                        this.loc = expr.Location;
 
362
                        this.type = type;
 
363
                }
 
364
 
 
365
                public Lifted (Expression expr, Expression unwrap, TypeSpec type)
 
366
                        : this (expr, unwrap as Unwrap, type)
 
367
                {
 
368
                }
 
369
 
 
370
                public override bool ContainsEmitWithAwait ()
 
371
                {
 
372
                        return unwrap.ContainsEmitWithAwait ();
 
373
                }
 
374
                
 
375
                public override Expression CreateExpressionTree (ResolveContext ec)
 
376
                {
 
377
                        return expr.CreateExpressionTree (ec);
 
378
                }                       
 
379
 
 
380
                protected override Expression DoResolve (ResolveContext ec)
 
381
                {
 
382
                        //
 
383
                        // It's null when lifting non-nullable type
 
384
                        //
 
385
                        if (unwrap == null) {
 
386
                                // S -> T? is wrap only
 
387
                                if (type.IsNullableType)
 
388
                                        return Wrap.Create (expr, type);
 
389
 
 
390
                                // S -> T can be simplified
 
391
                                return expr;
 
392
                        }
 
393
 
 
394
                        // Wrap target for T?
 
395
                        if (type.IsNullableType) {
 
396
                                expr = Wrap.Create (expr, type);
 
397
                                if (expr == null)
 
398
                                        return null;
 
399
 
 
400
                                null_value = LiftedNull.Create (type, loc);
 
401
                        } else if (TypeSpec.IsValueType (type)) {
 
402
                                null_value = LiftedNull.Create (type, loc);
 
403
                        } else {
 
404
                                null_value = new NullConstant (type, loc);
 
405
                        }
 
406
 
 
407
                        eclass = ExprClass.Value;
 
408
                        return this;
 
409
                }
 
410
 
 
411
                public override void Emit (EmitContext ec)
 
412
                {
 
413
                        Label is_null_label = ec.DefineLabel ();
 
414
                        Label end_label = ec.DefineLabel ();
 
415
 
 
416
                        unwrap.EmitCheck (ec);
 
417
                        ec.Emit (OpCodes.Brfalse, is_null_label);
 
418
 
 
419
                        expr.Emit (ec);
 
420
 
 
421
                        ec.Emit (OpCodes.Br, end_label);
 
422
                        ec.MarkLabel (is_null_label);
 
423
 
 
424
                        null_value.Emit (ec);
 
425
                        ec.MarkLabel (end_label);
 
426
                }
 
427
 
 
428
                public void AddressOf (EmitContext ec, AddressOp mode)
 
429
                {
 
430
                        unwrap.AddressOf (ec, mode);
 
431
                }
 
432
        }
 
433
 
 
434
        public class LiftedUnaryOperator : Unary, IMemoryLocation
 
435
        {
 
436
                Unwrap unwrap;
 
437
                Expression user_operator;
 
438
 
 
439
                public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
 
440
                        : base (op, expr, loc)
 
441
                {
 
442
                }
 
443
 
 
444
                public void AddressOf (EmitContext ec, AddressOp mode)
 
445
                {
 
446
                        unwrap.AddressOf (ec, mode);
 
447
                }
 
448
 
 
449
                public override Expression CreateExpressionTree (ResolveContext ec)
 
450
                {
 
451
                        if (user_operator != null)
 
452
                                return user_operator.CreateExpressionTree (ec);
 
453
 
 
454
                        if (Oper == Operator.UnaryPlus)
 
455
                                return Expr.CreateExpressionTree (ec);
 
456
 
 
457
                        return base.CreateExpressionTree (ec);
 
458
                }
 
459
 
 
460
                protected override Expression DoResolve (ResolveContext ec)
 
461
                {
 
462
                        unwrap = Unwrap.Create (Expr, false);
 
463
                        if (unwrap == null)
 
464
                                return null;
 
465
 
 
466
                        Expression res = base.ResolveOperator (ec, unwrap);
 
467
                        if (res != this) {
 
468
                                if (user_operator == null)
 
469
                                        return res;
 
470
                        } else {
 
471
                                res = Expr = LiftExpression (ec, Expr);
 
472
                        }
 
473
 
 
474
                        if (res == null)
 
475
                                return null;
 
476
 
 
477
                        eclass = ExprClass.Value;
 
478
                        type = res.Type;
 
479
                        return this;
 
480
                }
 
481
 
 
482
                public override void Emit (EmitContext ec)
 
483
                {
 
484
                        Label is_null_label = ec.DefineLabel ();
 
485
                        Label end_label = ec.DefineLabel ();
 
486
 
 
487
                        unwrap.EmitCheck (ec);
 
488
                        ec.Emit (OpCodes.Brfalse, is_null_label);
 
489
 
 
490
                        if (user_operator != null) {
 
491
                                user_operator.Emit (ec);
 
492
                        } else {
 
493
                                EmitOperator (ec, NullableInfo.GetUnderlyingType (type));
 
494
                        }
 
495
 
 
496
                        ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
 
497
                        ec.Emit (OpCodes.Br_S, end_label);
 
498
 
 
499
                        ec.MarkLabel (is_null_label);
 
500
                        LiftedNull.Create (type, loc).Emit (ec);
 
501
 
 
502
                        ec.MarkLabel (end_label);
 
503
                }
 
504
 
 
505
                static Expression LiftExpression (ResolveContext ec, Expression expr)
 
506
                {
 
507
                        var lifted_type = new NullableType (expr.Type, expr.Location);
 
508
                        if (lifted_type.ResolveAsType (ec) == null)
 
509
                                return null;
 
510
 
 
511
                        expr.Type = lifted_type.Type;
 
512
                        return expr;
 
513
                }
 
514
 
 
515
                protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
 
516
                {
 
517
                        expr = base.ResolveEnumOperator (ec, expr, predefined);
 
518
                        if (expr == null)
 
519
                                return null;
 
520
 
 
521
                        Expr = LiftExpression (ec, Expr);
 
522
                        return LiftExpression (ec, expr);
 
523
                }
 
524
 
 
525
                protected override Expression ResolveUserOperator (ResolveContext ec, Expression expr)
 
526
                {
 
527
                        expr = base.ResolveUserOperator (ec, expr);
 
528
                        if (expr == null)
 
529
                                return null;
 
530
 
 
531
                        //
 
532
                        // When a user operator is of non-nullable type
 
533
                        //
 
534
                        if (Expr is Unwrap) {
 
535
                                user_operator = LiftExpression (ec, expr);
 
536
                                return user_operator;
 
537
                        }
 
538
 
 
539
                        return expr;
 
540
                }
 
541
        }
 
542
 
 
543
        public class LiftedBinaryOperator : Binary
 
544
        {
 
545
                Unwrap left_unwrap, right_unwrap;
 
546
                Expression left_orig, right_orig;
 
547
                Expression user_operator;
 
548
                MethodSpec wrap_ctor;
 
549
 
 
550
                public LiftedBinaryOperator (Binary.Operator op, Expression left, Expression right)
 
551
                        : base (op, left, right)
 
552
                {
 
553
                }
 
554
 
 
555
                bool IsBitwiseBoolean {
 
556
                        get {
 
557
                                return (Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) &&
 
558
                                ((left_unwrap != null && left_unwrap.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) ||
 
559
                                 (right_unwrap != null && right_unwrap.Type.BuiltinType == BuiltinTypeSpec.Type.Bool));
 
560
                        }
 
561
                }
 
562
 
 
563
                bool IsLeftNullLifted {
 
564
                        get {
 
565
                                return (state & State.LeftNullLifted) != 0;
 
566
                        }
 
567
                }
 
568
 
 
569
                bool IsRightNullLifted {
 
570
                        get {
 
571
                                return (state & State.RightNullLifted) != 0;
 
572
                        }
 
573
                }
 
574
 
 
575
                public override Expression CreateExpressionTree (ResolveContext ec)
 
576
                {
 
577
                        if (user_operator != null)
 
578
                                return user_operator.CreateExpressionTree (ec);
 
579
 
 
580
                        return base.CreateExpressionTree (ec);
 
581
                }
 
582
 
 
583
                //
 
584
                // CSC 2 has this behavior, it allows structs to be compared
 
585
                // with the null literal *outside* of a generics context and
 
586
                // inlines that as true or false.
 
587
                //
 
588
                Constant CreateNullConstant (ResolveContext ec, Expression expr)
 
589
                {
 
590
                        // FIXME: Handle side effect constants
 
591
                        Constant c = new BoolConstant (ec.BuiltinTypes, Oper == Operator.Inequality, loc);
 
592
 
 
593
                        if ((Oper & Operator.EqualityMask) != 0) {
 
594
                                ec.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
 
595
                                        TypeManager.CSharpName (expr.Type), c.GetValueAsLiteral ());
 
596
                        } else {
 
597
                                ec.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
 
598
                                        TypeManager.CSharpName (expr.Type), c.GetValueAsLiteral ());
 
599
                        }
 
600
 
 
601
                        return ReducedExpression.Create (c, this);
 
602
                }
 
603
 
 
604
                protected override Expression DoResolve (ResolveContext ec)
 
605
                {
 
606
                        if ((Oper & Operator.LogicalMask) != 0) {
 
607
                                Error_OperatorCannotBeApplied (ec, left, right);
 
608
                                return null;
 
609
                        }
 
610
 
 
611
                        bool use_default_call = (Oper & (Operator.BitwiseMask | Operator.EqualityMask)) != 0;
 
612
                        left_orig = left;
 
613
                        if (left.Type.IsNullableType) {
 
614
                                left = left_unwrap = Unwrap.Create (left, use_default_call);
 
615
                                if (left == null)
 
616
                                        return null;
 
617
                        }
 
618
 
 
619
                        right_orig = right;
 
620
                        if (right.Type.IsNullableType) {
 
621
                                right = right_unwrap = Unwrap.Create (right, use_default_call);
 
622
                                if (right == null)
 
623
                                        return null;
 
624
                        }
 
625
 
 
626
                        //
 
627
                        // Some details are in 6.4.2, 7.2.7
 
628
                        // Arguments can be lifted for equal operators when the return type is bool and both
 
629
                        // arguments are of same type
 
630
                        //      
 
631
                        if (left_orig is NullLiteral) {
 
632
                                left = right;
 
633
                                state |= State.LeftNullLifted;
 
634
                                type = ec.BuiltinTypes.Bool;
 
635
                        }
 
636
 
 
637
                        if (right_orig.IsNull) {
 
638
                                if ((Oper & Operator.ShiftMask) != 0)
 
639
                                        right = new EmptyExpression (ec.BuiltinTypes.Int);
 
640
                                else
 
641
                                        right = left;
 
642
 
 
643
                                state |= State.RightNullLifted;
 
644
                                type = ec.BuiltinTypes.Bool;
 
645
                        }
 
646
 
 
647
                        eclass = ExprClass.Value;
 
648
                        return DoResolveCore (ec, left_orig, right_orig);
 
649
                }
 
650
 
 
651
                void EmitBitwiseBoolean (EmitContext ec)
 
652
                {
 
653
                        Label load_left = ec.DefineLabel ();
 
654
                        Label load_right = ec.DefineLabel ();
 
655
                        Label end_label = ec.DefineLabel ();
 
656
 
 
657
                        // null & value, null | value
 
658
                        if (left_unwrap == null) {
 
659
                                left_unwrap = right_unwrap;
 
660
                                right_unwrap = null;
 
661
                                right = left;
 
662
                        }
 
663
 
 
664
                        left_unwrap.Emit (ec);
 
665
                        ec.Emit (OpCodes.Brtrue, load_right);
 
666
 
 
667
                        // value & null, value | null
 
668
                        if (right_unwrap != null) {
 
669
                                right_unwrap.Emit (ec);
 
670
                                ec.Emit (OpCodes.Brtrue_S, load_left);
 
671
                        }
 
672
 
 
673
                        left_unwrap.EmitCheck (ec);
 
674
                        ec.Emit (OpCodes.Brfalse_S, load_right);
 
675
 
 
676
                        // load left
 
677
                        ec.MarkLabel (load_left);
 
678
 
 
679
                        if (Oper == Operator.BitwiseAnd) {
 
680
                                left_unwrap.Load (ec);
 
681
                        } else {
 
682
                                if (right_unwrap == null) {
 
683
                                        right.Emit (ec);
 
684
                                        if (right is EmptyConstantCast || right is EmptyCast)
 
685
                                                ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
 
686
                                } else {
 
687
                                        right_unwrap.Load (ec);
 
688
                                        right_unwrap = left_unwrap;
 
689
                                }
 
690
                        }
 
691
                        ec.Emit (OpCodes.Br_S, end_label);
 
692
 
 
693
                        // load right
 
694
                        ec.MarkLabel (load_right);
 
695
                        if (right_unwrap == null) {
 
696
                                if (Oper == Operator.BitwiseAnd) {
 
697
                                        right.Emit (ec);
 
698
                                        if (right is EmptyConstantCast || right is EmptyCast)
 
699
                                                ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
 
700
                                } else {
 
701
                                        left_unwrap.Load (ec);
 
702
                                }
 
703
                        } else {
 
704
                                right_unwrap.Load (ec);
 
705
                        }
 
706
 
 
707
                        ec.MarkLabel (end_label);
 
708
                }
 
709
 
 
710
                //
 
711
                // Emits optimized equality or inequality operator when possible
 
712
                //
 
713
                void EmitEquality (EmitContext ec)
 
714
                {
 
715
                        //
 
716
                        // Either left or right is null
 
717
                        //
 
718
                        if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) {
 
719
                                left_unwrap.EmitCheck (ec);
 
720
                                if (Oper == Binary.Operator.Equality) {
 
721
                                        ec.EmitInt (0);
 
722
                                        ec.Emit (OpCodes.Ceq);
 
723
                                }
 
724
                                return;
 
725
                        }
 
726
 
 
727
                        if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) {
 
728
                                right_unwrap.EmitCheck (ec);
 
729
                                if (Oper == Binary.Operator.Equality) {
 
730
                                        ec.EmitInt (0);
 
731
                                        ec.Emit (OpCodes.Ceq);
 
732
                                }
 
733
                                return;
 
734
                        }
 
735
 
 
736
                        Label dissimilar_label = ec.DefineLabel ();
 
737
                        Label end_label = ec.DefineLabel ();
 
738
 
 
739
                        if (user_operator != null) {
 
740
                                user_operator.Emit (ec);
 
741
                                ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label);
 
742
                        } else {
 
743
                                if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
 
744
                                        left = left.EmitToField (ec);
 
745
                                        right = right.EmitToField (ec);
 
746
                                }
 
747
 
 
748
                                left.Emit (ec);
 
749
                                right.Emit (ec);
 
750
 
 
751
                                ec.Emit (OpCodes.Bne_Un_S, dissimilar_label);
 
752
                        }
 
753
 
 
754
                        if (left_unwrap != null)
 
755
                                left_unwrap.EmitCheck (ec);
 
756
 
 
757
                        if (right_unwrap != null)
 
758
                                right_unwrap.EmitCheck (ec);
 
759
 
 
760
                        if (left_unwrap != null && right_unwrap != null) {
 
761
                                if (Oper == Operator.Inequality)
 
762
                                        ec.Emit (OpCodes.Xor);
 
763
                                else
 
764
                                        ec.Emit (OpCodes.Ceq);
 
765
                        } else {
 
766
                                if (Oper == Operator.Inequality) {
 
767
                                        ec.EmitInt (0);
 
768
                                        ec.Emit (OpCodes.Ceq);
 
769
                                }
 
770
                        }
 
771
 
 
772
                        ec.Emit (OpCodes.Br_S, end_label);
 
773
 
 
774
                        ec.MarkLabel (dissimilar_label);
 
775
                        if (Oper == Operator.Inequality)
 
776
                                ec.EmitInt (1);
 
777
                        else
 
778
                                ec.EmitInt (0);
 
779
 
 
780
                        ec.MarkLabel (end_label);
 
781
                }
 
782
                
 
783
                public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
 
784
                {
 
785
                        Emit (ec);
 
786
                        ec.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
 
787
                }                       
 
788
 
 
789
                public override void Emit (EmitContext ec)
 
790
                {
 
791
                        //
 
792
                        // Optimize same expression operation
 
793
                        //
 
794
                        if (right_unwrap != null && right.Equals (left))
 
795
                                right_unwrap = left_unwrap;
 
796
 
 
797
                        if (user_operator == null && IsBitwiseBoolean) {
 
798
                                EmitBitwiseBoolean (ec);
 
799
                                return;
 
800
                        }
 
801
 
 
802
                        if ((Oper & Operator.EqualityMask) != 0) {
 
803
                                EmitEquality (ec);
 
804
                                return;
 
805
                        }
 
806
 
 
807
                        Label is_null_label = ec.DefineLabel ();
 
808
                        Label end_label = ec.DefineLabel ();
 
809
 
 
810
                        if (left_unwrap != null) {
 
811
                                left_unwrap.EmitCheck (ec);
 
812
                                ec.Emit (OpCodes.Brfalse, is_null_label);
 
813
                        }
 
814
 
 
815
                        //
 
816
                        // Don't emit HasValue check when left and right expressions are same
 
817
                        //
 
818
                        if (right_unwrap != null && !left.Equals (right)) {
 
819
                                right_unwrap.EmitCheck (ec);
 
820
                                ec.Emit (OpCodes.Brfalse, is_null_label);
 
821
                        }
 
822
 
 
823
                        EmitOperator (ec, left.Type);
 
824
 
 
825
                        if (wrap_ctor != null)
 
826
                                ec.Emit (OpCodes.Newobj, wrap_ctor);
 
827
 
 
828
                        ec.Emit (OpCodes.Br_S, end_label);
 
829
                        ec.MarkLabel (is_null_label);
 
830
 
 
831
                        if ((Oper & Operator.ComparisonMask) != 0) {
 
832
                                ec.EmitInt (0);
 
833
                        } else {
 
834
                                LiftedNull.Create (type, loc).Emit (ec);
 
835
                        }
 
836
 
 
837
                        ec.MarkLabel (end_label);
 
838
                }
 
839
 
 
840
                protected override void EmitOperator (EmitContext ec, TypeSpec l)
 
841
                {
 
842
                        if (user_operator != null) {
 
843
                                user_operator.Emit (ec);
 
844
                                return;
 
845
                        }
 
846
 
 
847
                        if (left.Type.IsNullableType) {
 
848
                                l = NullableInfo.GetUnderlyingType (left.Type);
 
849
                                left = EmptyCast.Create (left, l);
 
850
                        }
 
851
 
 
852
                        if (right.Type.IsNullableType) {
 
853
                                right = EmptyCast.Create (right, NullableInfo.GetUnderlyingType (right.Type));
 
854
                        }
 
855
 
 
856
                        base.EmitOperator (ec, l);
 
857
                }
 
858
 
 
859
                Expression LiftResult (ResolveContext ec, Expression res_expr)
 
860
                {
 
861
                        TypeSpec lifted_type;
 
862
 
 
863
                        //
 
864
                        // Avoid double conversion
 
865
                        //
 
866
                        if (left_unwrap == null || IsLeftNullLifted || left_unwrap.Type != left.Type || (left_unwrap != null && IsRightNullLifted)) {
 
867
                                lifted_type = new NullableType (left.Type, loc).ResolveAsType (ec);
 
868
                                if (lifted_type == null)
 
869
                                        return null;
 
870
 
 
871
                                if (left is UserCast || left is EmptyCast || left is OpcodeCast)
 
872
                                        left.Type = lifted_type;
 
873
                                else
 
874
                                        left = EmptyCast.Create (left, lifted_type);
 
875
                        }
 
876
 
 
877
                        if (left != right && (right_unwrap == null || IsRightNullLifted || right_unwrap.Type != right.Type || (right_unwrap != null && IsLeftNullLifted))) {
 
878
                                lifted_type = new NullableType (right.Type, loc).ResolveAsType (ec);
 
879
                                if (lifted_type == null)
 
880
                                        return null;
 
881
 
 
882
                                var r = right;
 
883
                                if (r is ReducedExpression)
 
884
                                        r = ((ReducedExpression) r).OriginalExpression;
 
885
 
 
886
                                if (r is UserCast || r is EmptyCast || r is OpcodeCast)
 
887
                                        r.Type = lifted_type;
 
888
                                else
 
889
                                        right = EmptyCast.Create (right, lifted_type);
 
890
                        }
 
891
 
 
892
                        if ((Oper & Operator.ComparisonMask) == 0) {
 
893
                                lifted_type = new NullableType (res_expr.Type, loc).ResolveAsType (ec);
 
894
                                if (lifted_type == null)
 
895
                                        return null;
 
896
 
 
897
                                wrap_ctor = NullableInfo.GetConstructor (lifted_type);
 
898
                                type = res_expr.Type = lifted_type;
 
899
                        }
 
900
 
 
901
                        if (IsLeftNullLifted) {
 
902
                                left = LiftedNull.Create (right.Type, left.Location);
 
903
 
 
904
                                //
 
905
                                // Special case for bool?, the result depends on both null right side and left side value
 
906
                                //
 
907
                                if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type).BuiltinType == BuiltinTypeSpec.Type.Bool) {
 
908
                                        return res_expr;
 
909
                                }
 
910
 
 
911
                                if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
 
912
                                        return LiftedNull.CreateFromExpression (ec, res_expr);
 
913
 
 
914
                                //
 
915
                                // Value types and null comparison
 
916
                                //
 
917
                                if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0)
 
918
                                        return CreateNullConstant (ec, right_orig);
 
919
                        }
 
920
 
 
921
                        if (IsRightNullLifted) {
 
922
                                right = LiftedNull.Create (left.Type, right.Location);
 
923
 
 
924
                                //
 
925
                                // Special case for bool?, the result depends on both null right side and left side value
 
926
                                //
 
927
                                if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type).BuiltinType == BuiltinTypeSpec.Type.Bool) {
 
928
                                        return res_expr;
 
929
                                }
 
930
 
 
931
                                if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
 
932
                                        return LiftedNull.CreateFromExpression (ec, res_expr);
 
933
 
 
934
                                //
 
935
                                // Value types and null comparison
 
936
                                //
 
937
                                if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0)
 
938
                                        return CreateNullConstant (ec, left_orig);
 
939
                        }
 
940
 
 
941
                        return res_expr;
 
942
                }
 
943
 
 
944
                protected override Expression ResolveOperatorPredefined (ResolveContext ec, Binary.PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
 
945
                {
 
946
                        Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only, enum_type);
 
947
 
 
948
                        if (e == this || enum_type != null)
 
949
                                return LiftResult (ec, e);
 
950
 
 
951
                        //
 
952
                        // 7.9.9 Equality operators and null
 
953
                        //
 
954
                        // The == and != operators permit one operand to be a value of a nullable type and
 
955
                        // the other to be the null literal, even if no predefined or user-defined operator
 
956
                        // (in unlifted or lifted form) exists for the operation.
 
957
                        //
 
958
                        if (e == null && (Oper & Operator.EqualityMask) != 0) {
 
959
                                if ((IsLeftNullLifted && right_unwrap != null) || (IsRightNullLifted && left_unwrap != null))
 
960
                                        return LiftResult (ec, this);
 
961
                        }
 
962
 
 
963
                        return e;
 
964
                }
 
965
 
 
966
                protected override Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
 
967
                {
 
968
                        //
 
969
                        // Try original types first for exact match without unwrapping
 
970
                        //
 
971
                        Expression expr = base.ResolveUserOperator (ec, left_orig, right_orig);
 
972
                        if (expr != null)
 
973
                                return expr;
 
974
 
 
975
                        State orig_state = state;
 
976
 
 
977
                        //
 
978
                        // One side is a nullable type, try to match underlying types
 
979
                        //
 
980
                        if (left_unwrap != null || right_unwrap != null || (state & (State.RightNullLifted | State.LeftNullLifted)) != 0) {
 
981
                                expr = base.ResolveUserOperator (ec, left, right);
 
982
                        }
 
983
 
 
984
                        if (expr == null)
 
985
                                return null;
 
986
 
 
987
                        //
 
988
                        // Lift the result in the case it can be null and predefined or user operator
 
989
                        // result type is of a value type
 
990
                        //
 
991
                        if (!TypeSpec.IsValueType (expr.Type))
 
992
                                return null;
 
993
 
 
994
                        if (state != orig_state)
 
995
                                return expr;
 
996
 
 
997
                        expr = LiftResult (ec, expr);
 
998
                        if (expr is Constant)
 
999
                                return expr;
 
1000
 
 
1001
                        type = expr.Type;
 
1002
                        user_operator = expr;
 
1003
                        return this;
 
1004
                }
 
1005
        }
 
1006
 
 
1007
        public class NullCoalescingOperator : Expression
 
1008
        {
 
1009
                Expression left, right;
 
1010
                Unwrap unwrap;
 
1011
 
 
1012
                public NullCoalescingOperator (Expression left, Expression right)
 
1013
                {
 
1014
                        this.left = left;
 
1015
                        this.right = right;
 
1016
                        this.loc = left.Location;
 
1017
                }
 
1018
 
 
1019
                public Expression LeftExpression {
 
1020
                        get {
 
1021
                                return left;
 
1022
                        }
 
1023
                }
 
1024
 
 
1025
                public Expression RightExpression {
 
1026
                        get {
 
1027
                                return right;
 
1028
                        }
 
1029
                }
 
1030
                
 
1031
                public override Expression CreateExpressionTree (ResolveContext ec)
 
1032
                {
 
1033
                        if (left is NullLiteral)
 
1034
                                ec.Report.Error (845, loc, "An expression tree cannot contain a coalescing operator with null left side");
 
1035
 
 
1036
                        UserCast uc = left as UserCast;
 
1037
                        Expression conversion = null;
 
1038
                        if (uc != null) {
 
1039
                                left = uc.Source;
 
1040
 
 
1041
                                Arguments c_args = new Arguments (2);
 
1042
                                c_args.Add (new Argument (uc.CreateExpressionTree (ec)));
 
1043
                                c_args.Add (new Argument (left.CreateExpressionTree (ec)));
 
1044
                                conversion = CreateExpressionFactoryCall (ec, "Lambda", c_args);
 
1045
                        }
 
1046
 
 
1047
                        Arguments args = new Arguments (3);
 
1048
                        args.Add (new Argument (left.CreateExpressionTree (ec)));
 
1049
                        args.Add (new Argument (right.CreateExpressionTree (ec)));
 
1050
                        if (conversion != null)
 
1051
                                args.Add (new Argument (conversion));
 
1052
                        
 
1053
                        return CreateExpressionFactoryCall (ec, "Coalesce", args);
 
1054
                }
 
1055
 
 
1056
                Expression ConvertExpression (ResolveContext ec)
 
1057
                {
 
1058
                        // TODO: ImplicitConversionExists should take care of this
 
1059
                        if (left.eclass == ExprClass.MethodGroup)
 
1060
                                return null;
 
1061
 
 
1062
                        TypeSpec ltype = left.Type;
 
1063
 
 
1064
                        //
 
1065
                        // If left is a nullable type and an implicit conversion exists from right to underlying type of left,
 
1066
                        // the result is underlying type of left
 
1067
                        //
 
1068
                        if (ltype.IsNullableType) {
 
1069
                                unwrap = Unwrap.Create (left, false);
 
1070
                                if (unwrap == null)
 
1071
                                        return null;
 
1072
 
 
1073
                                //
 
1074
                                // Reduce (left ?? null) to left
 
1075
                                //
 
1076
                                if (right.IsNull)
 
1077
                                        return ReducedExpression.Create (left, this);
 
1078
 
 
1079
                                if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) {
 
1080
                                        left = unwrap;
 
1081
                                        ltype = left.Type;
 
1082
 
 
1083
                                        //
 
1084
                                        // If right is a dynamic expression, the result type is dynamic
 
1085
                                        //
 
1086
                                        if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 
1087
                                                type = right.Type;
 
1088
 
 
1089
                                                // Need to box underlying value type
 
1090
                                                left = Convert.ImplicitBoxingConversion (left, ltype, type);
 
1091
                                                return this;
 
1092
                                        }
 
1093
 
 
1094
                                        right = Convert.ImplicitConversion (ec, right, ltype, loc);
 
1095
                                        type = ltype;
 
1096
                                        return this;
 
1097
                                }
 
1098
                        } else if (TypeSpec.IsReferenceType (ltype)) {
 
1099
                                if (Convert.ImplicitConversionExists (ec, right, ltype)) {
 
1100
                                        //
 
1101
                                        // If right is a dynamic expression, the result type is dynamic
 
1102
                                        //
 
1103
                                        if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 
1104
                                                type = right.Type;
 
1105
                                                return this;
 
1106
                                        }
 
1107
 
 
1108
                                        //
 
1109
                                        // Reduce ("foo" ?? expr) to expression
 
1110
                                        //
 
1111
                                        Constant lc = left as Constant;
 
1112
                                        if (lc != null && !lc.IsDefaultValue)
 
1113
                                                return ReducedExpression.Create (lc, this);
 
1114
 
 
1115
                                        //
 
1116
                                        // Reduce (left ?? null) to left OR (null-constant ?? right) to right
 
1117
                                        //
 
1118
                                        if (right.IsNull || lc != null)
 
1119
                                                return ReducedExpression.Create (lc != null ? right : left, this);
 
1120
 
 
1121
                                        right = Convert.ImplicitConversion (ec, right, ltype, loc);
 
1122
                                        type = ltype;
 
1123
                                        return this;
 
1124
                                }
 
1125
 
 
1126
                                //
 
1127
                                // Special case null ?? null
 
1128
                                //
 
1129
                                if (ltype == right.Type) {
 
1130
                                        type = ltype;
 
1131
                                        return this;
 
1132
                                }
 
1133
                        } else {
 
1134
                                return null;
 
1135
                        }
 
1136
 
 
1137
                        TypeSpec rtype = right.Type;
 
1138
                        if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup)
 
1139
                                return null;
 
1140
 
 
1141
                        //
 
1142
                        // Reduce (null ?? right) to right
 
1143
                        //
 
1144
                        if (left.IsNull)
 
1145
                                return ReducedExpression.Create (right, this).Resolve (ec);
 
1146
 
 
1147
                        left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc);
 
1148
                        type = rtype;
 
1149
                        return this;
 
1150
                }
 
1151
 
 
1152
                public override bool ContainsEmitWithAwait ()
 
1153
                {
 
1154
                        if (unwrap != null)
 
1155
                                return unwrap.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
 
1156
 
 
1157
                        return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
 
1158
                }
 
1159
 
 
1160
                protected override Expression DoResolve (ResolveContext ec)
 
1161
                {
 
1162
                        left = left.Resolve (ec);
 
1163
                        right = right.Resolve (ec);
 
1164
 
 
1165
                        if (left == null || right == null)
 
1166
                                return null;
 
1167
 
 
1168
                        eclass = ExprClass.Value;
 
1169
 
 
1170
                        Expression e = ConvertExpression (ec);
 
1171
                        if (e == null) {
 
1172
                                Binary.Error_OperatorCannotBeApplied (ec, left, right, "??", loc);
 
1173
                                return null;
 
1174
                        }
 
1175
 
 
1176
                        return e;
 
1177
                }
 
1178
 
 
1179
                public override void Emit (EmitContext ec)
 
1180
                {
 
1181
                        Label end_label = ec.DefineLabel ();
 
1182
 
 
1183
                        if (unwrap != null) {
 
1184
                                Label is_null_label = ec.DefineLabel ();
 
1185
 
 
1186
                                unwrap.EmitCheck (ec);
 
1187
                                ec.Emit (OpCodes.Brfalse, is_null_label);
 
1188
 
 
1189
                                left.Emit (ec);
 
1190
                                ec.Emit (OpCodes.Br, end_label);
 
1191
 
 
1192
                                ec.MarkLabel (is_null_label);
 
1193
                                right.Emit (ec);
 
1194
 
 
1195
                                ec.MarkLabel (end_label);
 
1196
                                return;
 
1197
                        }
 
1198
 
 
1199
                        left.Emit (ec);
 
1200
                        ec.Emit (OpCodes.Dup);
 
1201
 
 
1202
                        // Only to make verifier happy
 
1203
                        if (left.Type.IsGenericParameter)
 
1204
                                ec.Emit (OpCodes.Box, left.Type);
 
1205
 
 
1206
                        ec.Emit (OpCodes.Brtrue, end_label);
 
1207
 
 
1208
                        ec.Emit (OpCodes.Pop);
 
1209
                        right.Emit (ec);
 
1210
 
 
1211
                        ec.MarkLabel (end_label);
 
1212
                }
 
1213
 
 
1214
                protected override void CloneTo (CloneContext clonectx, Expression t)
 
1215
                {
 
1216
                        NullCoalescingOperator target = (NullCoalescingOperator) t;
 
1217
 
 
1218
                        target.left = left.Clone (clonectx);
 
1219
                        target.right = right.Clone (clonectx);
 
1220
                }
 
1221
                
 
1222
                public override object Accept (StructuralVisitor visitor)
 
1223
                {
 
1224
                        return visitor.Visit (this);
 
1225
                }
 
1226
        }
 
1227
 
 
1228
        class LiftedUnaryMutator : UnaryMutator
 
1229
        {
 
1230
                public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
 
1231
                        : base (mode, expr, loc)
 
1232
                {
 
1233
                }
 
1234
 
 
1235
                protected override Expression DoResolve (ResolveContext ec)
 
1236
                {
 
1237
                        var orig_expr = expr;
 
1238
 
 
1239
                        expr = Unwrap.Create (expr);
 
1240
 
 
1241
                        var res = base.DoResolveOperation (ec);
 
1242
 
 
1243
                        expr = orig_expr;
 
1244
                        type = expr.Type;
 
1245
 
 
1246
                        return res;
 
1247
                }
 
1248
 
 
1249
                protected override void EmitOperation (EmitContext ec)
 
1250
                {
 
1251
                        Label is_null_label = ec.DefineLabel ();
 
1252
                        Label end_label = ec.DefineLabel ();
 
1253
 
 
1254
                        LocalTemporary lt = new LocalTemporary (type);
 
1255
 
 
1256
                        // Value is on the stack
 
1257
                        lt.Store (ec);
 
1258
 
 
1259
                        var call = new CallEmitter ();
 
1260
                        call.InstanceExpression = lt;
 
1261
                        call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
 
1262
 
 
1263
                        ec.Emit (OpCodes.Brfalse, is_null_label);
 
1264
 
 
1265
                        call = new CallEmitter ();
 
1266
                        call.InstanceExpression = lt;
 
1267
                        call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
 
1268
 
 
1269
                        lt.Release (ec);
 
1270
 
 
1271
                        base.EmitOperation (ec);
 
1272
 
 
1273
                        ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
 
1274
                        ec.Emit (OpCodes.Br_S, end_label);
 
1275
 
 
1276
                        ec.MarkLabel (is_null_label);
 
1277
                        LiftedNull.Create (type, loc).Emit (ec);
 
1278
 
 
1279
                        ec.MarkLabel (end_label);
 
1280
                }
 
1281
        }
 
1282
}
 
1283