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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.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
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
 
2
// 
 
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
 
4
// software and associated documentation files (the "Software"), to deal in the Software
 
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
 
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
 
7
// to whom the Software is furnished to do so, subject to the following conditions:
 
8
// 
 
9
// The above copyright notice and this permission notice shall be included in all copies or
 
10
// substantial portions of the Software.
 
11
// 
 
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
17
// DEALINGS IN THE SOFTWARE.
 
18
 
 
19
using System;
 
20
using System.Collections.Concurrent;
 
21
using System.Collections.Generic;
 
22
using System.Diagnostics;
 
23
using System.Globalization;
 
24
using System.Linq;
 
25
using System.Text;
 
26
using System.Threading;
 
27
using ICSharpCode.NRefactory.CSharp.TypeSystem;
 
28
using ICSharpCode.NRefactory.Semantics;
 
29
using ICSharpCode.NRefactory.TypeSystem;
 
30
using ICSharpCode.NRefactory.TypeSystem.Implementation;
 
31
using ICSharpCode.NRefactory.Utils;
 
32
 
 
33
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
34
{
 
35
        /// <summary>
 
36
        /// Contains the main resolver logic.
 
37
        /// </summary>
 
38
        /// <remarks>
 
39
        /// This class is thread-safe.
 
40
        /// </remarks>
 
41
        public class CSharpResolver
 
42
        {
 
43
                static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError;
 
44
                
 
45
                readonly ICompilation compilation;
 
46
                internal readonly CSharpConversions conversions;
 
47
                readonly CSharpTypeResolveContext context;
 
48
                readonly bool checkForOverflow;
 
49
                readonly bool isWithinLambdaExpression;
 
50
                
 
51
                #region Constructor
 
52
                public CSharpResolver(ICompilation compilation)
 
53
                {
 
54
                        if (compilation == null)
 
55
                                throw new ArgumentNullException("compilation");
 
56
                        this.compilation = compilation;
 
57
                        this.conversions = CSharpConversions.Get(compilation);
 
58
                        this.context = new CSharpTypeResolveContext(compilation.MainAssembly);
 
59
                        
 
60
                        var pc = compilation.MainAssembly.UnresolvedAssembly as CSharpProjectContent;
 
61
                        if (pc != null) {
 
62
                                this.checkForOverflow = pc.CompilerSettings.CheckForOverflow;
 
63
                        }
 
64
                }
 
65
                
 
66
                public CSharpResolver(CSharpTypeResolveContext context)
 
67
                {
 
68
                        if (context == null)
 
69
                                throw new ArgumentNullException("context");
 
70
                        this.compilation = context.Compilation;
 
71
                        this.conversions = CSharpConversions.Get(compilation);
 
72
                        this.context = context;
 
73
                        if (context.CurrentTypeDefinition != null)
 
74
                                currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition);
 
75
                }
 
76
                
 
77
                private CSharpResolver(ICompilation compilation, CSharpConversions conversions, CSharpTypeResolveContext context, bool checkForOverflow, bool isWithinLambdaExpression, TypeDefinitionCache currentTypeDefinitionCache, ImmutableStack<IVariable> localVariableStack, ObjectInitializerContext objectInitializerStack)
 
78
                {
 
79
                        this.compilation = compilation;
 
80
                        this.conversions = conversions;
 
81
                        this.context = context;
 
82
                        this.checkForOverflow = checkForOverflow;
 
83
                        this.isWithinLambdaExpression = isWithinLambdaExpression;
 
84
                        this.currentTypeDefinitionCache = currentTypeDefinitionCache;
 
85
                        this.localVariableStack = localVariableStack;
 
86
                        this.objectInitializerStack = objectInitializerStack;
 
87
                }
 
88
                #endregion
 
89
                
 
90
                #region Properties
 
91
                /// <summary>
 
92
                /// Gets the compilation used by the resolver.
 
93
                /// </summary>
 
94
                public ICompilation Compilation {
 
95
                        get { return compilation; }
 
96
                }
 
97
                
 
98
                /// <summary>
 
99
                /// Gets the current type resolve context.
 
100
                /// </summary>
 
101
                public CSharpTypeResolveContext CurrentTypeResolveContext {
 
102
                        get { return context; }
 
103
                }
 
104
                
 
105
                CSharpResolver WithContext(CSharpTypeResolveContext newContext)
 
106
                {
 
107
                        return new CSharpResolver(compilation, conversions, newContext, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack);
 
108
                }
 
109
                
 
110
                /// <summary>
 
111
                /// Gets whether the current context is <c>checked</c>.
 
112
                /// </summary>
 
113
                public bool CheckForOverflow {
 
114
                        get { return checkForOverflow; }
 
115
                }
 
116
                
 
117
                /// <summary>
 
118
                /// Sets whether the current context is <c>checked</c>.
 
119
                /// </summary>
 
120
                public CSharpResolver WithCheckForOverflow(bool checkForOverflow)
 
121
                {
 
122
                        if (checkForOverflow == this.checkForOverflow)
 
123
                                return this;
 
124
                        return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack);
 
125
                }
 
126
                
 
127
                /// <summary>
 
128
                /// Gets whether the resolver is currently within a lambda expression.
 
129
                /// </summary>
 
130
                public bool IsWithinLambdaExpression {
 
131
                        get { return isWithinLambdaExpression; }
 
132
                }
 
133
                
 
134
                /// <summary>
 
135
                /// Sets whether the resolver is currently within a lambda expression.
 
136
                /// </summary>
 
137
                public CSharpResolver WithIsWithinLambdaExpression(bool isWithinLambdaExpression)
 
138
                {
 
139
                        return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack);
 
140
                }
 
141
                
 
142
                /// <summary>
 
143
                /// Gets the current member definition that is used to look up identifiers as parameters
 
144
                /// or type parameters.
 
145
                /// </summary>
 
146
                public IMember CurrentMember {
 
147
                        get { return context.CurrentMember; }
 
148
                }
 
149
                
 
150
                /// <summary>
 
151
                /// Sets the current member definition.
 
152
                /// </summary>
 
153
                /// <remarks>Don't forget to also set CurrentTypeDefinition when setting CurrentMember;
 
154
                /// setting one of the properties does not automatically set the other.</remarks>
 
155
                public CSharpResolver WithCurrentMember(IMember member)
 
156
                {
 
157
                        return WithContext(context.WithCurrentMember(member));
 
158
                }
 
159
                
 
160
                /// <summary>
 
161
                /// Gets the current using scope that is used to look up identifiers as class names.
 
162
                /// </summary>
 
163
                public ResolvedUsingScope CurrentUsingScope {
 
164
                        get { return context.CurrentUsingScope; }
 
165
                }
 
166
                
 
167
                /// <summary>
 
168
                /// Sets the current using scope that is used to look up identifiers as class names.
 
169
                /// </summary>
 
170
                public CSharpResolver WithCurrentUsingScope(ResolvedUsingScope usingScope)
 
171
                {
 
172
                        return WithContext(context.WithUsingScope(usingScope));
 
173
                }
 
174
                #endregion
 
175
                
 
176
                #region Per-CurrentTypeDefinition Cache
 
177
                readonly TypeDefinitionCache currentTypeDefinitionCache;
 
178
                
 
179
                /// <summary>
 
180
                /// Gets the current type definition.
 
181
                /// </summary>
 
182
                public ITypeDefinition CurrentTypeDefinition {
 
183
                        get { return context.CurrentTypeDefinition; }
 
184
                }
 
185
                
 
186
                /// <summary>
 
187
                /// Sets the current type definition.
 
188
                /// </summary>
 
189
                public CSharpResolver WithCurrentTypeDefinition(ITypeDefinition typeDefinition)
 
190
                {
 
191
                        if (this.CurrentTypeDefinition == typeDefinition)
 
192
                                return this;
 
193
                        
 
194
                        TypeDefinitionCache newTypeDefinitionCache;
 
195
                        if (typeDefinition != null)
 
196
                                newTypeDefinitionCache = new TypeDefinitionCache(typeDefinition);
 
197
                        else
 
198
                                newTypeDefinitionCache = null;
 
199
                        
 
200
                        return new CSharpResolver(compilation, conversions, context.WithCurrentTypeDefinition(typeDefinition),
 
201
                                                  checkForOverflow, isWithinLambdaExpression, newTypeDefinitionCache, localVariableStack, objectInitializerStack);
 
202
                }
 
203
                
 
204
                sealed class TypeDefinitionCache
 
205
                {
 
206
                        public readonly ITypeDefinition TypeDefinition;
 
207
                        public readonly Dictionary<string, ResolveResult> SimpleNameLookupCacheExpression = new Dictionary<string, ResolveResult>();
 
208
                        public readonly Dictionary<string, ResolveResult> SimpleNameLookupCacheInvocationTarget = new Dictionary<string, ResolveResult>();
 
209
                        public readonly Dictionary<string, ResolveResult> SimpleTypeLookupCache = new Dictionary<string, ResolveResult>();
 
210
                        
 
211
                        public TypeDefinitionCache(ITypeDefinition typeDefinition)
 
212
                        {
 
213
                                this.TypeDefinition = typeDefinition;
 
214
                        }
 
215
                }
 
216
                #endregion
 
217
                
 
218
                #region Local Variable Management
 
219
                
 
220
                // We store the local variables in an immutable stack.
 
221
                // The beginning of a block is marked by a null entry.
 
222
                
 
223
                // This data structure is used to allow efficient cloning of the resolver with its local variable context.
 
224
                readonly ImmutableStack<IVariable> localVariableStack = ImmutableStack<IVariable>.Empty;
 
225
                
 
226
                CSharpResolver WithLocalVariableStack(ImmutableStack<IVariable> stack)
 
227
                {
 
228
                        return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, stack, objectInitializerStack);
 
229
                }
 
230
                
 
231
                /// <summary>
 
232
                /// Opens a new scope for local variables.
 
233
                /// </summary>
 
234
                public CSharpResolver PushBlock()
 
235
                {
 
236
                        return WithLocalVariableStack(localVariableStack.Push(null));
 
237
                }
 
238
                
 
239
                /// <summary>
 
240
                /// Closes the current scope for local variables; removing all variables in that scope.
 
241
                /// </summary>
 
242
                public CSharpResolver PopBlock()
 
243
                {
 
244
                        var stack = localVariableStack;
 
245
                        IVariable removedVar;
 
246
                        do {
 
247
                                removedVar = stack.Peek();
 
248
                                stack = stack.Pop();
 
249
                        } while (removedVar != null);
 
250
                        return WithLocalVariableStack(stack);
 
251
                }
 
252
                
 
253
                /// <summary>
 
254
                /// Adds a new variable or lambda parameter to the current block.
 
255
                /// </summary>
 
256
                public CSharpResolver AddVariable(IVariable variable)
 
257
                {
 
258
                        if (variable == null)
 
259
                                throw new ArgumentNullException("variable");
 
260
                        return WithLocalVariableStack(localVariableStack.Push(variable));
 
261
                }
 
262
                
 
263
                /// <summary>
 
264
                /// Removes the variable that was just added.
 
265
                /// </summary>
 
266
                public CSharpResolver PopLastVariable()
 
267
                {
 
268
                        if (localVariableStack.Peek() == null)
 
269
                                throw new InvalidOperationException("There is no variable within the current block.");
 
270
                        return WithLocalVariableStack(localVariableStack.Pop());
 
271
                }
 
272
                
 
273
                /// <summary>
 
274
                /// Gets all currently visible local variables and lambda parameters.
 
275
                /// </summary>
 
276
                public IEnumerable<IVariable> LocalVariables {
 
277
                        get {
 
278
                                return localVariableStack.Where(v => v != null);
 
279
                        }
 
280
                }
 
281
                #endregion
 
282
                
 
283
                #region Object Initializer Context
 
284
                sealed class ObjectInitializerContext
 
285
                {
 
286
                        internal readonly ResolveResult initializedObject;
 
287
                        internal readonly ObjectInitializerContext prev;
 
288
                        
 
289
                        public ObjectInitializerContext(ResolveResult initializedObject, CSharpResolver.ObjectInitializerContext prev)
 
290
                        {
 
291
                                this.initializedObject = initializedObject;
 
292
                                this.prev = prev;
 
293
                        }
 
294
                }
 
295
                
 
296
                readonly ObjectInitializerContext objectInitializerStack;
 
297
                
 
298
                CSharpResolver WithObjectInitializerStack(ObjectInitializerContext stack)
 
299
                {
 
300
                        return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, stack);
 
301
                }
 
302
                
 
303
                /// <summary>
 
304
                /// Pushes the type of the object that is currently being initialized.
 
305
                /// </summary>
 
306
                public CSharpResolver PushObjectInitializer(ResolveResult initializedObject)
 
307
                {
 
308
                        if (initializedObject == null)
 
309
                                throw new ArgumentNullException("initializedObject");
 
310
                        return WithObjectInitializerStack(new ObjectInitializerContext(initializedObject, objectInitializerStack));
 
311
                }
 
312
                
 
313
                public CSharpResolver PopObjectInitializer()
 
314
                {
 
315
                        if (objectInitializerStack == null)
 
316
                                throw new InvalidOperationException();
 
317
                        return WithObjectInitializerStack(objectInitializerStack.prev);
 
318
                }
 
319
                
 
320
                /// <summary>
 
321
                /// Gets whether this context is within an object initializer.
 
322
                /// </summary>
 
323
                public bool IsInObjectInitializer {
 
324
                        get { return objectInitializerStack != null; }
 
325
                }
 
326
                
 
327
                /// <summary>
 
328
                /// Gets the current object initializer. This usually is an <see cref="InitializedObjectResolveResult"/>
 
329
                /// or (for nested initializers) a semantic tree based on an <see cref="InitializedObjectResolveResult"/>.
 
330
                /// Returns ErrorResolveResult if there is no object initializer.
 
331
                /// </summary>
 
332
                public ResolveResult CurrentObjectInitializer {
 
333
                        get {
 
334
                                return objectInitializerStack != null ? objectInitializerStack.initializedObject : ErrorResult;
 
335
                        }
 
336
                }
 
337
                
 
338
                /// <summary>
 
339
                /// Gets the type of the object currently being initialized.
 
340
                /// Returns SharedTypes.Unknown if no object initializer is currently open (or if the object initializer
 
341
                /// has unknown type).
 
342
                /// </summary>
 
343
                public IType CurrentObjectInitializerType {
 
344
                        get { return CurrentObjectInitializer.Type; }
 
345
                }
 
346
                #endregion
 
347
                
 
348
                #region Clone
 
349
                /// <summary>
 
350
                /// Creates a copy of this CSharp resolver.
 
351
                /// </summary>
 
352
                [Obsolete("CSharpResolver is immutable, cloning is no longer necessary")]
 
353
                public CSharpResolver Clone()
 
354
                {
 
355
                        return this;
 
356
                }
 
357
                #endregion
 
358
                
 
359
                #region ResolveUnaryOperator
 
360
                #region ResolveUnaryOperator method
 
361
                public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
 
362
                {
 
363
                        if (expression.Type.Kind == TypeKind.Dynamic) {
 
364
                                if (op == UnaryOperatorType.Await) {
 
365
                                        return new AwaitResolveResult(SpecialType.Dynamic, new DynamicInvocationResolveResult(new DynamicMemberResolveResult(expression, "GetAwaiter"), DynamicInvocationType.Invocation, EmptyList<ResolveResult>.Instance), SpecialType.Dynamic, null, null, null);
 
366
                                }
 
367
                                else {
 
368
                                        return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);
 
369
                                }
 
370
                        }
 
371
                        
 
372
                        // C# 4.0 spec: Ā§7.3.3 Unary operator overload resolution
 
373
                        string overloadableOperatorName = GetOverloadableOperatorName(op);
 
374
                        if (overloadableOperatorName == null) {
 
375
                                switch (op) {
 
376
                                        case UnaryOperatorType.Dereference:
 
377
                                                PointerType p = expression.Type as PointerType;
 
378
                                                if (p != null)
 
379
                                                        return UnaryOperatorResolveResult(p.ElementType, op, expression);
 
380
                                                else
 
381
                                                        return ErrorResult;
 
382
                                        case UnaryOperatorType.AddressOf:
 
383
                                                return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
 
384
                                        case UnaryOperatorType.Await: {
 
385
                                                ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
 
386
                                                ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0], argumentNames: null, allowOptionalParameters: false);
 
387
 
 
388
                                                var lookup = CreateMemberLookup();
 
389
                                                IMethod getResultMethod;
 
390
                                                IType awaitResultType;
 
391
                                                var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
 
392
                                                if (getResultMethodGroup != null) {
 
393
                                                        var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
 
394
                                                        getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null;
 
395
                                                        awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType;
 
396
                                                }
 
397
                                                else {
 
398
                                                        getResultMethod = null;
 
399
                                                        awaitResultType = SpecialType.UnknownType;
 
400
                                                }
 
401
 
 
402
                                                var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false);
 
403
                                                var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null);
 
404
                                                if (isCompletedProperty != null && (!isCompletedProperty.ReturnType.IsKnownType(KnownTypeCode.Boolean) || !isCompletedProperty.CanGet))
 
405
                                                        isCompletedProperty = null;
 
406
 
 
407
                                                var interfaceOnCompleted = compilation.FindType(KnownTypeCode.INotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "OnCompleted");
 
408
                                                var interfaceUnsafeOnCompleted = compilation.FindType(KnownTypeCode.ICriticalNotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "UnsafeOnCompleted");
 
409
 
 
410
                                                IMethod onCompletedMethod = null;
 
411
                                                var candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceUnsafeOnCompleted)).ToList();
 
412
                                                if (candidates.Count == 0) {
 
413
                                                        candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceOnCompleted)).ToList();
 
414
                                                        if (candidates.Count == 1)
 
415
                                                                onCompletedMethod = candidates[0];
 
416
                                                }
 
417
                                                else if (candidates.Count == 1) {
 
418
                                                        onCompletedMethod = candidates[0];
 
419
                                                }
 
420
 
 
421
                                                return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod);
 
422
                                        }
 
423
 
 
424
                                        default:
 
425
                                                throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
 
426
                                }
 
427
                        }
 
428
                        // If the type is nullable, get the underlying type:
 
429
                        IType type = NullableType.GetUnderlyingType(expression.Type);
 
430
                        bool isNullable = NullableType.IsNullable(expression.Type);
 
431
                        
 
432
                        // the operator is overloadable:
 
433
                        OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { expression });
 
434
                        foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) {
 
435
                                userDefinedOperatorOR.AddCandidate(candidate);
 
436
                        }
 
437
                        if (userDefinedOperatorOR.FoundApplicableCandidate) {
 
438
                                return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
 
439
                        }
 
440
                        
 
441
                        expression = UnaryNumericPromotion(op, ref type, isNullable, expression);
 
442
                        CSharpOperators.OperatorMethod[] methodGroup;
 
443
                        CSharpOperators operators = CSharpOperators.Get(compilation);
 
444
                        switch (op) {
 
445
                                case UnaryOperatorType.Increment:
 
446
                                case UnaryOperatorType.Decrement:
 
447
                                case UnaryOperatorType.PostIncrement:
 
448
                                case UnaryOperatorType.PostDecrement:
 
449
                                        // C# 4.0 spec: Ā§7.6.9 Postfix increment and decrement operators
 
450
                                        // C# 4.0 spec: Ā§7.7.5 Prefix increment and decrement operators
 
451
                                        TypeCode code = ReflectionHelper.GetTypeCode(type);
 
452
                                        if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
 
453
                                                return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
 
454
                                        else
 
455
                                                return new ErrorResolveResult(expression.Type);
 
456
                                case UnaryOperatorType.Plus:
 
457
                                        methodGroup = operators.UnaryPlusOperators;
 
458
                                        break;
 
459
                                case UnaryOperatorType.Minus:
 
460
                                        methodGroup = CheckForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators;
 
461
                                        break;
 
462
                                case UnaryOperatorType.Not:
 
463
                                        methodGroup = operators.LogicalNegationOperators;
 
464
                                        break;
 
465
                                case UnaryOperatorType.BitNot:
 
466
                                        if (type.Kind == TypeKind.Enum) {
 
467
                                                if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) {
 
468
                                                        // evaluate as (E)(~(U)x);
 
469
                                                        var U = compilation.FindType(expression.ConstantValue.GetType());
 
470
                                                        var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
 
471
                                                        return CheckErrorAndResolveUncheckedCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
 
472
                                                } else {
 
473
                                                        return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
 
474
                                                }
 
475
                                        } else {
 
476
                                                methodGroup = operators.BitwiseComplementOperators;
 
477
                                                break;
 
478
                                        }
 
479
                                default:
 
480
                                        throw new InvalidOperationException();
 
481
                        }
 
482
                        OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { expression });
 
483
                        foreach (var candidate in methodGroup) {
 
484
                                builtinOperatorOR.AddCandidate(candidate);
 
485
                        }
 
486
                        CSharpOperators.UnaryOperatorMethod m = (CSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate;
 
487
                        IType resultType = m.ReturnType;
 
488
                        if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) {
 
489
                                if (userDefinedOperatorOR.BestCandidate != null) {
 
490
                                        // If there are any user-defined operators, prefer those over the built-in operators.
 
491
                                        // It'll be a more informative error.
 
492
                                        return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
 
493
                                } else if (builtinOperatorOR.BestCandidateAmbiguousWith != null) {
 
494
                                        // If the best candidate is ambiguous, just use the input type instead
 
495
                                        // of picking one of the ambiguous overloads.
 
496
                                        return new ErrorResolveResult(expression.Type);
 
497
                                } else {
 
498
                                        return new ErrorResolveResult(resultType);
 
499
                                }
 
500
                        } else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
 
501
                                object val;
 
502
                                try {
 
503
                                        val = m.Invoke(this, expression.ConstantValue);
 
504
                                } catch (ArithmeticException) {
 
505
                                        return new ErrorResolveResult(resultType);
 
506
                                }
 
507
                                return new ConstantResolveResult(resultType, val);
 
508
                        } else {
 
509
                                expression = Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
 
510
                                return UnaryOperatorResolveResult(resultType, op, expression,
 
511
                                                                  builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator);
 
512
                        }
 
513
                }
 
514
                
 
515
                OperatorResolveResult UnaryOperatorResolveResult(IType resultType, UnaryOperatorType op, ResolveResult expression, bool isLifted = false)
 
516
                {
 
517
                        return new OperatorResolveResult(
 
518
                                resultType, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow),
 
519
                                null, isLifted, new[] { expression });
 
520
                }
 
521
                #endregion
 
522
                
 
523
                #region UnaryNumericPromotion
 
524
                ResolveResult UnaryNumericPromotion(UnaryOperatorType op, ref IType type, bool isNullable, ResolveResult expression)
 
525
                {
 
526
                        // C# 4.0 spec: Ā§7.3.6.1
 
527
                        TypeCode code = ReflectionHelper.GetTypeCode(type);
 
528
                        if (isNullable && type.Kind == TypeKind.Null)
 
529
                                code = TypeCode.SByte; // cause promotion of null to int32
 
530
                        switch (op) {
 
531
                                case UnaryOperatorType.Minus:
 
532
                                        if (code == TypeCode.UInt32) {
 
533
                                                type = compilation.FindType(KnownTypeCode.Int64);
 
534
                                                return Convert(expression, MakeNullable(type, isNullable),
 
535
                                                               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
 
536
                                        }
 
537
                                        goto case UnaryOperatorType.Plus;
 
538
                                case UnaryOperatorType.Plus:
 
539
                                case UnaryOperatorType.BitNot:
 
540
                                        if (code >= TypeCode.Char && code <= TypeCode.UInt16) {
 
541
                                                type = compilation.FindType(KnownTypeCode.Int32);
 
542
                                                return Convert(expression, MakeNullable(type, isNullable),
 
543
                                                               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
 
544
                                        }
 
545
                                        break;
 
546
                        }
 
547
                        return expression;
 
548
                }
 
549
                #endregion
 
550
                
 
551
                #region GetOverloadableOperatorName
 
552
                static string GetOverloadableOperatorName(UnaryOperatorType op)
 
553
                {
 
554
                        switch (op) {
 
555
                                case UnaryOperatorType.Not:
 
556
                                        return "op_LogicalNot";
 
557
                                case UnaryOperatorType.BitNot:
 
558
                                        return "op_OnesComplement";
 
559
                                case UnaryOperatorType.Minus:
 
560
                                        return "op_UnaryNegation";
 
561
                                case UnaryOperatorType.Plus:
 
562
                                        return "op_UnaryPlus";
 
563
                                case UnaryOperatorType.Increment:
 
564
                                case UnaryOperatorType.PostIncrement:
 
565
                                        return "op_Increment";
 
566
                                case UnaryOperatorType.Decrement:
 
567
                                case UnaryOperatorType.PostDecrement:
 
568
                                        return "op_Decrement";
 
569
                                default:
 
570
                                        return null;
 
571
                        }
 
572
                }
 
573
                #endregion
 
574
                #endregion
 
575
                
 
576
                #region ResolveBinaryOperator
 
577
                #region ResolveBinaryOperator method
 
578
                public ResolveResult ResolveBinaryOperator(BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
 
579
                {
 
580
                        if (lhs.Type.Kind == TypeKind.Dynamic || rhs.Type.Kind == TypeKind.Dynamic) {
 
581
                                lhs = Convert(lhs, SpecialType.Dynamic);
 
582
                                rhs = Convert(rhs, SpecialType.Dynamic);
 
583
                                return BinaryOperatorResolveResult(SpecialType.Dynamic, lhs, op, rhs);
 
584
                        }
 
585
                        
 
586
                        // C# 4.0 spec: Ā§7.3.4 Binary operator overload resolution
 
587
                        string overloadableOperatorName = GetOverloadableOperatorName(op);
 
588
                        if (overloadableOperatorName == null) {
 
589
                                
 
590
                                // Handle logical and/or exactly as bitwise and/or:
 
591
                                // - If the user overloads a bitwise operator, that implicitly creates the corresponding logical operator.
 
592
                                // - If both inputs are compile-time constants, it doesn't matter that we don't short-circuit.
 
593
                                // - If inputs aren't compile-time constants, we don't evaluate anything, so again it doesn't matter that we don't short-circuit
 
594
                                if (op == BinaryOperatorType.ConditionalAnd) {
 
595
                                        overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseAnd);
 
596
                                } else if (op == BinaryOperatorType.ConditionalOr) {
 
597
                                        overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseOr);
 
598
                                } else if (op == BinaryOperatorType.NullCoalescing) {
 
599
                                        // null coalescing operator is not overloadable and needs to be handled separately
 
600
                                        return ResolveNullCoalescingOperator(lhs, rhs);
 
601
                                } else {
 
602
                                        throw new ArgumentException("Invalid value for BinaryOperatorType", "op");
 
603
                                }
 
604
                        }
 
605
                        
 
606
                        // If the type is nullable, get the underlying type:
 
607
                        bool isNullable = NullableType.IsNullable(lhs.Type) || NullableType.IsNullable(rhs.Type);
 
608
                        IType lhsType = NullableType.GetUnderlyingType(lhs.Type);
 
609
                        IType rhsType = NullableType.GetUnderlyingType(rhs.Type);
 
610
                        
 
611
                        // the operator is overloadable:
 
612
                        OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { lhs, rhs });
 
613
                        HashSet<IParameterizedMember> userOperatorCandidates = new HashSet<IParameterizedMember>();
 
614
                        userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName));
 
615
                        userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName));
 
616
                        foreach (var candidate in userOperatorCandidates) {
 
617
                                userDefinedOperatorOR.AddCandidate(candidate);
 
618
                        }
 
619
                        if (userDefinedOperatorOR.FoundApplicableCandidate) {
 
620
                                return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
 
621
                        }
 
622
                        
 
623
                        if (lhsType.Kind == TypeKind.Null && rhsType.IsReferenceType == false
 
624
                            || lhsType.IsReferenceType == false && rhsType.Kind == TypeKind.Null)
 
625
                        {
 
626
                                isNullable = true;
 
627
                        }
 
628
                        if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight) {
 
629
                                // special case: the shift operators allow "var x = null << null", producing int?.
 
630
                                if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
 
631
                                        isNullable = true;
 
632
                                // for shift operators, do unary promotion independently on both arguments
 
633
                                lhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref lhsType, isNullable, lhs);
 
634
                                rhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref rhsType, isNullable, rhs);
 
635
                        } else {
 
636
                                bool allowNullableConstants = op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality;
 
637
                                if (!BinaryNumericPromotion(isNullable, ref lhs, ref rhs, allowNullableConstants))
 
638
                                        return new ErrorResolveResult(lhs.Type);
 
639
                        }
 
640
                        // re-read underlying types after numeric promotion
 
641
                        lhsType = NullableType.GetUnderlyingType(lhs.Type);
 
642
                        rhsType = NullableType.GetUnderlyingType(rhs.Type);
 
643
                        
 
644
                        IEnumerable<CSharpOperators.OperatorMethod> methodGroup;
 
645
                        CSharpOperators operators = CSharpOperators.Get(compilation);
 
646
                        switch (op) {
 
647
                                case BinaryOperatorType.Multiply:
 
648
                                        methodGroup = operators.MultiplicationOperators;
 
649
                                        break;
 
650
                                case BinaryOperatorType.Divide:
 
651
                                        methodGroup = operators.DivisionOperators;
 
652
                                        break;
 
653
                                case BinaryOperatorType.Modulus:
 
654
                                        methodGroup = operators.RemainderOperators;
 
655
                                        break;
 
656
                                case BinaryOperatorType.Add:
 
657
                                        methodGroup = operators.AdditionOperators;
 
658
                                        {
 
659
                                                if (lhsType.Kind == TypeKind.Enum) {
 
660
                                                        // E operator +(E x, U y);
 
661
                                                        IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable);
 
662
                                                        if (TryConvert(ref rhs, underlyingType)) {
 
663
                                                                return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
 
664
                                                        }
 
665
                                                }
 
666
                                                if (rhsType.Kind == TypeKind.Enum) {
 
667
                                                        // E operator +(U x, E y);
 
668
                                                        IType underlyingType = MakeNullable(GetEnumUnderlyingType(rhsType), isNullable);
 
669
                                                        if (TryConvert(ref lhs, underlyingType)) {
 
670
                                                                return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs);
 
671
                                                        }
 
672
                                                }
 
673
                                                
 
674
                                                if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) {
 
675
                                                        return BinaryOperatorResolveResult(lhsType, lhs, op, rhs);
 
676
                                                } else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) {
 
677
                                                        return BinaryOperatorResolveResult(rhsType, lhs, op, rhs);
 
678
                                                }
 
679
                                                
 
680
                                                if (lhsType is PointerType) {
 
681
                                                        methodGroup = new [] {
 
682
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int32),
 
683
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt32),
 
684
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int64),
 
685
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt64)
 
686
                                                        };
 
687
                                                } else if (rhsType is PointerType) {
 
688
                                                        methodGroup = new [] {
 
689
                                                                PointerArithmeticOperator(rhsType, KnownTypeCode.Int32, rhsType),
 
690
                                                                PointerArithmeticOperator(rhsType, KnownTypeCode.UInt32, rhsType),
 
691
                                                                PointerArithmeticOperator(rhsType, KnownTypeCode.Int64, rhsType),
 
692
                                                                PointerArithmeticOperator(rhsType, KnownTypeCode.UInt64, rhsType)
 
693
                                                        };
 
694
                                                }
 
695
                                                if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
 
696
                                                        return new ErrorResolveResult(SpecialType.NullType);
 
697
                                        }
 
698
                                        break;
 
699
                                case BinaryOperatorType.Subtract:
 
700
                                        methodGroup = operators.SubtractionOperators;
 
701
                                        {
 
702
                                                if (lhsType.Kind == TypeKind.Enum) {
 
703
                                                        // E operator ā€“(E x, U y);
 
704
                                                        IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable);
 
705
                                                        if (TryConvert(ref rhs, underlyingType)) {
 
706
                                                                return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
 
707
                                                        }
 
708
                                                        // U operator ā€“(E x, E y);
 
709
                                                        if (TryConvert(ref rhs, lhs.Type)) {
 
710
                                                                return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs);
 
711
                                                        }
 
712
                                                }
 
713
                                                if (rhsType.Kind == TypeKind.Enum) {
 
714
                                                        // U operator ā€“(E x, E y);
 
715
                                                        if (TryConvert(ref lhs, rhs.Type)) {
 
716
                                                                return HandleEnumSubtraction(isNullable, rhsType, lhs, rhs);
 
717
                                                        }
 
718
                                                }
 
719
                                                
 
720
                                                if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) {
 
721
                                                        return BinaryOperatorResolveResult(lhsType, lhs, op, rhs);
 
722
                                                } else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) {
 
723
                                                        return BinaryOperatorResolveResult(rhsType, lhs, op, rhs);
 
724
                                                }
 
725
                                                
 
726
                                                if (lhsType is PointerType) {
 
727
                                                        if (rhsType is PointerType) {
 
728
                                                                IType int64 = compilation.FindType(KnownTypeCode.Int64);
 
729
                                                                if (lhsType.Equals(rhsType)) {
 
730
                                                                        return BinaryOperatorResolveResult(int64, lhs, op, rhs);
 
731
                                                                } else {
 
732
                                                                        return new ErrorResolveResult(int64);
 
733
                                                                }
 
734
                                                        }
 
735
                                                        methodGroup = new [] {
 
736
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int32),
 
737
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt32),
 
738
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int64),
 
739
                                                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt64)
 
740
                                                        };
 
741
                                                }
 
742
                                                
 
743
                                                if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
 
744
                                                        return new ErrorResolveResult(SpecialType.NullType);
 
745
                                        }
 
746
                                        break;
 
747
                                case BinaryOperatorType.ShiftLeft:
 
748
                                        methodGroup = operators.ShiftLeftOperators;
 
749
                                        break;
 
750
                                case BinaryOperatorType.ShiftRight:
 
751
                                        methodGroup = operators.ShiftRightOperators;
 
752
                                        break;
 
753
                                case BinaryOperatorType.Equality:
 
754
                                case BinaryOperatorType.InEquality:
 
755
                                case BinaryOperatorType.LessThan:
 
756
                                case BinaryOperatorType.GreaterThan:
 
757
                                case BinaryOperatorType.LessThanOrEqual:
 
758
                                case BinaryOperatorType.GreaterThanOrEqual:
 
759
                                        {
 
760
                                                if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) {
 
761
                                                        // bool operator op(E x, E y);
 
762
                                                        return HandleEnumComparison(op, lhsType, isNullable, lhs, rhs);
 
763
                                                } else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
 
764
                                                        // bool operator op(E x, E y);
 
765
                                                        return HandleEnumComparison(op, rhsType, isNullable, lhs, rhs);
 
766
                                                } else if (lhsType is PointerType && rhsType is PointerType) {
 
767
                                                        return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
 
768
                                                }
 
769
                                                if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality) {
 
770
                                                        if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true) {
 
771
                                                                // If it's a reference comparison
 
772
                                                                if (op == BinaryOperatorType.Equality)
 
773
                                                                        methodGroup = operators.ReferenceEqualityOperators;
 
774
                                                                else
 
775
                                                                        methodGroup = operators.ReferenceInequalityOperators;
 
776
                                                                break;
 
777
                                                        } else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type)
 
778
                                                                   || IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null) {
 
779
                                                                // compare type parameter or nullable type with the null literal
 
780
                                                                return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
 
781
                                                        }
 
782
                                                }
 
783
                                                switch (op) {
 
784
                                                        case BinaryOperatorType.Equality:
 
785
                                                                methodGroup = operators.ValueEqualityOperators;
 
786
                                                                break;
 
787
                                                        case BinaryOperatorType.InEquality:
 
788
                                                                methodGroup = operators.ValueInequalityOperators;
 
789
                                                                break;
 
790
                                                        case BinaryOperatorType.LessThan:
 
791
                                                                methodGroup = operators.LessThanOperators;
 
792
                                                                break;
 
793
                                                        case BinaryOperatorType.GreaterThan:
 
794
                                                                methodGroup = operators.GreaterThanOperators;
 
795
                                                                break;
 
796
                                                        case BinaryOperatorType.LessThanOrEqual:
 
797
                                                                methodGroup = operators.LessThanOrEqualOperators;
 
798
                                                                break;
 
799
                                                        case BinaryOperatorType.GreaterThanOrEqual:
 
800
                                                                methodGroup = operators.GreaterThanOrEqualOperators;
 
801
                                                                break;
 
802
                                                        default:
 
803
                                                                throw new InvalidOperationException();
 
804
                                                }
 
805
                                        }
 
806
                                        break;
 
807
                                case BinaryOperatorType.BitwiseAnd:
 
808
                                case BinaryOperatorType.BitwiseOr:
 
809
                                case BinaryOperatorType.ExclusiveOr:
 
810
                                        {
 
811
                                                if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) {
 
812
                                                        // bool operator op(E x, E y);
 
813
                                                        return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
 
814
                                                } else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
 
815
                                                        // bool operator op(E x, E y);
 
816
                                                        return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs);
 
817
                                                }
 
818
                                                
 
819
                                                switch (op) {
 
820
                                                        case BinaryOperatorType.BitwiseAnd:
 
821
                                                                methodGroup = operators.BitwiseAndOperators;
 
822
                                                                break;
 
823
                                                        case BinaryOperatorType.BitwiseOr:
 
824
                                                                methodGroup = operators.BitwiseOrOperators;
 
825
                                                                break;
 
826
                                                        case BinaryOperatorType.ExclusiveOr:
 
827
                                                                methodGroup = operators.BitwiseXorOperators;
 
828
                                                                break;
 
829
                                                        default:
 
830
                                                                throw new InvalidOperationException();
 
831
                                                }
 
832
                                        }
 
833
                                        break;
 
834
                                case BinaryOperatorType.ConditionalAnd:
 
835
                                        methodGroup = operators.LogicalAndOperators;
 
836
                                        break;
 
837
                                case BinaryOperatorType.ConditionalOr:
 
838
                                        methodGroup = operators.LogicalOrOperators;
 
839
                                        break;
 
840
                                default:
 
841
                                        throw new InvalidOperationException();
 
842
                        }
 
843
                        OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { lhs, rhs });
 
844
                        foreach (var candidate in methodGroup) {
 
845
                                builtinOperatorOR.AddCandidate(candidate);
 
846
                        }
 
847
                        CSharpOperators.BinaryOperatorMethod m = (CSharpOperators.BinaryOperatorMethod)builtinOperatorOR.BestCandidate;
 
848
                        IType resultType = m.ReturnType;
 
849
                        if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) {
 
850
                                // If there are any user-defined operators, prefer those over the built-in operators.
 
851
                                // It'll be a more informative error.
 
852
                                if (userDefinedOperatorOR.BestCandidate != null)
 
853
                                        return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
 
854
                                else
 
855
                                        return new ErrorResolveResult(resultType);
 
856
                        } else if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
 
857
                                object val;
 
858
                                try {
 
859
                                        val = m.Invoke(this, lhs.ConstantValue, rhs.ConstantValue);
 
860
                                } catch (ArithmeticException) {
 
861
                                        return new ErrorResolveResult(resultType);
 
862
                                }
 
863
                                return new ConstantResolveResult(resultType, val);
 
864
                        } else {
 
865
                                lhs = Convert(lhs, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
 
866
                                rhs = Convert(rhs, m.Parameters[1].Type, builtinOperatorOR.ArgumentConversions[1]);
 
867
                                return BinaryOperatorResolveResult(resultType, lhs, op, rhs,
 
868
                                                                   builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator);
 
869
                        }
 
870
                }
 
871
                
 
872
                bool IsNullableTypeOrNonValueType(IType type)
 
873
                {
 
874
                        return NullableType.IsNullable(type) || type.IsReferenceType != false;
 
875
                }
 
876
                
 
877
                ResolveResult BinaryOperatorResolveResult(IType resultType, ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs, bool isLifted = false)
 
878
                {
 
879
                        return new OperatorResolveResult(
 
880
                                resultType, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow),
 
881
                                null, isLifted, new[] { lhs, rhs });
 
882
                }
 
883
                #endregion
 
884
                
 
885
                #region Pointer arithmetic
 
886
                CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, IType inputType1, KnownTypeCode inputType2)
 
887
                {
 
888
                        return PointerArithmeticOperator(resultType, inputType1, compilation.FindType(inputType2));
 
889
                }
 
890
                
 
891
                CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, KnownTypeCode inputType1, IType inputType2)
 
892
                {
 
893
                        return PointerArithmeticOperator(resultType, compilation.FindType(inputType1), inputType2);
 
894
                }
 
895
                
 
896
                CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, IType inputType1, IType inputType2)
 
897
                {
 
898
                        return new CSharpOperators.BinaryOperatorMethod(compilation) {
 
899
                                ReturnType = resultType,
 
900
                                Parameters = {
 
901
                                        new DefaultParameter(inputType1, string.Empty),
 
902
                                        new DefaultParameter(inputType2, string.Empty)
 
903
                                }
 
904
                        };
 
905
                }
 
906
                #endregion
 
907
                
 
908
                #region Enum helper methods
 
909
                IType GetEnumUnderlyingType(IType enumType)
 
910
                {
 
911
                        ITypeDefinition def = enumType.GetDefinition();
 
912
                        return def != null ? def.EnumUnderlyingType : SpecialType.UnknownType;
 
913
                }
 
914
                
 
915
                /// <summary>
 
916
                /// Handle the case where an enum value is compared with another enum value
 
917
                /// bool operator op(E x, E y);
 
918
                /// </summary>
 
919
                ResolveResult HandleEnumComparison(BinaryOperatorType op, IType enumType, bool isNullable, ResolveResult lhs, ResolveResult rhs)
 
920
                {
 
921
                        // evaluate as ((U)x op (U)y)
 
922
                        IType elementType = GetEnumUnderlyingType(enumType);
 
923
                        if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) {
 
924
                                lhs = ResolveCast(elementType, lhs);
 
925
                                if (lhs.IsError)
 
926
                                        return lhs;
 
927
                                rhs = ResolveCast(elementType, rhs);
 
928
                                if (rhs.IsError)
 
929
                                        return rhs;
 
930
                                return ResolveBinaryOperator(op, lhs, rhs);
 
931
                        }
 
932
                        IType resultType = compilation.FindType(KnownTypeCode.Boolean);
 
933
                        return BinaryOperatorResolveResult(resultType, lhs, op, rhs, isNullable);
 
934
                }
 
935
                
 
936
                /// <summary>
 
937
                /// Handle the case where an enum value is subtracted from another enum value
 
938
                /// U operator ā€“(E x, E y);
 
939
                /// </summary>
 
940
                ResolveResult HandleEnumSubtraction(bool isNullable, IType enumType, ResolveResult lhs, ResolveResult rhs)
 
941
                {
 
942
                        // evaluate as (U)((U)x ā€“ (U)y)
 
943
                        IType elementType = GetEnumUnderlyingType(enumType);
 
944
                        if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) {
 
945
                                lhs = ResolveCast(elementType, lhs);
 
946
                                if (lhs.IsError)
 
947
                                        return lhs;
 
948
                                rhs = ResolveCast(elementType, rhs);
 
949
                                if (rhs.IsError)
 
950
                                        return rhs;
 
951
                                return CheckErrorAndResolveUncheckedCast(elementType, ResolveBinaryOperator(BinaryOperatorType.Subtract, lhs, rhs));
 
952
                        }
 
953
                        IType resultType = MakeNullable(elementType, isNullable);
 
954
                        return BinaryOperatorResolveResult(resultType, lhs, BinaryOperatorType.Subtract, rhs, isNullable);
 
955
                }
 
956
                
 
957
                /// <summary>
 
958
                /// Handle the following enum operators:
 
959
                /// E operator +(E x, U y);
 
960
                /// E operator +(U x, E y);
 
961
                /// E operator ā€“(E x, U y);
 
962
                /// E operator &amp;(E x, E y);
 
963
                /// E operator |(E x, E y);
 
964
                /// E operator ^(E x, E y);
 
965
                /// </summary>
 
966
                ResolveResult HandleEnumOperator(bool isNullable, IType enumType, BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
 
967
                {
 
968
                        // evaluate as (E)((U)x op (U)y)
 
969
                        if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) {
 
970
                                IType elementType = GetEnumUnderlyingType(enumType);
 
971
                                lhs = ResolveCast(elementType, lhs);
 
972
                                if (lhs.IsError)
 
973
                                        return lhs;
 
974
                                rhs = ResolveCast(elementType, rhs);
 
975
                                if (rhs.IsError)
 
976
                                        return rhs;
 
977
                                return CheckErrorAndResolveUncheckedCast(enumType, ResolveBinaryOperator(op, lhs, rhs));
 
978
                        }
 
979
                        IType resultType = MakeNullable(enumType, isNullable);
 
980
                        return BinaryOperatorResolveResult(resultType, lhs, op, rhs, isNullable);
 
981
                }
 
982
                
 
983
                IType MakeNullable(IType type, bool isNullable)
 
984
                {
 
985
                        if (isNullable)
 
986
                                return NullableType.Create(compilation, type);
 
987
                        else
 
988
                                return type;
 
989
                }
 
990
                #endregion
 
991
                
 
992
                #region BinaryNumericPromotion
 
993
                bool BinaryNumericPromotion(bool isNullable, ref ResolveResult lhs, ref ResolveResult rhs, bool allowNullableConstants)
 
994
                {
 
995
                        // C# 4.0 spec: Ā§7.3.6.2
 
996
                        TypeCode lhsCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(lhs.Type));
 
997
                        TypeCode rhsCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(rhs.Type));
 
998
                        // if one of the inputs is the null literal, promote that to the type of the other operand
 
999
                        if (isNullable && lhs.Type.Kind == TypeKind.Null && rhsCode >= TypeCode.Boolean && rhsCode <= TypeCode.Decimal) {
 
1000
                                lhs = CastTo(rhsCode, isNullable, lhs, allowNullableConstants);
 
1001
                                lhsCode = rhsCode;
 
1002
                        } else if (isNullable && rhs.Type.Kind == TypeKind.Null && lhsCode >= TypeCode.Boolean && lhsCode <= TypeCode.Decimal) {
 
1003
                                rhs = CastTo(lhsCode, isNullable, rhs, allowNullableConstants);
 
1004
                                rhsCode = lhsCode;
 
1005
                        }
 
1006
                        bool bindingError = false;
 
1007
                        if (lhsCode >= TypeCode.Char && lhsCode <= TypeCode.Decimal
 
1008
                            && rhsCode >= TypeCode.Char && rhsCode <= TypeCode.Decimal)
 
1009
                        {
 
1010
                                TypeCode targetType;
 
1011
                                if (lhsCode == TypeCode.Decimal || rhsCode == TypeCode.Decimal) {
 
1012
                                        targetType = TypeCode.Decimal;
 
1013
                                        bindingError = (lhsCode == TypeCode.Single || lhsCode == TypeCode.Double
 
1014
                                                        || rhsCode == TypeCode.Single || rhsCode == TypeCode.Double);
 
1015
                                } else if (lhsCode == TypeCode.Double || rhsCode == TypeCode.Double) {
 
1016
                                        targetType = TypeCode.Double;
 
1017
                                } else if (lhsCode == TypeCode.Single || rhsCode == TypeCode.Single) {
 
1018
                                        targetType = TypeCode.Single;
 
1019
                                } else if (lhsCode == TypeCode.UInt64 || rhsCode == TypeCode.UInt64) {
 
1020
                                        targetType = TypeCode.UInt64;
 
1021
                                        bindingError = IsSigned(lhsCode, lhs) || IsSigned(rhsCode, rhs);
 
1022
                                } else if (lhsCode == TypeCode.Int64 || rhsCode == TypeCode.Int64) {
 
1023
                                        targetType = TypeCode.Int64;
 
1024
                                } else if (lhsCode == TypeCode.UInt32 || rhsCode == TypeCode.UInt32) {
 
1025
                                        targetType = (IsSigned(lhsCode, lhs) || IsSigned(rhsCode, rhs)) ? TypeCode.Int64 : TypeCode.UInt32;
 
1026
                                } else {
 
1027
                                        targetType = TypeCode.Int32;
 
1028
                                }
 
1029
                                lhs = CastTo(targetType, isNullable, lhs, allowNullableConstants);
 
1030
                                rhs = CastTo(targetType, isNullable, rhs, allowNullableConstants);
 
1031
                        }
 
1032
                        return !bindingError;
 
1033
                }
 
1034
                
 
1035
                bool IsSigned(TypeCode code, ResolveResult rr)
 
1036
                {
 
1037
                        // Determine whether the rr with code==ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(rr.Type))
 
1038
                        // is a signed primitive type.
 
1039
                        switch (code) {
 
1040
                                case TypeCode.SByte:
 
1041
                                case TypeCode.Int16:
 
1042
                                        return true;
 
1043
                                case TypeCode.Int32:
 
1044
                                        // for int, consider implicit constant expression conversion
 
1045
                                        if (rr.IsCompileTimeConstant && rr.ConstantValue != null && (int)rr.ConstantValue >= 0)
 
1046
                                                return false;
 
1047
                                        else
 
1048
                                                return true;
 
1049
                                case TypeCode.Int64:
 
1050
                                        // for long, consider implicit constant expression conversion
 
1051
                                        if (rr.IsCompileTimeConstant && rr.ConstantValue != null && (long)rr.ConstantValue >= 0)
 
1052
                                                return false;
 
1053
                                        else
 
1054
                                                return true;
 
1055
                                default:
 
1056
                                        return false;
 
1057
                        }
 
1058
                }
 
1059
                
 
1060
                ResolveResult CastTo(TypeCode targetType, bool isNullable, ResolveResult expression, bool allowNullableConstants)
 
1061
                {
 
1062
                        IType elementType = compilation.FindType(targetType);
 
1063
                        IType nullableType = MakeNullable(elementType, isNullable);
 
1064
                        if (nullableType.Equals(expression.Type))
 
1065
                                return expression;
 
1066
                        if (allowNullableConstants && expression.IsCompileTimeConstant) {
 
1067
                                if (expression.ConstantValue == null)
 
1068
                                        return new ConstantResolveResult(nullableType, null);
 
1069
                                ResolveResult rr = ResolveCast(elementType, expression);
 
1070
                                if (rr.IsError)
 
1071
                                        return rr;
 
1072
                                Debug.Assert(rr.IsCompileTimeConstant);
 
1073
                                return new ConstantResolveResult(nullableType, rr.ConstantValue);
 
1074
                        } else {
 
1075
                                return Convert(expression, nullableType,
 
1076
                                               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
 
1077
                        }
 
1078
                }
 
1079
                #endregion
 
1080
                
 
1081
                #region GetOverloadableOperatorName
 
1082
                static string GetOverloadableOperatorName(BinaryOperatorType op)
 
1083
                {
 
1084
                        switch (op) {
 
1085
                                case BinaryOperatorType.Add:
 
1086
                                        return "op_Addition";
 
1087
                                case BinaryOperatorType.Subtract:
 
1088
                                        return "op_Subtraction";
 
1089
                                case BinaryOperatorType.Multiply:
 
1090
                                        return "op_Multiply";
 
1091
                                case BinaryOperatorType.Divide:
 
1092
                                        return "op_Division";
 
1093
                                case BinaryOperatorType.Modulus:
 
1094
                                        return "op_Modulus";
 
1095
                                case BinaryOperatorType.BitwiseAnd:
 
1096
                                        return "op_BitwiseAnd";
 
1097
                                case BinaryOperatorType.BitwiseOr:
 
1098
                                        return "op_BitwiseOr";
 
1099
                                case BinaryOperatorType.ExclusiveOr:
 
1100
                                        return "op_ExclusiveOr";
 
1101
                                case BinaryOperatorType.ShiftLeft:
 
1102
                                        return "op_LeftShift";
 
1103
                                case BinaryOperatorType.ShiftRight:
 
1104
                                        return "op_RightShift";
 
1105
                                case BinaryOperatorType.Equality:
 
1106
                                        return "op_Equality";
 
1107
                                case BinaryOperatorType.InEquality:
 
1108
                                        return "op_Inequality";
 
1109
                                case BinaryOperatorType.GreaterThan:
 
1110
                                        return "op_GreaterThan";
 
1111
                                case BinaryOperatorType.LessThan:
 
1112
                                        return "op_LessThan";
 
1113
                                case BinaryOperatorType.GreaterThanOrEqual:
 
1114
                                        return "op_GreaterThanOrEqual";
 
1115
                                case BinaryOperatorType.LessThanOrEqual:
 
1116
                                        return "op_LessThanOrEqual";
 
1117
                                default:
 
1118
                                        return null;
 
1119
                        }
 
1120
                }
 
1121
                #endregion
 
1122
                
 
1123
                #region Null coalescing operator
 
1124
                ResolveResult ResolveNullCoalescingOperator(ResolveResult lhs, ResolveResult rhs)
 
1125
                {
 
1126
                        if (NullableType.IsNullable(lhs.Type)) {
 
1127
                                IType a0 = NullableType.GetUnderlyingType(lhs.Type);
 
1128
                                if (TryConvert(ref rhs, a0)) {
 
1129
                                        return BinaryOperatorResolveResult(a0, lhs, BinaryOperatorType.NullCoalescing, rhs);
 
1130
                                }
 
1131
                        }
 
1132
                        if (TryConvert(ref rhs, lhs.Type)) {
 
1133
                                return BinaryOperatorResolveResult(lhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs);
 
1134
                        }
 
1135
                        if (TryConvert(ref lhs, rhs.Type)) {
 
1136
                                return BinaryOperatorResolveResult(rhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs);
 
1137
                        } else {
 
1138
                                return new ErrorResolveResult(lhs.Type);
 
1139
                        }
 
1140
                }
 
1141
                #endregion
 
1142
                #endregion
 
1143
                
 
1144
                #region Get user-defined operator candidates
 
1145
                IEnumerable<IParameterizedMember> GetUserDefinedOperatorCandidates(IType type, string operatorName)
 
1146
                {
 
1147
                        if (operatorName == null)
 
1148
                                return EmptyList<IMethod>.Instance;
 
1149
                        TypeCode c = ReflectionHelper.GetTypeCode(type);
 
1150
                        if (TypeCode.Boolean <= c && c <= TypeCode.Decimal || c == TypeCode.String) {
 
1151
                                // The .NET framework contains some of C#'s built-in operators as user-defined operators.
 
1152
                                // However, we must not use those as user-defined operators (we would skip numeric promotion).
 
1153
                                return EmptyList<IMethod>.Instance;
 
1154
                        }
 
1155
                        // C# 4.0 spec: Ā§7.3.5 Candidate user-defined operators
 
1156
                        var operators = type.GetMethods(m => m.IsOperator && m.Name == operatorName).ToList();
 
1157
                        LiftUserDefinedOperators(operators);
 
1158
                        return operators;
 
1159
                }
 
1160
                
 
1161
                void LiftUserDefinedOperators(List<IMethod> operators)
 
1162
                {
 
1163
                        int nonLiftedMethodCount = operators.Count;
 
1164
                        // Construct lifted operators
 
1165
                        for (int i = 0; i < nonLiftedMethodCount; i++) {
 
1166
                                var liftedMethod = LiftUserDefinedOperator(operators[i]);
 
1167
                                if (liftedMethod != null)
 
1168
                                        operators.Add(liftedMethod);
 
1169
                        }
 
1170
                }
 
1171
                
 
1172
                LiftedUserDefinedOperator LiftUserDefinedOperator(IMethod m)
 
1173
                {
 
1174
                        if (IsComparisonOperator(m)) {
 
1175
                                if (!m.ReturnType.Equals(compilation.FindType(KnownTypeCode.Boolean)))
 
1176
                                        return null; // cannot lift this operator
 
1177
                        } else {
 
1178
                                if (!NullableType.IsNonNullableValueType(m.ReturnType))
 
1179
                                        return null; // cannot lift this operator
 
1180
                        }
 
1181
                        for (int i = 0; i < m.Parameters.Count; i++) {
 
1182
                                if (!NullableType.IsNonNullableValueType(m.Parameters[i].Type))
 
1183
                                        return null; // cannot lift this operator
 
1184
                        }
 
1185
                        return new LiftedUserDefinedOperator(m);
 
1186
                }
 
1187
                
 
1188
                static bool IsComparisonOperator(IMethod m)
 
1189
                {
 
1190
                        var type = OperatorDeclaration.GetOperatorType(m.Name);
 
1191
                        return type.HasValue && type.Value.IsComparisonOperator();
 
1192
                }
 
1193
                
 
1194
                sealed class LiftedUserDefinedOperator : SpecializedMethod, OverloadResolution.ILiftedOperator
 
1195
                {
 
1196
                        internal readonly IParameterizedMember nonLiftedOperator;
 
1197
                        
 
1198
                        public LiftedUserDefinedOperator(IMethod nonLiftedMethod)
 
1199
                                : base(nonLiftedMethod, TypeParameterSubstitution.Identity)
 
1200
                        {
 
1201
                                this.nonLiftedOperator = nonLiftedMethod;
 
1202
                                var substitution = new MakeNullableVisitor(nonLiftedMethod.Compilation);
 
1203
                                this.Parameters = base.CreateParameters(substitution);
 
1204
                                // Comparison operators keep the 'bool' return type even when lifted.
 
1205
                                if (IsComparisonOperator(nonLiftedMethod))
 
1206
                                        this.ReturnType = nonLiftedMethod.ReturnType;
 
1207
                                else
 
1208
                                        this.ReturnType = nonLiftedMethod.ReturnType.AcceptVisitor(substitution);
 
1209
                        }
 
1210
                        
 
1211
                        public IList<IParameter> NonLiftedParameters {
 
1212
                                get { return nonLiftedOperator.Parameters; }
 
1213
                        }
 
1214
                        
 
1215
                        public override bool Equals(object obj)
 
1216
                        {
 
1217
                                LiftedUserDefinedOperator op = obj as LiftedUserDefinedOperator;
 
1218
                                return op != null && this.nonLiftedOperator.Equals(op.nonLiftedOperator);
 
1219
                        }
 
1220
                        
 
1221
                        public override int GetHashCode()
 
1222
                        {
 
1223
                                return nonLiftedOperator.GetHashCode() ^ 0x7191254;
 
1224
                        }
 
1225
                }
 
1226
                
 
1227
                sealed class MakeNullableVisitor : TypeVisitor
 
1228
                {
 
1229
                        readonly ICompilation compilation;
 
1230
                        
 
1231
                        public MakeNullableVisitor(ICompilation compilation)
 
1232
                        {
 
1233
                                this.compilation = compilation;
 
1234
                        }
 
1235
                        
 
1236
                        public override IType VisitTypeDefinition(ITypeDefinition type)
 
1237
                        {
 
1238
                                return NullableType.Create(compilation, type);
 
1239
                        }
 
1240
                        
 
1241
                        public override IType VisitTypeParameter(ITypeParameter type)
 
1242
                        {
 
1243
                                return NullableType.Create(compilation, type);
 
1244
                        }
 
1245
                        
 
1246
                        public override IType VisitParameterizedType(ParameterizedType type)
 
1247
                        {
 
1248
                                return NullableType.Create(compilation, type);
 
1249
                        }
 
1250
                        
 
1251
                        public override IType VisitOtherType(IType type)
 
1252
                        {
 
1253
                                return NullableType.Create(compilation, type);
 
1254
                        }
 
1255
                }
 
1256
                
 
1257
                ResolveResult CreateResolveResultForUserDefinedOperator(OverloadResolution r, System.Linq.Expressions.ExpressionType operatorType)
 
1258
                {
 
1259
                        if (r.BestCandidateErrors != OverloadResolutionErrors.None)
 
1260
                                return r.CreateResolveResult(null);
 
1261
                        IMethod method = (IMethod)r.BestCandidate;
 
1262
                        return new OperatorResolveResult(method.ReturnType, operatorType, method,
 
1263
                                                         isLiftedOperator: method is OverloadResolution.ILiftedOperator,
 
1264
                                                         operands: r.GetArgumentsWithConversions());
 
1265
                }
 
1266
                #endregion
 
1267
                
 
1268
                #region ResolveCast
 
1269
                bool TryConvert(ref ResolveResult rr, IType targetType)
 
1270
                {
 
1271
                        Conversion c = conversions.ImplicitConversion(rr, targetType);
 
1272
                        if (c.IsValid) {
 
1273
                                rr = Convert(rr, targetType, c);
 
1274
                                return true;
 
1275
                        } else {
 
1276
                                return false;
 
1277
                        }
 
1278
                }
 
1279
                
 
1280
                ResolveResult Convert(ResolveResult rr, IType targetType)
 
1281
                {
 
1282
                        return Convert(rr, targetType, conversions.ImplicitConversion(rr, targetType));
 
1283
                }
 
1284
                
 
1285
                ResolveResult Convert(ResolveResult rr, IType targetType, Conversion c)
 
1286
                {
 
1287
                        if (c == Conversion.IdentityConversion)
 
1288
                                return rr;
 
1289
                        else if (rr.IsCompileTimeConstant && c != Conversion.None && !c.IsUserDefined)
 
1290
                                return ResolveCast(targetType, rr);
 
1291
                        else
 
1292
                                return new ConversionResolveResult(targetType, rr, c, checkForOverflow);
 
1293
                }
 
1294
                
 
1295
                public ResolveResult ResolveCast(IType targetType, ResolveResult expression)
 
1296
                {
 
1297
                        // C# 4.0 spec: Ā§7.7.6 Cast expressions
 
1298
                        Conversion c = conversions.ExplicitConversion(expression, targetType);
 
1299
                        if (expression.IsCompileTimeConstant && !c.IsUserDefined) {
 
1300
                                TypeCode code = ReflectionHelper.GetTypeCode(targetType);
 
1301
                                if (code >= TypeCode.Boolean && code <= TypeCode.Decimal && expression.ConstantValue != null) {
 
1302
                                        try {
 
1303
                                                return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue));
 
1304
                                        } catch (OverflowException) {
 
1305
                                                return new ErrorResolveResult(targetType);
 
1306
                                        } catch (InvalidCastException) {
 
1307
                                                return new ErrorResolveResult(targetType);
 
1308
                                        }
 
1309
                                } else if (code == TypeCode.String) {
 
1310
                                        if (expression.ConstantValue == null || expression.ConstantValue is string)
 
1311
                                                return new ConstantResolveResult(targetType, expression.ConstantValue);
 
1312
                                        else
 
1313
                                                return new ErrorResolveResult(targetType);
 
1314
                                } else if (targetType.Kind == TypeKind.Enum) {
 
1315
                                        code = ReflectionHelper.GetTypeCode(GetEnumUnderlyingType(targetType));
 
1316
                                        if (code >= TypeCode.SByte && code <= TypeCode.UInt64 && expression.ConstantValue != null) {
 
1317
                                                try {
 
1318
                                                        return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue));
 
1319
                                                } catch (OverflowException) {
 
1320
                                                        return new ErrorResolveResult(targetType);
 
1321
                                                } catch (InvalidCastException) {
 
1322
                                                        return new ErrorResolveResult(targetType);
 
1323
                                                }
 
1324
                                        }
 
1325
                                }
 
1326
                        }
 
1327
                        return new ConversionResolveResult(targetType, expression, c, checkForOverflow);
 
1328
                }
 
1329
                
 
1330
                internal object CSharpPrimitiveCast(TypeCode targetType, object input)
 
1331
                {
 
1332
                        return Utils.CSharpPrimitiveCast.Cast(targetType, input, this.CheckForOverflow);
 
1333
                }
 
1334
                
 
1335
                ResolveResult CheckErrorAndResolveUncheckedCast(IType targetType, ResolveResult expression)
 
1336
                {
 
1337
                        if (expression.IsError)
 
1338
                                return expression;
 
1339
                        else
 
1340
                                return WithCheckForOverflow(false).ResolveCast(targetType, expression);
 
1341
                }
 
1342
                #endregion
 
1343
                
 
1344
                #region ResolveSimpleName
 
1345
                public ResolveResult ResolveSimpleName(string identifier, IList<IType> typeArguments, bool isInvocationTarget = false)
 
1346
                {
 
1347
                        // C# 4.0 spec: Ā§7.6.2 Simple Names
 
1348
                        
 
1349
                        return LookupSimpleNameOrTypeName(
 
1350
                                identifier, typeArguments,
 
1351
                                isInvocationTarget ? NameLookupMode.InvocationTarget : NameLookupMode.Expression);
 
1352
                }
 
1353
                
 
1354
                public ResolveResult LookupSimpleNameOrTypeName(string identifier, IList<IType> typeArguments, NameLookupMode lookupMode)
 
1355
                {
 
1356
                        // C# 4.0 spec: Ā§3.8 Namespace and type names; Ā§7.6.2 Simple Names
 
1357
                        
 
1358
                        if (identifier == null)
 
1359
                                throw new ArgumentNullException("identifier");
 
1360
                        if (typeArguments == null)
 
1361
                                throw new ArgumentNullException("typeArguments");
 
1362
                        
 
1363
                        int k = typeArguments.Count;
 
1364
                        
 
1365
                        if (k == 0) {
 
1366
                                if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget) {
 
1367
                                        // Look in local variables
 
1368
                                        foreach (IVariable v in this.LocalVariables) {
 
1369
                                                if (v.Name == identifier) {
 
1370
                                                        return new LocalResolveResult(v);
 
1371
                                                }
 
1372
                                        }
 
1373
                                        // Look in parameters of current method
 
1374
                                        IParameterizedMember parameterizedMember = this.CurrentMember as IParameterizedMember;
 
1375
                                        if (parameterizedMember != null) {
 
1376
                                                foreach (IParameter p in parameterizedMember.Parameters) {
 
1377
                                                        if (p.Name == identifier) {
 
1378
                                                                return new LocalResolveResult(p);
 
1379
                                                        }
 
1380
                                                }
 
1381
                                        }
 
1382
                                }
 
1383
                                
 
1384
                                // look in type parameters of current method
 
1385
                                IMethod m = this.CurrentMember as IMethod;
 
1386
                                if (m != null) {
 
1387
                                        foreach (ITypeParameter tp in m.TypeParameters) {
 
1388
                                                if (tp.Name == identifier)
 
1389
                                                        return new TypeResolveResult(tp);
 
1390
                                        }
 
1391
                                }
 
1392
                        }
 
1393
                        
 
1394
                        bool parameterizeResultType = !(typeArguments.Count != 0 && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument));
 
1395
                        
 
1396
                        ResolveResult r = null;
 
1397
                        if (currentTypeDefinitionCache != null) {
 
1398
                                Dictionary<string, ResolveResult> cache = null;
 
1399
                                bool foundInCache = false;
 
1400
                                if (k == 0) {
 
1401
                                        switch (lookupMode) {
 
1402
                                                case NameLookupMode.Expression:
 
1403
                                                        cache = currentTypeDefinitionCache.SimpleNameLookupCacheExpression;
 
1404
                                                        break;
 
1405
                                                case NameLookupMode.InvocationTarget:
 
1406
                                                        cache = currentTypeDefinitionCache.SimpleNameLookupCacheInvocationTarget;
 
1407
                                                        break;
 
1408
                                                case NameLookupMode.Type:
 
1409
                                                        cache = currentTypeDefinitionCache.SimpleTypeLookupCache;
 
1410
                                                        break;
 
1411
                                        }
 
1412
                                        if (cache != null) {
 
1413
                                                lock (cache)
 
1414
                                                        foundInCache = cache.TryGetValue(identifier, out r);
 
1415
                                        }
 
1416
                                }
 
1417
                                if (foundInCache) {
 
1418
                                        r = (r != null ? r.ShallowClone() : null);
 
1419
                                } else {
 
1420
                                        r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType);
 
1421
                                        if (cache != null) {
 
1422
                                                // also cache missing members (r==null)
 
1423
                                                lock (cache)
 
1424
                                                        cache[identifier] = r;
 
1425
                                        }
 
1426
                                }
 
1427
                                if (r != null)
 
1428
                                        return r;
 
1429
                        }
 
1430
                        
 
1431
                        if (context.CurrentUsingScope == null) {
 
1432
                                // If no using scope was specified, we still need to look in the global namespace:
 
1433
                                r = LookInUsingScopeNamespace(null, compilation.RootNamespace, identifier, typeArguments, parameterizeResultType);
 
1434
                        } else {
 
1435
                                if (k == 0 && lookupMode != NameLookupMode.TypeInUsingDeclaration) {
 
1436
                                        if (context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) {
 
1437
                                                r = (r != null ? r.ShallowClone() : null);
 
1438
                                        } else {
 
1439
                                                r = LookInCurrentUsingScope(identifier, typeArguments, false, false);
 
1440
                                                context.CurrentUsingScope.ResolveCache.TryAdd(identifier, r);
 
1441
                                        }
 
1442
                                } else {
 
1443
                                        r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == NameLookupMode.TypeInUsingDeclaration, parameterizeResultType);
 
1444
                                }
 
1445
                        }
 
1446
                        if (r != null)
 
1447
                                return r;
 
1448
                        
 
1449
                        if (typeArguments.Count == 0 && identifier == "dynamic") {
 
1450
                                return new TypeResolveResult(SpecialType.Dynamic);
 
1451
                        } else {
 
1452
                                return new UnknownIdentifierResolveResult(identifier, typeArguments.Count);
 
1453
                        }
 
1454
                }
 
1455
                
 
1456
                public bool IsVariableReferenceWithSameType (ResolveResult rr, string identifier, out TypeResolveResult trr)
 
1457
                {
 
1458
                        if (!(rr is MemberResolveResult || rr is LocalResolveResult)) {
 
1459
                                trr = null;
 
1460
                                return false;
 
1461
                        }
 
1462
                        trr = LookupSimpleNameOrTypeName (identifier, EmptyList<IType>.Instance, NameLookupMode.Type) as TypeResolveResult;
 
1463
                        return trr != null && trr.Type.Equals (rr.Type);
 
1464
                }
 
1465
                
 
1466
                ResolveResult LookInCurrentType(string identifier, IList<IType> typeArguments, NameLookupMode lookupMode, bool parameterizeResultType)
 
1467
                {
 
1468
                        int k = typeArguments.Count;
 
1469
                        MemberLookup lookup = CreateMemberLookup(lookupMode);
 
1470
                        // look in current type definitions
 
1471
                        for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
 
1472
                                if (k == 0) {
 
1473
                                        // Look for type parameter with that name
 
1474
                                        var typeParameters = t.TypeParameters;
 
1475
                                        // Look at all type parameters, including those copied from outer classes,
 
1476
                                        // so that we can fetch the version with the correct owner.
 
1477
                                        for (int i = 0; i < typeParameters.Count; i++) {
 
1478
                                                if (typeParameters[i].Name == identifier)
 
1479
                                                        return new TypeResolveResult(typeParameters[i]);
 
1480
                                        }
 
1481
                                }
 
1482
                                
 
1483
                                if (lookupMode == NameLookupMode.BaseTypeReference && t == this.CurrentTypeDefinition) {
 
1484
                                        // don't look in current type when resolving a base type reference
 
1485
                                        continue;
 
1486
                                }
 
1487
                                
 
1488
                                ResolveResult r;
 
1489
                                if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget) {
 
1490
                                        var targetResolveResult = (t == this.CurrentTypeDefinition ? ResolveThisReference() : new TypeResolveResult(t));
 
1491
                                        r = lookup.Lookup(targetResolveResult, identifier, typeArguments, lookupMode == NameLookupMode.InvocationTarget);
 
1492
                                } else {
 
1493
                                        r = lookup.LookupType(t, identifier, typeArguments, parameterizeResultType);
 
1494
                                }
 
1495
                                if (!(r is UnknownMemberResolveResult)) // but do return AmbiguousMemberResolveResult
 
1496
                                        return r;
 
1497
                        }
 
1498
                        return null;
 
1499
                }
 
1500
                
 
1501
                ResolveResult LookInCurrentUsingScope(string identifier, IList<IType> typeArguments, bool isInUsingDeclaration, bool parameterizeResultType)
 
1502
                {
 
1503
                        // look in current namespace definitions
 
1504
                        ResolvedUsingScope currentUsingScope = this.CurrentUsingScope;
 
1505
                        for (ResolvedUsingScope u = currentUsingScope; u != null; u = u.Parent) {
 
1506
                                var resultInNamespace = LookInUsingScopeNamespace(u, u.Namespace, identifier, typeArguments, parameterizeResultType);
 
1507
                                if (resultInNamespace != null)
 
1508
                                        return resultInNamespace;
 
1509
                                // then look for aliases:
 
1510
                                if (typeArguments.Count == 0) {
 
1511
                                        if (u.ExternAliases.Contains(identifier)) {
 
1512
                                                return ResolveExternAlias(identifier);
 
1513
                                        }
 
1514
                                        if (!(isInUsingDeclaration && u == currentUsingScope)) {
 
1515
                                                foreach (var pair in u.UsingAliases) {
 
1516
                                                        if (pair.Key == identifier) {
 
1517
                                                                return pair.Value.ShallowClone();
 
1518
                                                        }
 
1519
                                                }
 
1520
                                        }
 
1521
                                }
 
1522
                                // finally, look in the imported namespaces:
 
1523
                                if (!(isInUsingDeclaration && u == currentUsingScope)) {
 
1524
                                        IType firstResult = null;
 
1525
                                        foreach (var importedNamespace in u.Usings) {
 
1526
                                                ITypeDefinition def = importedNamespace.GetTypeDefinition(identifier, typeArguments.Count);
 
1527
                                                if (def != null) {
 
1528
                                                        IType resultType;
 
1529
                                                        if (parameterizeResultType && typeArguments.Count > 0)
 
1530
                                                                resultType = new ParameterizedType(def, typeArguments);
 
1531
                                                        else
 
1532
                                                                resultType = def;
 
1533
                                                        
 
1534
                                                        if (firstResult == null || !TopLevelTypeDefinitionIsAccessible(firstResult.GetDefinition())) {
 
1535
                                                                firstResult = resultType;
 
1536
                                                        } else if (TopLevelTypeDefinitionIsAccessible(def)) {
 
1537
                                                                return new AmbiguousTypeResolveResult(firstResult);
 
1538
                                                        }
 
1539
                                                }
 
1540
                                        }
 
1541
                                        if (firstResult != null)
 
1542
                                                return new TypeResolveResult(firstResult);
 
1543
                                }
 
1544
                                // if we didn't find anything: repeat lookup with parent namespace
 
1545
                        }
 
1546
                        return null;
 
1547
                }
 
1548
 
 
1549
                ResolveResult LookInUsingScopeNamespace(ResolvedUsingScope usingScope, INamespace n, string identifier, IList<IType> typeArguments, bool parameterizeResultType)
 
1550
                {
 
1551
                        if (n == null)
 
1552
                                return null;
 
1553
                        // first look for a namespace
 
1554
                        int k = typeArguments.Count;
 
1555
                        if (k == 0) {
 
1556
                                INamespace childNamespace = n.GetChildNamespace(identifier);
 
1557
                                if (childNamespace != null) {
 
1558
                                        if (usingScope != null && usingScope.HasAlias(identifier))
 
1559
                                                return new AmbiguousTypeResolveResult(new UnknownType(null, identifier));
 
1560
                                        return new NamespaceResolveResult(childNamespace);
 
1561
                                }
 
1562
                        }
 
1563
                        // then look for a type
 
1564
                        ITypeDefinition def = n.GetTypeDefinition(identifier, k);
 
1565
                        if (def != null) {
 
1566
                                IType result = def;
 
1567
                                if (parameterizeResultType && k > 0) {
 
1568
                                        result = new ParameterizedType(def, typeArguments);
 
1569
                                }
 
1570
                                if (usingScope != null && usingScope.HasAlias(identifier))
 
1571
                                        return new AmbiguousTypeResolveResult(result);
 
1572
                                else
 
1573
                                        return new TypeResolveResult(result);
 
1574
                        }
 
1575
                        return null;
 
1576
                }
 
1577
                
 
1578
                bool TopLevelTypeDefinitionIsAccessible(ITypeDefinition typeDef)
 
1579
                {
 
1580
                        if (typeDef.IsInternal) {
 
1581
                                return typeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly);
 
1582
                        }
 
1583
                        return true;
 
1584
                }
 
1585
                
 
1586
                /// <summary>
 
1587
                /// Looks up an alias (identifier in front of :: operator)
 
1588
                /// </summary>
 
1589
                public ResolveResult ResolveAlias(string identifier)
 
1590
                {
 
1591
                        if (identifier == "global")
 
1592
                                return new NamespaceResolveResult(compilation.RootNamespace);
 
1593
                        
 
1594
                        for (ResolvedUsingScope n = this.CurrentUsingScope; n != null; n = n.Parent) {
 
1595
                                if (n.ExternAliases.Contains(identifier)) {
 
1596
                                        return ResolveExternAlias(identifier);
 
1597
                                }
 
1598
                                foreach (var pair in n.UsingAliases) {
 
1599
                                        if (pair.Key == identifier) {
 
1600
                                                return (pair.Value as NamespaceResolveResult) ?? ErrorResult;
 
1601
                                        }
 
1602
                                }
 
1603
                        }
 
1604
                        return ErrorResult;
 
1605
                }
 
1606
                
 
1607
                ResolveResult ResolveExternAlias(string alias)
 
1608
                {
 
1609
                        INamespace ns = compilation.GetNamespaceForExternAlias(alias);
 
1610
                        if (ns != null)
 
1611
                                return new NamespaceResolveResult(ns);
 
1612
                        else
 
1613
                                return ErrorResult;
 
1614
                }
 
1615
                #endregion
 
1616
                
 
1617
                #region ResolveMemberAccess
 
1618
                public ResolveResult ResolveMemberAccess(ResolveResult target, string identifier, IList<IType> typeArguments, NameLookupMode lookupMode = NameLookupMode.Expression)
 
1619
                {
 
1620
                        // C# 4.0 spec: Ā§7.6.4
 
1621
                        
 
1622
                        bool parameterizeResultType = !(typeArguments.Count != 0 && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument));
 
1623
                        NamespaceResolveResult nrr = target as NamespaceResolveResult;
 
1624
                        if (nrr != null) {
 
1625
                                return ResolveMemberAccessOnNamespace(nrr, identifier, typeArguments, parameterizeResultType);
 
1626
                        }
 
1627
                        
 
1628
                        if (target.Type.Kind == TypeKind.Dynamic)
 
1629
                                return new DynamicMemberResolveResult(target, identifier);
 
1630
                        
 
1631
                        MemberLookup lookup = CreateMemberLookup(lookupMode);
 
1632
                        ResolveResult result;
 
1633
                        switch (lookupMode) {
 
1634
                                case NameLookupMode.Expression:
 
1635
                                        result = lookup.Lookup(target, identifier, typeArguments, isInvocation: false);
 
1636
                                        break;
 
1637
                                case NameLookupMode.InvocationTarget:
 
1638
                                        result = lookup.Lookup(target, identifier, typeArguments, isInvocation: true);
 
1639
                                        break;
 
1640
                                case NameLookupMode.Type:
 
1641
                                case NameLookupMode.TypeInUsingDeclaration:
 
1642
                                case NameLookupMode.BaseTypeReference:
 
1643
                                        result = lookup.LookupType(target.Type, identifier, typeArguments, parameterizeResultType);
 
1644
                                        break;
 
1645
                                default:
 
1646
                                        throw new NotSupportedException("Invalid value for NameLookupMode");
 
1647
                        }
 
1648
                        if (result is UnknownMemberResolveResult) {
 
1649
                                // We intentionally use all extension methods here, not just the eligible ones.
 
1650
                                // Proper eligibility checking is only possible for the full invocation
 
1651
                                // (after we know the remaining arguments).
 
1652
                                // The eligibility check in GetExtensionMethods is only intended for code completion.
 
1653
                                var extensionMethods = GetExtensionMethods(identifier, typeArguments);
 
1654
                                if (extensionMethods.Count > 0) {
 
1655
                                        return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) {
 
1656
                                                extensionMethods = extensionMethods
 
1657
                                        };
 
1658
                                }
 
1659
                        } else {
 
1660
                                MethodGroupResolveResult mgrr = result as MethodGroupResolveResult;
 
1661
                                if (mgrr != null) {
 
1662
                                        Debug.Assert(mgrr.extensionMethods == null);
 
1663
                                        // set the values that are necessary to make MethodGroupResolveResult.GetExtensionMethods() work
 
1664
                                        mgrr.resolver = this;
 
1665
                                }
 
1666
                        }
 
1667
                        return result;
 
1668
                }
 
1669
                
 
1670
                [Obsolete("Use ResolveMemberAccess() with NameLookupMode.Type instead")]
 
1671
                public ResolveResult ResolveMemberType(ResolveResult target, string identifier, IList<IType> typeArguments)
 
1672
                {
 
1673
                        return ResolveMemberAccess(target, identifier, typeArguments, NameLookupMode.Type);
 
1674
                }
 
1675
                
 
1676
                ResolveResult ResolveMemberAccessOnNamespace(NamespaceResolveResult nrr, string identifier, IList<IType> typeArguments, bool parameterizeResultType)
 
1677
                {
 
1678
                        if (typeArguments.Count == 0) {
 
1679
                                INamespace childNamespace = nrr.Namespace.GetChildNamespace(identifier);
 
1680
                                if (childNamespace != null)
 
1681
                                        return new NamespaceResolveResult(childNamespace);
 
1682
                        }
 
1683
                        ITypeDefinition def = nrr.Namespace.GetTypeDefinition(identifier, typeArguments.Count);
 
1684
                        if (def != null) {
 
1685
                                if (parameterizeResultType && typeArguments.Count > 0)
 
1686
                                        return new TypeResolveResult(new ParameterizedType(def, typeArguments));
 
1687
                                else
 
1688
                                        return new TypeResolveResult(def);
 
1689
                        }
 
1690
                        return ErrorResult;
 
1691
                }
 
1692
                
 
1693
                /// <summary>
 
1694
                /// Creates a MemberLookup instance using this resolver's settings.
 
1695
                /// </summary>
 
1696
                public MemberLookup CreateMemberLookup()
 
1697
                {
 
1698
                        ITypeDefinition currentTypeDefinition = this.CurrentTypeDefinition;
 
1699
                        bool isInEnumMemberInitializer = this.CurrentMember != null && this.CurrentMember.EntityType == EntityType.Field
 
1700
                                && currentTypeDefinition != null && currentTypeDefinition.Kind == TypeKind.Enum;
 
1701
                        return new MemberLookup(currentTypeDefinition, this.Compilation.MainAssembly, isInEnumMemberInitializer);
 
1702
                }
 
1703
                
 
1704
                /// <summary>
 
1705
                /// Creates a MemberLookup instance using this resolver's settings.
 
1706
                /// </summary>
 
1707
                public MemberLookup CreateMemberLookup(NameLookupMode lookupMode)
 
1708
                {
 
1709
                        if (lookupMode == NameLookupMode.BaseTypeReference && this.CurrentTypeDefinition != null) {
 
1710
                                // When looking up a base type reference, treat us as being outside the current type definition
 
1711
                                // for accessibility purposes.
 
1712
                                // This avoids a stack overflow when referencing a protected class nested inside the base class
 
1713
                                // of a parent class. (NameLookupTests.InnerClassInheritingFromProtectedBaseInnerClassShouldNotCauseStackOverflow)
 
1714
                                return new MemberLookup(this.CurrentTypeDefinition.DeclaringTypeDefinition, this.Compilation.MainAssembly, false);
 
1715
                        } else {
 
1716
                                return CreateMemberLookup();
 
1717
                        }
 
1718
                }
 
1719
                #endregion
 
1720
                
 
1721
                #region ResolveIdentifierInObjectInitializer
 
1722
                public ResolveResult ResolveIdentifierInObjectInitializer(string identifier)
 
1723
                {
 
1724
                        MemberLookup memberLookup = CreateMemberLookup();
 
1725
                        return memberLookup.Lookup(this.CurrentObjectInitializer, identifier, EmptyList<IType>.Instance, false);
 
1726
                }
 
1727
                #endregion
 
1728
                
 
1729
                #region GetExtensionMethods
 
1730
                /// <summary>
 
1731
                /// Gets all extension methods that are available in the current context.
 
1732
                /// </summary>
 
1733
                /// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param>
 
1734
                /// <param name="typeArguments">Explicitly provided type arguments.
 
1735
                /// An empty list will return all matching extension method definitions;
 
1736
                /// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods
 
1737
                /// with the matching number of type parameters.</param>
 
1738
                /// <remarks>
 
1739
                /// The results are stored in nested lists because they are grouped by using scope.
 
1740
                /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
 
1741
                /// the return value will be
 
1742
                /// new List {
 
1743
                ///    new List { all extensions from MoreExtensions },
 
1744
                ///    new List { all extensions from SomeExtensions }
 
1745
                /// }
 
1746
                /// </remarks>
 
1747
                public List<List<IMethod>> GetExtensionMethods(string name = null, IList<IType> typeArguments = null)
 
1748
                {
 
1749
                        return GetExtensionMethods(null, name, typeArguments);
 
1750
                }
 
1751
                
 
1752
                /// <summary>
 
1753
                /// Gets the extension methods that are called 'name'
 
1754
                /// and are applicable with a first argument type of 'targetType'.
 
1755
                /// </summary>
 
1756
                /// <param name="targetType">Type of the 'this' argument</param>
 
1757
                /// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param>
 
1758
                /// <param name="typeArguments">Explicitly provided type arguments.
 
1759
                /// An empty list will return all matching extension method definitions;
 
1760
                /// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods
 
1761
                /// with the matching number of type parameters.</param>
 
1762
                /// <param name="substituteInferredTypes">
 
1763
                /// Specifies whether to produce a <see cref="SpecializedMethod"/>
 
1764
                /// when type arguments could be inferred from <paramref name="targetType"/>. This parameter
 
1765
                /// is only used for inferred types and has no effect if <paramref name="typeArguments"/> is non-empty.
 
1766
                /// </param>
 
1767
                /// <remarks>
 
1768
                /// The results are stored in nested lists because they are grouped by using scope.
 
1769
                /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
 
1770
                /// the return value will be
 
1771
                /// new List {
 
1772
                ///    new List { all extensions from MoreExtensions },
 
1773
                ///    new List { all extensions from SomeExtensions }
 
1774
                /// }
 
1775
                /// </remarks>
 
1776
                public List<List<IMethod>> GetExtensionMethods(IType targetType, string name = null, IList<IType> typeArguments = null, bool substituteInferredTypes = false)
 
1777
                {
 
1778
                        List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>();
 
1779
                        foreach (var inputGroup in GetAllExtensionMethods()) {
 
1780
                                List<IMethod> outputGroup = new List<IMethod>();
 
1781
                                foreach (var method in inputGroup) {
 
1782
                                        if (name != null && method.Name != name)
 
1783
                                                continue;
 
1784
                                        
 
1785
                                        IType[] inferredTypes;
 
1786
                                        if (typeArguments != null && typeArguments.Count > 0) {
 
1787
                                                if (method.TypeParameters.Count != typeArguments.Count)
 
1788
                                                        continue;
 
1789
                                                var sm = method.Specialize(new TypeParameterSubstitution(null, typeArguments));
 
1790
                                                if (IsEligibleExtensionMethod(compilation, conversions, targetType, sm, false, out inferredTypes))
 
1791
                                                        outputGroup.Add(sm);
 
1792
                                        } else {
 
1793
                                                if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, true, out inferredTypes)) {
 
1794
                                                        if (substituteInferredTypes && inferredTypes != null) {
 
1795
                                                                outputGroup.Add(method.Specialize(new TypeParameterSubstitution(null, inferredTypes)));
 
1796
                                                        } else {
 
1797
                                                                outputGroup.Add(method);
 
1798
                                                        }
 
1799
                                                }
 
1800
                                        }
 
1801
                                }
 
1802
                                if (outputGroup.Count > 0)
 
1803
                                        extensionMethodGroups.Add(outputGroup);
 
1804
                        }
 
1805
                        return extensionMethodGroups;
 
1806
                }
 
1807
                
 
1808
                /// <summary>
 
1809
                /// Checks whether the specified extension method is eligible on the target type.
 
1810
                /// </summary>
 
1811
                /// <param name="targetType">Target type that is passed as first argument to the extension method.</param>
 
1812
                /// <param name="method">The extension method.</param>
 
1813
                /// <param name="useTypeInference">Whether to perform type inference for the method.
 
1814
                /// Use <c>false</c> if <paramref name="method"/> is already parameterized (e.g. when type arguments were given explicitly).
 
1815
                /// Otherwise, use <c>true</c>.
 
1816
                /// </param>
 
1817
                /// <param name="outInferredTypes">If the method is generic and <paramref name="useTypeInference"/> is <c>true</c>,
 
1818
                /// and at least some of the type arguments could be inferred, this parameter receives the inferred type arguments.
 
1819
                /// Since only the type for the first parameter is considered, not all type arguments may be inferred.
 
1820
                /// If an array is returned, any slot with an uninferred type argument will be set to the method's
 
1821
                /// corresponding type parameter.
 
1822
                /// </param>
 
1823
                public static bool IsEligibleExtensionMethod(IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes)
 
1824
                {
 
1825
                        if (targetType == null)
 
1826
                                throw new ArgumentNullException("targetType");
 
1827
                        if (method == null)
 
1828
                                throw new ArgumentNullException("method");
 
1829
                        var compilation = method.Compilation;
 
1830
                        return IsEligibleExtensionMethod(compilation, CSharpConversions.Get(compilation), targetType, method, useTypeInference, out outInferredTypes);
 
1831
                }
 
1832
                
 
1833
                static bool IsEligibleExtensionMethod(ICompilation compilation, CSharpConversions conversions, IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes)
 
1834
                {
 
1835
                        outInferredTypes = null;
 
1836
                        if (targetType == null)
 
1837
                                return true;
 
1838
                        if (method.Parameters.Count == 0)
 
1839
                                return false;
 
1840
                        IType thisParameterType = method.Parameters[0].Type;
 
1841
                        if (useTypeInference && method.TypeParameters.Count > 0) {
 
1842
                                // We need to infer type arguments from targetType:
 
1843
                                TypeInference ti = new TypeInference(compilation, conversions);
 
1844
                                ResolveResult[] arguments = { new ResolveResult(targetType) };
 
1845
                                IType[] parameterTypes = { method.Parameters[0].Type };
 
1846
                                bool success;
 
1847
                                var inferredTypes = ti.InferTypeArguments(method.TypeParameters, arguments, parameterTypes, out success);
 
1848
                                var substitution = new TypeParameterSubstitution(null, inferredTypes);
 
1849
                                // Validate that the types that could be inferred (aren't unknown) satisfy the constraints:
 
1850
                                bool hasInferredTypes = false;
 
1851
                                for (int i = 0; i < inferredTypes.Length; i++) {
 
1852
                                        if (inferredTypes[i].Kind != TypeKind.Unknown && inferredTypes[i].Kind != TypeKind.UnboundTypeArgument) {
 
1853
                                                hasInferredTypes = true;
 
1854
                                                if (!OverloadResolution.ValidateConstraints(method.TypeParameters[i], inferredTypes[i], substitution, conversions))
 
1855
                                                        return false;
 
1856
                                        } else {
 
1857
                                                inferredTypes[i] = method.TypeParameters[i]; // do not substitute types that could not be inferred
 
1858
                                        }
 
1859
                                }
 
1860
                                if (hasInferredTypes)
 
1861
                                        outInferredTypes = inferredTypes;
 
1862
                                thisParameterType = thisParameterType.AcceptVisitor(substitution);
 
1863
                        }
 
1864
                        Conversion c = conversions.ImplicitConversion(targetType, thisParameterType);
 
1865
                        return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion);
 
1866
                }
 
1867
                
 
1868
                /// <summary>
 
1869
                /// Gets all extension methods available in the current using scope.
 
1870
                /// This list includes unaccessible
 
1871
                /// </summary>
 
1872
                IList<List<IMethod>> GetAllExtensionMethods()
 
1873
                {
 
1874
                        var currentUsingScope = context.CurrentUsingScope;
 
1875
                        if (currentUsingScope == null)
 
1876
                                return EmptyList<List<IMethod>>.Instance;
 
1877
                        List<List<IMethod>> extensionMethodGroups = LazyInit.VolatileRead(ref currentUsingScope.AllExtensionMethods);
 
1878
                        if (extensionMethodGroups != null) {
 
1879
                                return extensionMethodGroups;
 
1880
                        }
 
1881
                        extensionMethodGroups = new List<List<IMethod>>();
 
1882
                        List<IMethod> m;
 
1883
                        for (ResolvedUsingScope scope = currentUsingScope; scope != null; scope = scope.Parent) {
 
1884
                                INamespace ns = scope.Namespace;
 
1885
                                if (ns != null) {
 
1886
                                        m = GetExtensionMethods(ns).ToList();
 
1887
                                        if (m.Count > 0)
 
1888
                                                extensionMethodGroups.Add(m);
 
1889
                                }
 
1890
                                
 
1891
                                m = scope.Usings
 
1892
                                        .Distinct()
 
1893
                                        .SelectMany(importedNamespace => GetExtensionMethods(importedNamespace))
 
1894
                                        .ToList();
 
1895
                                if (m.Count > 0)
 
1896
                                        extensionMethodGroups.Add(m);
 
1897
                        }
 
1898
                        return LazyInit.GetOrSet(ref currentUsingScope.AllExtensionMethods, extensionMethodGroups);
 
1899
                }
 
1900
                
 
1901
                IEnumerable<IMethod> GetExtensionMethods(INamespace ns)
 
1902
                {
 
1903
                        // TODO: maybe make this a property on INamespace?
 
1904
                        return
 
1905
                                from c in ns.Types
 
1906
                                where c.IsStatic && c.HasExtensionMethods && c.TypeParameters.Count == 0
 
1907
                                from m in c.Methods
 
1908
                                where m.IsExtensionMethod
 
1909
                                select m;
 
1910
                }
 
1911
                #endregion
 
1912
                
 
1913
                #region ResolveInvocation
 
1914
 
 
1915
                IList<ResolveResult> AddArgumentNamesIfNecessary(ResolveResult[] arguments, string[] argumentNames) {
 
1916
                        if (argumentNames == null) {
 
1917
                                return arguments;
 
1918
                        }
 
1919
                        else {
 
1920
                                var result = new ResolveResult[arguments.Length];
 
1921
                                for (int i = 0; i < arguments.Length; i++) {
 
1922
                                        result[i] = (argumentNames[i] != null ? new NamedArgumentResolveResult(argumentNames[i], arguments[i]) : arguments[i]);
 
1923
                                }
 
1924
                                return result;
 
1925
                        }
 
1926
                }
 
1927
 
 
1928
                private ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames, bool allowOptionalParameters)
 
1929
                {
 
1930
                        // C# 4.0 spec: Ā§7.6.5
 
1931
                        
 
1932
                        if (target.Type.Kind == TypeKind.Dynamic) {
 
1933
                                return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
 
1934
                        }
 
1935
                        
 
1936
                        bool isDynamic = arguments.Any(a => a.Type.Kind == TypeKind.Dynamic);
 
1937
                        MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
 
1938
                        if (mgrr != null) {
 
1939
                                if (isDynamic) {
 
1940
                                        // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method.
 
1941
                                        var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray());
 
1942
                                        var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();
 
1943
 
 
1944
                                        if (applicableMethods.Count > 1) {
 
1945
                                                ResolveResult actualTarget;
 
1946
                                                if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult))
 
1947
                                                        actualTarget = new TypeResolveResult(mgrr.TargetType);
 
1948
                                                else
 
1949
                                                        actualTarget = mgrr.TargetResult;
 
1950
 
 
1951
                                                var l = new List<MethodListWithDeclaringType>();
 
1952
                                                foreach (var m in applicableMethods) {
 
1953
                                                        if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType)
 
1954
                                                                l.Add(new MethodListWithDeclaringType(m.DeclaringType));
 
1955
                                                        l[l.Count - 1].Add(m.Method);
 
1956
                                                }
 
1957
                                                return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
 
1958
                                        }
 
1959
                                }
 
1960
 
 
1961
                                OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions, allowOptionalParameters: allowOptionalParameters);
 
1962
                                if (or.BestCandidate != null) {
 
1963
                                        if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
 
1964
                                                return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType), returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
 
1965
                                        else
 
1966
                                                return or.CreateResolveResult(mgrr.TargetResult, returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
 
1967
                                } else {
 
1968
                                        // No candidate found at all (not even an inapplicable one).
 
1969
                                        // This can happen with empty method groups (as sometimes used with extension methods)
 
1970
                                        return new UnknownMethodResolveResult(
 
1971
                                                mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames));
 
1972
                                }
 
1973
                        }
 
1974
                        UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult;
 
1975
                        if (umrr != null) {
 
1976
                                return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames));
 
1977
                        }
 
1978
                        UnknownIdentifierResolveResult uirr = target as UnknownIdentifierResolveResult;
 
1979
                        if (uirr != null && CurrentTypeDefinition != null) {
 
1980
                                return new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames));
 
1981
                        }
 
1982
                        IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();
 
1983
                        if (invokeMethod != null) {
 
1984
                                OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
 
1985
                                or.AddCandidate(invokeMethod);
 
1986
                                return new CSharpInvocationResolveResult(
 
1987
                                        target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
 
1988
                                        or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
 
1989
                                        isExpandedForm: or.BestCandidateIsExpandedForm,
 
1990
                                        isDelegateInvocation: true,
 
1991
                                        argumentToParameterMap: or.GetArgumentToParameterMap(),
 
1992
                                        returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
 
1993
                        }
 
1994
                        return ErrorResult;
 
1995
                }
 
1996
 
 
1997
                /// <summary>
 
1998
                /// Resolves an invocation.
 
1999
                /// </summary>
 
2000
                /// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
 
2001
                /// <param name="arguments">
 
2002
                /// Arguments passed to the method.
 
2003
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2004
                /// </param>
 
2005
                /// <param name="argumentNames">
 
2006
                /// The argument names. Pass the null string for positional arguments.
 
2007
                /// </param>
 
2008
                /// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns>
 
2009
                public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
 
2010
                {
 
2011
                        return ResolveInvocation(target, arguments, argumentNames, allowOptionalParameters: true);
 
2012
                }
 
2013
                
 
2014
                List<IParameter> CreateParameters(ResolveResult[] arguments, string[] argumentNames)
 
2015
                {
 
2016
                        List<IParameter> list = new List<IParameter>();
 
2017
                        if (argumentNames == null) {
 
2018
                                argumentNames = new string[arguments.Length];
 
2019
                        } else {
 
2020
                                if (argumentNames.Length != arguments.Length)
 
2021
                                        throw new ArgumentException();
 
2022
                                argumentNames = (string[])argumentNames.Clone();
 
2023
                        }
 
2024
                        for (int i = 0; i < arguments.Length; i++) {
 
2025
                                // invent argument names where necessary:
 
2026
                                if (argumentNames[i] == null) {
 
2027
                                        string newArgumentName = GuessParameterName(arguments[i]);
 
2028
                                        if (argumentNames.Contains(newArgumentName)) {
 
2029
                                                // disambiguate argument name (e.g. add a number)
 
2030
                                                int num = 1;
 
2031
                                                string newName;
 
2032
                                                do {
 
2033
                                                        newName = newArgumentName + num.ToString();
 
2034
                                                        num++;
 
2035
                                                } while(argumentNames.Contains(newName));
 
2036
                                                newArgumentName = newName;
 
2037
                                        }
 
2038
                                        argumentNames[i] = newArgumentName;
 
2039
                                }
 
2040
                                
 
2041
                                // create the parameter:
 
2042
                                ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
 
2043
                                if (brrr != null) {
 
2044
                                        list.Add(new DefaultParameter(arguments[i].Type, argumentNames[i], isRef: brrr.IsRef, isOut: brrr.IsOut));
 
2045
                                } else {
 
2046
                                        // argument might be a lambda or delegate type, so we have to try to guess the delegate type
 
2047
                                        IType type = arguments[i].Type;
 
2048
                                        if (type.Kind == TypeKind.Null || type.Kind == TypeKind.Unknown) {
 
2049
                                                list.Add(new DefaultParameter(compilation.FindType(KnownTypeCode.Object), argumentNames[i]));
 
2050
                                        } else {
 
2051
                                                list.Add(new DefaultParameter(type, argumentNames[i]));
 
2052
                                        }
 
2053
                                }
 
2054
                        }
 
2055
                        return list;
 
2056
                }
 
2057
                
 
2058
                static string GuessParameterName(ResolveResult rr)
 
2059
                {
 
2060
                        MemberResolveResult mrr = rr as MemberResolveResult;
 
2061
                        if (mrr != null)
 
2062
                                return mrr.Member.Name;
 
2063
                        
 
2064
                        UnknownMemberResolveResult umrr = rr as UnknownMemberResolveResult;
 
2065
                        if (umrr != null)
 
2066
                                return umrr.MemberName;
 
2067
                        
 
2068
                        MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult;
 
2069
                        if (mgrr != null)
 
2070
                                return mgrr.MethodName;
 
2071
                        
 
2072
                        LocalResolveResult vrr = rr as LocalResolveResult;
 
2073
                        if (vrr != null)
 
2074
                                return MakeParameterName(vrr.Variable.Name);
 
2075
                        
 
2076
                        if (rr.Type.Kind != TypeKind.Unknown && !string.IsNullOrEmpty(rr.Type.Name)) {
 
2077
                                return MakeParameterName(rr.Type.Name);
 
2078
                        } else {
 
2079
                                return "parameter";
 
2080
                        }
 
2081
                }
 
2082
                
 
2083
                static string MakeParameterName(string variableName)
 
2084
                {
 
2085
                        if (string.IsNullOrEmpty(variableName))
 
2086
                                return "parameter";
 
2087
                        if (variableName.Length > 1 && variableName[0] == '_')
 
2088
                                variableName = variableName.Substring(1);
 
2089
                        return char.ToLower(variableName[0]) + variableName.Substring(1);
 
2090
                }
 
2091
                
 
2092
                OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null)
 
2093
                {
 
2094
                        var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions);
 
2095
                        or.CheckForOverflow = checkForOverflow;
 
2096
                        return or;
 
2097
                }
 
2098
                #endregion
 
2099
                
 
2100
                #region ResolveIndexer
 
2101
                /// <summary>
 
2102
                /// Resolves an indexer access.
 
2103
                /// </summary>
 
2104
                /// <param name="target">Target expression.</param>
 
2105
                /// <param name="arguments">
 
2106
                /// Arguments passed to the indexer.
 
2107
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2108
                /// </param>
 
2109
                /// <param name="argumentNames">
 
2110
                /// The argument names. Pass the null string for positional arguments.
 
2111
                /// </param>
 
2112
                /// <returns>ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult</returns>
 
2113
                public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
 
2114
                {
 
2115
                        switch (target.Type.Kind) {
 
2116
                                case TypeKind.Dynamic:
 
2117
                                        return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames));
 
2118
                                        
 
2119
                                case TypeKind.Array:
 
2120
                                case TypeKind.Pointer:
 
2121
                                        // Ā§7.6.6.1 Array access / Ā§18.5.3 Pointer element access
 
2122
                                        AdjustArrayAccessArguments(arguments);
 
2123
                                        return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments);
 
2124
                        }
 
2125
                        
 
2126
                        // Ā§7.6.6.2 Indexer access
 
2127
 
 
2128
                        MemberLookup lookup = CreateMemberLookup();
 
2129
                        var indexers = lookup.LookupIndexers(target.Type);
 
2130
 
 
2131
                        if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
 
2132
                                // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer.
 
2133
                                var or2 = CreateOverloadResolution(arguments, argumentNames, null);
 
2134
                                var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList();
 
2135
 
 
2136
                                if (applicableIndexers.Count > 1) {
 
2137
                                        return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames));
 
2138
                                }
 
2139
                        }
 
2140
 
 
2141
                        OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
 
2142
                        or.AddMethodLists(indexers);
 
2143
                        if (or.BestCandidate != null) {
 
2144
                                return or.CreateResolveResult(target);
 
2145
                        } else {
 
2146
                                return ErrorResult;
 
2147
                        }
 
2148
                }
 
2149
                
 
2150
                /// <summary>
 
2151
                /// Converts all arguments to int,uint,long or ulong.
 
2152
                /// </summary>
 
2153
                void AdjustArrayAccessArguments(ResolveResult[] arguments)
 
2154
                {
 
2155
                        for (int i = 0; i < arguments.Length; i++) {
 
2156
                                if (!(TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.Int32)) ||
 
2157
                                      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.UInt32)) ||
 
2158
                                      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.Int64)) ||
 
2159
                                      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.UInt64))))
 
2160
                                {
 
2161
                                        // conversion failed
 
2162
                                        arguments[i] = Convert(arguments[i], compilation.FindType(KnownTypeCode.Int32), Conversion.None);
 
2163
                                }
 
2164
                        }
 
2165
                }
 
2166
                #endregion
 
2167
                
 
2168
                #region ResolveObjectCreation
 
2169
                /// <summary>
 
2170
                /// Resolves an object creation.
 
2171
                /// </summary>
 
2172
                /// <param name="type">Type of the object to create.</param>
 
2173
                /// <param name="arguments">
 
2174
                /// Arguments passed to the constructor.
 
2175
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2176
                /// </param>
 
2177
                /// <param name="argumentNames">
 
2178
                /// The argument names. Pass the null string for positional arguments.
 
2179
                /// </param>
 
2180
                /// <param name="allowProtectedAccess">
 
2181
                /// Whether to allow calling protected constructors.
 
2182
                /// This should be false except when resolving constructor initializers.
 
2183
                /// </param>
 
2184
                /// <param name="initializerStatements">
 
2185
                /// Statements for Objects/Collections initializer.
 
2186
                /// <see cref="InvocationResolveResult.InitializerStatements"/>
 
2187
                /// </param>
 
2188
                /// <returns>InvocationResolveResult or ErrorResolveResult</returns>
 
2189
                public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null)
 
2190
                {
 
2191
                        if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
 
2192
                                ResolveResult input = arguments[0];
 
2193
                                IMethod invoke = input.Type.GetDelegateInvokeMethod();
 
2194
                                if (invoke != null) {
 
2195
                                        input = new MethodGroupResolveResult(
 
2196
                                                input, invoke.Name,
 
2197
                                                methods: new[] { new MethodListWithDeclaringType(invoke.DeclaringType) { invoke } },
 
2198
                                                typeArguments: EmptyList<IType>.Instance
 
2199
                                        );
 
2200
                                }
 
2201
                                return Convert(input, type);
 
2202
                        }
 
2203
                        OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
 
2204
                        MemberLookup lookup = CreateMemberLookup();
 
2205
                        var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null);
 
2206
                        foreach (IMethod ctor in type.GetConstructors()) {
 
2207
                                if (lookup.IsAccessible(ctor, allowProtectedAccess)) {
 
2208
                                        var orErrors = or.AddCandidate(ctor);
 
2209
                                        if (allApplicable != null && OverloadResolution.IsApplicable(orErrors))
 
2210
                                                allApplicable.Add(ctor);
 
2211
                                }
 
2212
                                else
 
2213
                                        or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible);
 
2214
                        }
 
2215
 
 
2216
                        if (allApplicable != null && allApplicable.Count > 1) {
 
2217
                                // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor.
 
2218
                                return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, AddArgumentNamesIfNecessary(arguments, argumentNames), initializerStatements);
 
2219
                        }
 
2220
 
 
2221
                        if (or.BestCandidate != null) {
 
2222
                                return or.CreateResolveResult(null, initializerStatements);
 
2223
                        } else {
 
2224
                                return new ErrorResolveResult(type);
 
2225
                        }
 
2226
                }
 
2227
                #endregion
 
2228
                
 
2229
                #region ResolveSizeOf
 
2230
                /// <summary>
 
2231
                /// Resolves 'sizeof(type)'.
 
2232
                /// </summary>
 
2233
                public ResolveResult ResolveSizeOf(IType type)
 
2234
                {
 
2235
                        IType int32 = compilation.FindType(KnownTypeCode.Int32);
 
2236
                        int? size = null;
 
2237
                        var typeForConstant = (type.Kind == TypeKind.Enum) ? type.GetDefinition().EnumUnderlyingType : type;
 
2238
 
 
2239
                        switch (ReflectionHelper.GetTypeCode(typeForConstant)) {
 
2240
                                case TypeCode.Boolean:
 
2241
                                case TypeCode.SByte:
 
2242
                                case TypeCode.Byte:
 
2243
                                        size = 1;
 
2244
                                        break;
 
2245
                                case TypeCode.Char:
 
2246
                                case TypeCode.Int16:
 
2247
                                case TypeCode.UInt16:
 
2248
                                        size = 2;
 
2249
                                        break;
 
2250
                                case TypeCode.Int32:
 
2251
                                case TypeCode.UInt32:
 
2252
                                case TypeCode.Single:
 
2253
                                        size = 4;
 
2254
                                        break;
 
2255
                                case TypeCode.Int64:
 
2256
                                case TypeCode.UInt64:
 
2257
                                case TypeCode.Double:
 
2258
                                        size = 8;
 
2259
                                        break;
 
2260
                        }
 
2261
                        return new SizeOfResolveResult(int32, type, size);
 
2262
                }
 
2263
                #endregion
 
2264
                
 
2265
                #region Resolve This/Base Reference
 
2266
                /// <summary>
 
2267
                /// Resolves 'this'.
 
2268
                /// </summary>
 
2269
                public ResolveResult ResolveThisReference()
 
2270
                {
 
2271
                        ITypeDefinition t = CurrentTypeDefinition;
 
2272
                        if (t != null) {
 
2273
                                if (t.TypeParameterCount != 0) {
 
2274
                                        // Self-parameterize the type
 
2275
                                        return new ThisResolveResult(new ParameterizedType(t, t.TypeParameters));
 
2276
                                } else {
 
2277
                                        return new ThisResolveResult(t);
 
2278
                                }
 
2279
                        }
 
2280
                        return ErrorResult;
 
2281
                }
 
2282
                
 
2283
                /// <summary>
 
2284
                /// Resolves 'base'.
 
2285
                /// </summary>
 
2286
                public ResolveResult ResolveBaseReference()
 
2287
                {
 
2288
                        ITypeDefinition t = CurrentTypeDefinition;
 
2289
                        if (t != null) {
 
2290
                                foreach (IType baseType in t.DirectBaseTypes) {
 
2291
                                        if (baseType.Kind != TypeKind.Unknown && baseType.Kind != TypeKind.Interface) {
 
2292
                                                return new ThisResolveResult(baseType, causesNonVirtualInvocation: true);
 
2293
                                        }
 
2294
                                }
 
2295
                        }
 
2296
                        return ErrorResult;
 
2297
                }
 
2298
                #endregion
 
2299
                
 
2300
                #region ResolveConditional
 
2301
                /// <summary>
 
2302
                /// Converts the input to <c>bool</c> using the rules for boolean expressions.
 
2303
                /// That is, <c>operator true</c> is used if a regular conversion to <c>bool</c> is not possible.
 
2304
                /// </summary>
 
2305
                public ResolveResult ResolveCondition(ResolveResult input)
 
2306
                {
 
2307
                        if (input == null)
 
2308
                                throw new ArgumentNullException("input");
 
2309
                        IType boolean = compilation.FindType(KnownTypeCode.Boolean);
 
2310
                        Conversion c = conversions.ImplicitConversion(input, boolean);
 
2311
                        if (!c.IsValid) {
 
2312
                                var opTrue = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_True").FirstOrDefault();
 
2313
                                if (opTrue != null) {
 
2314
                                        c = Conversion.UserDefinedConversion(opTrue, isImplicit: true, conversionBeforeUserDefinedOperator: Conversion.None, conversionAfterUserDefinedOperator: Conversion.None);
 
2315
                                }
 
2316
                        }
 
2317
                        return Convert(input, boolean, c);
 
2318
                }
 
2319
                
 
2320
                /// <summary>
 
2321
                /// Converts the negated input to <c>bool</c> using the rules for boolean expressions.
 
2322
                /// Computes <c>!(bool)input</c> if the implicit cast to bool is valid; otherwise
 
2323
                /// computes <c>input.operator false()</c>.
 
2324
                /// </summary>
 
2325
                public ResolveResult ResolveConditionFalse(ResolveResult input)
 
2326
                {
 
2327
                        if (input == null)
 
2328
                                throw new ArgumentNullException("input");
 
2329
                        IType boolean = compilation.FindType(KnownTypeCode.Boolean);
 
2330
                        Conversion c = conversions.ImplicitConversion(input, boolean);
 
2331
                        if (!c.IsValid) {
 
2332
                                var opFalse = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_False").FirstOrDefault();
 
2333
                                if (opFalse != null) {
 
2334
                                        c = Conversion.UserDefinedConversion(opFalse, isImplicit: true, conversionBeforeUserDefinedOperator: Conversion.None, conversionAfterUserDefinedOperator: Conversion.None);
 
2335
                                        return Convert(input, boolean, c);
 
2336
                                }
 
2337
                        }
 
2338
                        return ResolveUnaryOperator(UnaryOperatorType.Not, Convert(input, boolean, c));
 
2339
                }
 
2340
                
 
2341
                public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression)
 
2342
                {
 
2343
                        // C# 4.0 spec Ā§7.14: Conditional operator
 
2344
                        
 
2345
                        bool isValid;
 
2346
                        IType resultType;
 
2347
                        if (trueExpression.Type.Kind == TypeKind.Dynamic || falseExpression.Type.Kind == TypeKind.Dynamic) {
 
2348
                                resultType = SpecialType.Dynamic;
 
2349
                                isValid = TryConvert(ref trueExpression, resultType) & TryConvert(ref falseExpression, resultType);
 
2350
                        } else if (HasType(trueExpression) && HasType(falseExpression)) {
 
2351
                                Conversion t2f = conversions.ImplicitConversion(trueExpression, falseExpression.Type);
 
2352
                                Conversion f2t = conversions.ImplicitConversion(falseExpression, trueExpression.Type);
 
2353
                                // The operator is valid:
 
2354
                                // a) if there's a conversion in one direction but not the other
 
2355
                                // b) if there are conversions in both directions, and the types are equivalent
 
2356
                                if (IsBetterConditionalConversion(t2f, f2t)) {
 
2357
                                        resultType = falseExpression.Type;
 
2358
                                        isValid = true;
 
2359
                                        trueExpression = Convert(trueExpression, resultType, t2f);
 
2360
                                } else if (IsBetterConditionalConversion(f2t, t2f)) {
 
2361
                                        resultType = trueExpression.Type;
 
2362
                                        isValid = true;
 
2363
                                        falseExpression = Convert(falseExpression, resultType, f2t);
 
2364
                                } else {
 
2365
                                        resultType = trueExpression.Type;
 
2366
                                        isValid = trueExpression.Type.Equals(falseExpression.Type);
 
2367
                                }
 
2368
                        } else if (HasType(trueExpression)) {
 
2369
                                resultType = trueExpression.Type;
 
2370
                                isValid = TryConvert(ref falseExpression, resultType);
 
2371
                        } else if (HasType(falseExpression)) {
 
2372
                                resultType = falseExpression.Type;
 
2373
                                isValid = TryConvert(ref trueExpression, resultType);
 
2374
                        } else {
 
2375
                                return ErrorResult;
 
2376
                        }
 
2377
                        condition = ResolveCondition(condition);
 
2378
                        if (isValid) {
 
2379
                                if (condition.IsCompileTimeConstant && trueExpression.IsCompileTimeConstant && falseExpression.IsCompileTimeConstant) {
 
2380
                                        bool? val = condition.ConstantValue as bool?;
 
2381
                                        if (val == true)
 
2382
                                                return trueExpression;
 
2383
                                        else if (val == false)
 
2384
                                                return falseExpression;
 
2385
                                }
 
2386
                                return new OperatorResolveResult(resultType, System.Linq.Expressions.ExpressionType.Conditional,
 
2387
                                                                 condition, trueExpression, falseExpression);
 
2388
                        } else {
 
2389
                                return new ErrorResolveResult(resultType);
 
2390
                        }
 
2391
                }
 
2392
                
 
2393
                bool IsBetterConditionalConversion(Conversion c1, Conversion c2)
 
2394
                {
 
2395
                        // Valid is better than ImplicitConstantExpressionConversion is better than invalid
 
2396
                        if (!c1.IsValid)
 
2397
                                return false;
 
2398
                        if (c1 != Conversion.ImplicitConstantExpressionConversion && c2 == Conversion.ImplicitConstantExpressionConversion)
 
2399
                                return true;
 
2400
                        return !c2.IsValid;
 
2401
                }
 
2402
                
 
2403
                bool HasType(ResolveResult r)
 
2404
                {
 
2405
                        return r.Type.Kind != TypeKind.Unknown && r.Type.Kind != TypeKind.Null;
 
2406
                }
 
2407
                #endregion
 
2408
                
 
2409
                #region ResolvePrimitive
 
2410
                public ResolveResult ResolvePrimitive(object value)
 
2411
                {
 
2412
                        if (value == null) {
 
2413
                                return new ResolveResult(SpecialType.NullType);
 
2414
                        } else {
 
2415
                                TypeCode typeCode = Type.GetTypeCode(value.GetType());
 
2416
                                IType type = compilation.FindType(typeCode);
 
2417
                                return new ConstantResolveResult(type, value);
 
2418
                        }
 
2419
                }
 
2420
                #endregion
 
2421
                
 
2422
                #region ResolveDefaultValue
 
2423
                public ResolveResult ResolveDefaultValue(IType type)
 
2424
                {
 
2425
                        return new ConstantResolveResult(type, GetDefaultValue(type));
 
2426
                }
 
2427
                
 
2428
                public static object GetDefaultValue(IType type)
 
2429
                {
 
2430
                        switch (ReflectionHelper.GetTypeCode(type)) {
 
2431
                                case TypeCode.Boolean:
 
2432
                                        return false;
 
2433
                                case TypeCode.Char:
 
2434
                                        return '\0';
 
2435
                                case TypeCode.SByte:
 
2436
                                        return (sbyte)0;
 
2437
                                case TypeCode.Byte:
 
2438
                                        return (byte)0;
 
2439
                                case TypeCode.Int16:
 
2440
                                        return (short)0;
 
2441
                                case TypeCode.UInt16:
 
2442
                                        return (ushort)0;
 
2443
                                case TypeCode.Int32:
 
2444
                                        return 0;
 
2445
                                case TypeCode.UInt32:
 
2446
                                        return 0U;
 
2447
                                case TypeCode.Int64:
 
2448
                                        return 0L;
 
2449
                                case TypeCode.UInt64:
 
2450
                                        return 0UL;
 
2451
                                case TypeCode.Single:
 
2452
                                        return 0f;
 
2453
                                case TypeCode.Double:
 
2454
                                        return 0.0;
 
2455
                                case TypeCode.Decimal:
 
2456
                                        return 0m;
 
2457
                                default:
 
2458
                                        return null;
 
2459
                        }
 
2460
                }
 
2461
                #endregion
 
2462
                
 
2463
                #region ResolveArrayCreation
 
2464
                /// <summary>
 
2465
                /// Resolves an array creation.
 
2466
                /// </summary>
 
2467
                /// <param name="elementType">
 
2468
                /// The array element type.
 
2469
                /// Pass null to resolve an implicitly-typed array creation.
 
2470
                /// </param>
 
2471
                /// <param name="sizeArguments">
 
2472
                /// The size arguments.
 
2473
                /// The length of this array will be used as the number of dimensions of the array type.
 
2474
                /// Negative values will be treated as errors.
 
2475
                /// </param>
 
2476
                /// <param name="initializerElements">
 
2477
                /// The initializer elements. May be null if no array initializer was specified.
 
2478
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2479
                /// </param>
 
2480
                public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int[] sizeArguments, ResolveResult[] initializerElements = null)
 
2481
                {
 
2482
                        ResolveResult[] sizeArgResults = new ResolveResult[sizeArguments.Length];
 
2483
                        for (int i = 0; i < sizeArguments.Length; i++) {
 
2484
                                if (sizeArguments[i] < 0)
 
2485
                                        sizeArgResults[i] = ErrorResolveResult.UnknownError;
 
2486
                                else
 
2487
                                        sizeArgResults[i] = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), sizeArguments[i]);
 
2488
                        }
 
2489
                        return ResolveArrayCreation(elementType, sizeArgResults, initializerElements);
 
2490
                }
 
2491
                
 
2492
                /// <summary>
 
2493
                /// Resolves an array creation.
 
2494
                /// </summary>
 
2495
                /// <param name="elementType">
 
2496
                /// The array element type.
 
2497
                /// Pass null to resolve an implicitly-typed array creation.
 
2498
                /// </param>
 
2499
                /// <param name="sizeArguments">
 
2500
                /// The size arguments.
 
2501
                /// The length of this array will be used as the number of dimensions of the array type.
 
2502
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2503
                /// </param>
 
2504
                /// <param name="initializerElements">
 
2505
                /// The initializer elements. May be null if no array initializer was specified.
 
2506
                /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 
2507
                /// </param>
 
2508
                public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, ResolveResult[] sizeArguments, ResolveResult[] initializerElements = null)
 
2509
                {
 
2510
                        int dimensions = sizeArguments.Length;
 
2511
                        if (dimensions == 0)
 
2512
                                throw new ArgumentException("sizeArguments.Length must not be 0");
 
2513
                        if (elementType == null) {
 
2514
                                TypeInference typeInference = new TypeInference(compilation, conversions);
 
2515
                                bool success;
 
2516
                                elementType = typeInference.GetBestCommonType(initializerElements, out success);
 
2517
                        }
 
2518
                        IType arrayType = new ArrayType(compilation, elementType, dimensions);
 
2519
                        
 
2520
                        AdjustArrayAccessArguments(sizeArguments);
 
2521
                        
 
2522
                        if (initializerElements != null) {
 
2523
                                for (int i = 0; i < initializerElements.Length; i++) {
 
2524
                                        initializerElements[i] = Convert(initializerElements[i], elementType);
 
2525
                                }
 
2526
                        }
 
2527
                        return new ArrayCreateResolveResult(arrayType, sizeArguments, initializerElements);
 
2528
                }
 
2529
                #endregion
 
2530
                
 
2531
                public ResolveResult ResolveTypeOf(IType referencedType)
 
2532
                {
 
2533
                        return new TypeOfResolveResult(compilation.FindType(KnownTypeCode.Type), referencedType);
 
2534
                }
 
2535
                
 
2536
                #region ResolveAssignment
 
2537
                public ResolveResult ResolveAssignment(AssignmentOperatorType op, ResolveResult lhs, ResolveResult rhs)
 
2538
                {
 
2539
                        var linqOp = AssignmentExpression.GetLinqNodeType(op, this.CheckForOverflow);
 
2540
                        var bop = AssignmentExpression.GetCorrespondingBinaryOperator(op);
 
2541
                        if (bop == null) {
 
2542
                                return new OperatorResolveResult(lhs.Type, linqOp, lhs, this.Convert(rhs, lhs.Type));
 
2543
                        }
 
2544
                        ResolveResult bopResult = ResolveBinaryOperator(bop.Value, lhs, rhs);
 
2545
                        OperatorResolveResult opResult = bopResult as OperatorResolveResult;
 
2546
                        if (opResult == null || opResult.Operands.Count != 2)
 
2547
                                return bopResult;
 
2548
                        return new OperatorResolveResult(lhs.Type, linqOp, opResult.UserDefinedOperatorMethod, opResult.IsLiftedOperator,
 
2549
                                                         new [] { lhs, opResult.Operands[1] });
 
2550
                }
 
2551
                #endregion
 
2552
        }
 
2553
}