mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							2512 lines
						
					
					
						
							101 KiB
						
					
					
				
			
		
		
	
	
							2512 lines
						
					
					
						
							101 KiB
						
					
					
				// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team | 
						|
//  | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this | 
						|
// software and associated documentation files (the "Software"), to deal in the Software | 
						|
// without restriction, including without limitation the rights to use, copy, modify, merge, | 
						|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | 
						|
// to whom the Software is furnished to do so, subject to the following conditions: | 
						|
//  | 
						|
// The above copyright notice and this permission notice shall be included in all copies or | 
						|
// substantial portions of the Software. | 
						|
//  | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | 
						|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | 
						|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | 
						|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | 
						|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
						|
// DEALINGS IN THE SOFTWARE. | 
						|
 | 
						|
using System; | 
						|
using System.Collections.Generic; | 
						|
using System.Collections.Immutable; | 
						|
using System.Diagnostics; | 
						|
using System.Linq; | 
						|
using ICSharpCode.Decompiler.CSharp.Syntax; | 
						|
using ICSharpCode.Decompiler.CSharp.TypeSystem; | 
						|
using ICSharpCode.Decompiler.Semantics; | 
						|
using ICSharpCode.Decompiler.TypeSystem; | 
						|
using ICSharpCode.Decompiler.TypeSystem.Implementation; | 
						|
using ICSharpCode.Decompiler.Util; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.CSharp.Resolver | 
						|
{ | 
						|
	/// <summary> | 
						|
	/// Contains the main resolver logic. | 
						|
	/// </summary> | 
						|
	/// <remarks> | 
						|
	/// This class is thread-safe. | 
						|
	/// </remarks> | 
						|
	public class CSharpResolver : ICodeContext | 
						|
	{ | 
						|
		static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError; | 
						|
		readonly ICompilation compilation; | 
						|
		internal readonly CSharpConversions conversions; | 
						|
		readonly CSharpTypeResolveContext context; | 
						|
		readonly bool checkForOverflow; | 
						|
		readonly bool isWithinLambdaExpression; | 
						|
		 | 
						|
		#region Constructor | 
						|
		public CSharpResolver(ICompilation compilation) | 
						|
		{ | 
						|
			if (compilation == null) | 
						|
				throw new ArgumentNullException("compilation"); | 
						|
			this.compilation = compilation; | 
						|
			this.conversions = CSharpConversions.Get(compilation); | 
						|
			this.context = new CSharpTypeResolveContext(compilation.MainAssembly); | 
						|
		} | 
						|
		 | 
						|
		public CSharpResolver(CSharpTypeResolveContext context) | 
						|
		{ | 
						|
			if (context == null) | 
						|
				throw new ArgumentNullException("context"); | 
						|
			this.compilation = context.Compilation; | 
						|
			this.conversions = CSharpConversions.Get(compilation); | 
						|
			this.context = context; | 
						|
			if (context.CurrentTypeDefinition != null) | 
						|
				currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition); | 
						|
		} | 
						|
		 | 
						|
		private CSharpResolver(ICompilation compilation, CSharpConversions conversions, CSharpTypeResolveContext context, bool checkForOverflow, bool isWithinLambdaExpression, TypeDefinitionCache currentTypeDefinitionCache, ImmutableStack<IVariable> localVariableStack, ObjectInitializerContext objectInitializerStack) | 
						|
		{ | 
						|
			this.compilation = compilation; | 
						|
			this.conversions = conversions; | 
						|
			this.context = context; | 
						|
			this.checkForOverflow = checkForOverflow; | 
						|
			this.isWithinLambdaExpression = isWithinLambdaExpression; | 
						|
			this.currentTypeDefinitionCache = currentTypeDefinitionCache; | 
						|
			this.localVariableStack = localVariableStack; | 
						|
			this.objectInitializerStack = objectInitializerStack; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Properties | 
						|
		/// <summary> | 
						|
		/// Gets the compilation used by the resolver. | 
						|
		/// </summary> | 
						|
		public ICompilation Compilation { | 
						|
			get { return compilation; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the current type resolve context. | 
						|
		/// </summary> | 
						|
		public CSharpTypeResolveContext CurrentTypeResolveContext { | 
						|
			get { return context; } | 
						|
		} | 
						|
 | 
						|
		IAssembly ITypeResolveContext.CurrentAssembly { | 
						|
			get { return context.CurrentAssembly; } | 
						|
		} | 
						|
		 | 
						|
		CSharpResolver WithContext(CSharpTypeResolveContext newContext) | 
						|
		{ | 
						|
			return new CSharpResolver(compilation, conversions, newContext, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets whether the current context is <c>checked</c>. | 
						|
		/// </summary> | 
						|
		public bool CheckForOverflow { | 
						|
			get { return checkForOverflow; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Sets whether the current context is <c>checked</c>. | 
						|
		/// </summary> | 
						|
		public CSharpResolver WithCheckForOverflow(bool checkForOverflow) | 
						|
		{ | 
						|
			if (checkForOverflow == this.checkForOverflow) | 
						|
				return this; | 
						|
			return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets whether the resolver is currently within a lambda expression or anonymous method. | 
						|
		/// </summary> | 
						|
		public bool IsWithinLambdaExpression { | 
						|
			get { return isWithinLambdaExpression; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Sets whether the resolver is currently within a lambda expression. | 
						|
		/// </summary> | 
						|
		public CSharpResolver WithIsWithinLambdaExpression(bool isWithinLambdaExpression) | 
						|
		{ | 
						|
			return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the current member definition that is used to look up identifiers as parameters | 
						|
		/// or type parameters. | 
						|
		/// </summary> | 
						|
		public IMember CurrentMember { | 
						|
			get { return context.CurrentMember; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Sets the current member definition. | 
						|
		/// </summary> | 
						|
		/// <remarks>Don't forget to also set CurrentTypeDefinition when setting CurrentMember; | 
						|
		/// setting one of the properties does not automatically set the other.</remarks> | 
						|
		public CSharpResolver WithCurrentMember(IMember member) | 
						|
		{ | 
						|
			return WithContext(context.WithCurrentMember(member)); | 
						|
		} | 
						|
		 | 
						|
		ITypeResolveContext ITypeResolveContext.WithCurrentMember(IMember member) | 
						|
		{ | 
						|
			return WithCurrentMember(member); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the current using scope that is used to look up identifiers as class names. | 
						|
		/// </summary> | 
						|
		public ResolvedUsingScope CurrentUsingScope { | 
						|
			get { return context.CurrentUsingScope; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Sets the current using scope that is used to look up identifiers as class names. | 
						|
		/// </summary> | 
						|
		public CSharpResolver WithCurrentUsingScope(ResolvedUsingScope usingScope) | 
						|
		{ | 
						|
			return WithContext(context.WithUsingScope(usingScope)); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Per-CurrentTypeDefinition Cache | 
						|
		readonly TypeDefinitionCache currentTypeDefinitionCache; | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the current type definition. | 
						|
		/// </summary> | 
						|
		public ITypeDefinition CurrentTypeDefinition { | 
						|
			get { return context.CurrentTypeDefinition; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Sets the current type definition. | 
						|
		/// </summary> | 
						|
		public CSharpResolver WithCurrentTypeDefinition(ITypeDefinition typeDefinition) | 
						|
		{ | 
						|
			if (this.CurrentTypeDefinition == typeDefinition) | 
						|
				return this; | 
						|
			 | 
						|
			TypeDefinitionCache newTypeDefinitionCache; | 
						|
			if (typeDefinition != null) | 
						|
				newTypeDefinitionCache = new TypeDefinitionCache(typeDefinition); | 
						|
			else | 
						|
				newTypeDefinitionCache = null; | 
						|
			 | 
						|
			return new CSharpResolver(compilation, conversions, context.WithCurrentTypeDefinition(typeDefinition), | 
						|
			                          checkForOverflow, isWithinLambdaExpression, newTypeDefinitionCache, localVariableStack, objectInitializerStack); | 
						|
		} | 
						|
		 | 
						|
		ITypeResolveContext ITypeResolveContext.WithCurrentTypeDefinition(ITypeDefinition typeDefinition) | 
						|
		{ | 
						|
			return WithCurrentTypeDefinition(typeDefinition); | 
						|
		} | 
						|
		 | 
						|
		sealed class TypeDefinitionCache | 
						|
		{ | 
						|
			public readonly ITypeDefinition TypeDefinition; | 
						|
			public readonly Dictionary<string, ResolveResult> SimpleNameLookupCacheExpression = new Dictionary<string, ResolveResult>(); | 
						|
			public readonly Dictionary<string, ResolveResult> SimpleNameLookupCacheInvocationTarget = new Dictionary<string, ResolveResult>(); | 
						|
			public readonly Dictionary<string, ResolveResult> SimpleTypeLookupCache = new Dictionary<string, ResolveResult>(); | 
						|
			 | 
						|
			public TypeDefinitionCache(ITypeDefinition typeDefinition) | 
						|
			{ | 
						|
				this.TypeDefinition = typeDefinition; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Local Variable Management | 
						|
		 | 
						|
		// We store the local variables in an immutable stack. | 
						|
		// The beginning of a block is marked by a null entry. | 
						|
		 | 
						|
		// This data structure is used to allow efficient cloning of the resolver with its local variable context. | 
						|
		readonly ImmutableStack<IVariable> localVariableStack = ImmutableStack<IVariable>.Empty; | 
						|
		 | 
						|
		CSharpResolver WithLocalVariableStack(ImmutableStack<IVariable> stack) | 
						|
		{ | 
						|
			return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, stack, objectInitializerStack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Opens a new scope for local variables. | 
						|
		/// </summary> | 
						|
		public CSharpResolver PushBlock() | 
						|
		{ | 
						|
			return WithLocalVariableStack(localVariableStack.Push(null)); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Closes the current scope for local variables; removing all variables in that scope. | 
						|
		/// </summary> | 
						|
		public CSharpResolver PopBlock() | 
						|
		{ | 
						|
			var stack = localVariableStack; | 
						|
			IVariable removedVar; | 
						|
			do { | 
						|
				removedVar = stack.Peek(); | 
						|
				stack = stack.Pop(); | 
						|
			} while (removedVar != null); | 
						|
			return WithLocalVariableStack(stack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Adds a new variable or lambda parameter to the current block. | 
						|
		/// </summary> | 
						|
		public CSharpResolver AddVariable(IVariable variable) | 
						|
		{ | 
						|
			if (variable == null) | 
						|
				throw new ArgumentNullException("variable"); | 
						|
			return WithLocalVariableStack(localVariableStack.Push(variable)); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Removes the variable that was just added. | 
						|
		/// </summary> | 
						|
		public CSharpResolver PopLastVariable() | 
						|
		{ | 
						|
			if (localVariableStack.Peek() == null) | 
						|
				throw new InvalidOperationException("There is no variable within the current block."); | 
						|
			return WithLocalVariableStack(localVariableStack.Pop()); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets all currently visible local variables and lambda parameters. | 
						|
		/// Does not include method parameters. | 
						|
		/// </summary> | 
						|
		public IEnumerable<IVariable> LocalVariables { | 
						|
			get { | 
						|
				return localVariableStack.Where(v => v != null); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Object Initializer Context | 
						|
		sealed class ObjectInitializerContext | 
						|
		{ | 
						|
			internal readonly ResolveResult initializedObject; | 
						|
			internal readonly ObjectInitializerContext prev; | 
						|
			 | 
						|
			public ObjectInitializerContext(ResolveResult initializedObject, CSharpResolver.ObjectInitializerContext prev) | 
						|
			{ | 
						|
				this.initializedObject = initializedObject; | 
						|
				this.prev = prev; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		readonly ObjectInitializerContext objectInitializerStack; | 
						|
		 | 
						|
		CSharpResolver WithObjectInitializerStack(ObjectInitializerContext stack) | 
						|
		{ | 
						|
			return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, stack); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Pushes the type of the object that is currently being initialized. | 
						|
		/// </summary> | 
						|
		public CSharpResolver PushObjectInitializer(ResolveResult initializedObject) | 
						|
		{ | 
						|
			if (initializedObject == null) | 
						|
				throw new ArgumentNullException("initializedObject"); | 
						|
			return WithObjectInitializerStack(new ObjectInitializerContext(initializedObject, objectInitializerStack)); | 
						|
		} | 
						|
		 | 
						|
		public CSharpResolver PopObjectInitializer() | 
						|
		{ | 
						|
			if (objectInitializerStack == null) | 
						|
				throw new InvalidOperationException(); | 
						|
			return WithObjectInitializerStack(objectInitializerStack.prev); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets whether this context is within an object initializer. | 
						|
		/// </summary> | 
						|
		public bool IsInObjectInitializer { | 
						|
			get { return objectInitializerStack != null; } | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the current object initializer. This usually is an <see cref="InitializedObjectResolveResult"/> | 
						|
		/// or (for nested initializers) a semantic tree based on an <see cref="InitializedObjectResolveResult"/>. | 
						|
		/// Returns ErrorResolveResult if there is no object initializer. | 
						|
		/// </summary> | 
						|
		public ResolveResult CurrentObjectInitializer { | 
						|
			get { | 
						|
				return objectInitializerStack != null ? objectInitializerStack.initializedObject : ErrorResult; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the type of the object currently being initialized. | 
						|
		/// Returns SharedTypes.Unknown if no object initializer is currently open (or if the object initializer | 
						|
		/// has unknown type). | 
						|
		/// </summary> | 
						|
		public IType CurrentObjectInitializerType { | 
						|
			get { return CurrentObjectInitializer.Type; } | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveUnaryOperator | 
						|
		#region ResolveUnaryOperator method | 
						|
		public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression) | 
						|
		{ | 
						|
			if (expression.Type.Kind == TypeKind.Dynamic) { | 
						|
				if (op == UnaryOperatorType.Await) { | 
						|
					return new AwaitResolveResult(SpecialType.Dynamic, new DynamicInvocationResolveResult(new DynamicMemberResolveResult(expression, "GetAwaiter"), DynamicInvocationType.Invocation, EmptyList<ResolveResult>.Instance), SpecialType.Dynamic, null, null, null); | 
						|
				} | 
						|
				else { | 
						|
					return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression); | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			// C# 4.0 spec: §7.3.3 Unary operator overload resolution | 
						|
			string overloadableOperatorName = GetOverloadableOperatorName(op); | 
						|
			if (overloadableOperatorName == null) { | 
						|
				switch (op) { | 
						|
					case UnaryOperatorType.Dereference: | 
						|
						PointerType p = expression.Type as PointerType; | 
						|
						if (p != null) | 
						|
							return UnaryOperatorResolveResult(p.ElementType, op, expression); | 
						|
						else | 
						|
							return ErrorResult; | 
						|
					case UnaryOperatorType.AddressOf: | 
						|
						return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression); | 
						|
					case UnaryOperatorType.Await: { | 
						|
						ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); | 
						|
						ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0], argumentNames: null, allowOptionalParameters: false); | 
						|
 | 
						|
						var lookup = CreateMemberLookup(); | 
						|
						IMethod getResultMethod; | 
						|
						IType awaitResultType; | 
						|
						var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult; | 
						|
						if (getResultMethodGroup != null) { | 
						|
							var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions); | 
						|
							getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null; | 
						|
							awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType; | 
						|
						} | 
						|
						else { | 
						|
							getResultMethod = null; | 
						|
							awaitResultType = SpecialType.UnknownType; | 
						|
						} | 
						|
 | 
						|
						var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false); | 
						|
						var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null); | 
						|
						if (isCompletedProperty != null && (!isCompletedProperty.ReturnType.IsKnownType(KnownTypeCode.Boolean) || !isCompletedProperty.CanGet)) | 
						|
							isCompletedProperty = null; | 
						|
 | 
						|
						var interfaceOnCompleted = compilation.FindType(KnownTypeCode.INotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "OnCompleted"); | 
						|
						var interfaceUnsafeOnCompleted = compilation.FindType(KnownTypeCode.ICriticalNotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "UnsafeOnCompleted"); | 
						|
 | 
						|
						IMethod onCompletedMethod = null; | 
						|
						var candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceUnsafeOnCompleted)).ToList(); | 
						|
						if (candidates.Count == 0) { | 
						|
							candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceOnCompleted)).ToList(); | 
						|
							if (candidates.Count == 1) | 
						|
								onCompletedMethod = candidates[0]; | 
						|
						} | 
						|
						else if (candidates.Count == 1) { | 
						|
							onCompletedMethod = candidates[0]; | 
						|
						} | 
						|
 | 
						|
						return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod); | 
						|
					} | 
						|
 | 
						|
					default: | 
						|
						return ErrorResolveResult.UnknownError; | 
						|
				} | 
						|
			} | 
						|
			// If the type is nullable, get the underlying type: | 
						|
			IType type = NullableType.GetUnderlyingType(expression.Type); | 
						|
			bool isNullable = NullableType.IsNullable(expression.Type); | 
						|
			 | 
						|
			// the operator is overloadable: | 
						|
			OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { expression }); | 
						|
			foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) { | 
						|
				userDefinedOperatorOR.AddCandidate(candidate); | 
						|
			} | 
						|
			if (userDefinedOperatorOR.FoundApplicableCandidate) { | 
						|
				return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow)); | 
						|
			} | 
						|
			 | 
						|
			expression = UnaryNumericPromotion(op, ref type, isNullable, expression); | 
						|
			CSharpOperators.OperatorMethod[] methodGroup; | 
						|
			CSharpOperators operators = CSharpOperators.Get(compilation); | 
						|
			switch (op) { | 
						|
				case UnaryOperatorType.Increment: | 
						|
				case UnaryOperatorType.Decrement: | 
						|
				case UnaryOperatorType.PostIncrement: | 
						|
				case UnaryOperatorType.PostDecrement: | 
						|
					// C# 4.0 spec: §7.6.9 Postfix increment and decrement operators | 
						|
					// C# 4.0 spec: §7.7.5 Prefix increment and decrement operators | 
						|
					TypeCode code = ReflectionHelper.GetTypeCode(type); | 
						|
					if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer) | 
						|
						return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable); | 
						|
					else | 
						|
						return new ErrorResolveResult(expression.Type); | 
						|
				case UnaryOperatorType.Plus: | 
						|
					methodGroup = operators.UnaryPlusOperators; | 
						|
					break; | 
						|
				case UnaryOperatorType.Minus: | 
						|
					methodGroup = CheckForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators; | 
						|
					break; | 
						|
				case UnaryOperatorType.Not: | 
						|
					methodGroup = operators.LogicalNegationOperators; | 
						|
					break; | 
						|
				case UnaryOperatorType.BitNot: | 
						|
					if (type.Kind == TypeKind.Enum) { | 
						|
						if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) { | 
						|
							// evaluate as (E)(~(U)x); | 
						|
							var U = compilation.FindType(expression.ConstantValue.GetType()); | 
						|
							var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue); | 
						|
							var rr = ResolveUnaryOperator(op, unpackedEnum); | 
						|
							rr = WithCheckForOverflow(false).ResolveCast(type, rr); | 
						|
							if (rr.IsCompileTimeConstant) | 
						|
								return rr; | 
						|
						}  | 
						|
						return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable); | 
						|
					} else { | 
						|
						methodGroup = operators.BitwiseComplementOperators; | 
						|
						break; | 
						|
					} | 
						|
				default: | 
						|
					throw new InvalidOperationException(); | 
						|
			} | 
						|
			OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { expression }); | 
						|
			foreach (var candidate in methodGroup) { | 
						|
				builtinOperatorOR.AddCandidate(candidate); | 
						|
			} | 
						|
			CSharpOperators.UnaryOperatorMethod m = (CSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate; | 
						|
			IType resultType = m.ReturnType; | 
						|
			if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) { | 
						|
				if (userDefinedOperatorOR.BestCandidate != null) { | 
						|
					// If there are any user-defined operators, prefer those over the built-in operators. | 
						|
					// It'll be a more informative error. | 
						|
					return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow)); | 
						|
				} else if (builtinOperatorOR.BestCandidateAmbiguousWith != null) { | 
						|
					// If the best candidate is ambiguous, just use the input type instead | 
						|
					// of picking one of the ambiguous overloads. | 
						|
					return new ErrorResolveResult(expression.Type); | 
						|
				} else { | 
						|
					return new ErrorResolveResult(resultType); | 
						|
				} | 
						|
			} else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) { | 
						|
				object val; | 
						|
				try { | 
						|
					val = m.Invoke(this, expression.ConstantValue); | 
						|
				} catch (ArithmeticException) { | 
						|
					return new ErrorResolveResult(resultType); | 
						|
				} | 
						|
				return new ConstantResolveResult(resultType, val); | 
						|
			} else { | 
						|
				expression = Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]); | 
						|
				return UnaryOperatorResolveResult(resultType, op, expression, | 
						|
				                                  builtinOperatorOR.BestCandidate is ILiftedOperator); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		OperatorResolveResult UnaryOperatorResolveResult(IType resultType, UnaryOperatorType op, ResolveResult expression, bool isLifted = false) | 
						|
		{ | 
						|
			return new OperatorResolveResult( | 
						|
				resultType, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow), | 
						|
				null, isLifted, new[] { expression }); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region UnaryNumericPromotion | 
						|
		ResolveResult UnaryNumericPromotion(UnaryOperatorType op, ref IType type, bool isNullable, ResolveResult expression) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.3.6.1 | 
						|
			TypeCode code = ReflectionHelper.GetTypeCode(type); | 
						|
			if (isNullable && type.Kind == TypeKind.Null) | 
						|
				code = TypeCode.SByte; // cause promotion of null to int32 | 
						|
			switch (op) { | 
						|
				case UnaryOperatorType.Minus: | 
						|
					if (code == TypeCode.UInt32) { | 
						|
						type = compilation.FindType(KnownTypeCode.Int64); | 
						|
						return Convert(expression, MakeNullable(type, isNullable), | 
						|
						               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion); | 
						|
					} | 
						|
					goto case UnaryOperatorType.Plus; | 
						|
				case UnaryOperatorType.Plus: | 
						|
				case UnaryOperatorType.BitNot: | 
						|
					if (code >= TypeCode.Char && code <= TypeCode.UInt16) { | 
						|
						type = compilation.FindType(KnownTypeCode.Int32); | 
						|
						return Convert(expression, MakeNullable(type, isNullable), | 
						|
						               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion); | 
						|
					} | 
						|
					break; | 
						|
			} | 
						|
			return expression; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region GetOverloadableOperatorName | 
						|
		static string GetOverloadableOperatorName(UnaryOperatorType op) | 
						|
		{ | 
						|
			switch (op) { | 
						|
				case UnaryOperatorType.Not: | 
						|
					return "op_LogicalNot"; | 
						|
				case UnaryOperatorType.BitNot: | 
						|
					return "op_OnesComplement"; | 
						|
				case UnaryOperatorType.Minus: | 
						|
					return "op_UnaryNegation"; | 
						|
				case UnaryOperatorType.Plus: | 
						|
					return "op_UnaryPlus"; | 
						|
				case UnaryOperatorType.Increment: | 
						|
				case UnaryOperatorType.PostIncrement: | 
						|
					return "op_Increment"; | 
						|
				case UnaryOperatorType.Decrement: | 
						|
				case UnaryOperatorType.PostDecrement: | 
						|
					return "op_Decrement"; | 
						|
				default: | 
						|
					return null; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveBinaryOperator | 
						|
		#region ResolveBinaryOperator method | 
						|
		public ResolveResult ResolveBinaryOperator(BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			if (lhs.Type.Kind == TypeKind.Dynamic || rhs.Type.Kind == TypeKind.Dynamic) { | 
						|
				lhs = Convert(lhs, SpecialType.Dynamic); | 
						|
				rhs = Convert(rhs, SpecialType.Dynamic); | 
						|
				return BinaryOperatorResolveResult(SpecialType.Dynamic, lhs, op, rhs); | 
						|
			} | 
						|
			 | 
						|
			// C# 4.0 spec: §7.3.4 Binary operator overload resolution | 
						|
			string overloadableOperatorName = GetOverloadableOperatorName(op); | 
						|
			if (overloadableOperatorName == null) { | 
						|
				 | 
						|
				// Handle logical and/or exactly as bitwise and/or: | 
						|
				// - If the user overloads a bitwise operator, that implicitly creates the corresponding logical operator. | 
						|
				// - If both inputs are compile-time constants, it doesn't matter that we don't short-circuit. | 
						|
				// - If inputs aren't compile-time constants, we don't evaluate anything, so again it doesn't matter that we don't short-circuit | 
						|
				if (op == BinaryOperatorType.ConditionalAnd) { | 
						|
					overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseAnd); | 
						|
				} else if (op == BinaryOperatorType.ConditionalOr) { | 
						|
					overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseOr); | 
						|
				} else if (op == BinaryOperatorType.NullCoalescing) { | 
						|
					// null coalescing operator is not overloadable and needs to be handled separately | 
						|
					return ResolveNullCoalescingOperator(lhs, rhs); | 
						|
				} else { | 
						|
					return ErrorResolveResult.UnknownError; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			// If the type is nullable, get the underlying type: | 
						|
			bool isNullable = NullableType.IsNullable(lhs.Type) || NullableType.IsNullable(rhs.Type); | 
						|
			IType lhsType = NullableType.GetUnderlyingType(lhs.Type); | 
						|
			IType rhsType = NullableType.GetUnderlyingType(rhs.Type); | 
						|
			 | 
						|
			// the operator is overloadable: | 
						|
			OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { lhs, rhs }); | 
						|
			HashSet<IParameterizedMember> userOperatorCandidates = new HashSet<IParameterizedMember>(); | 
						|
			userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName)); | 
						|
			userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName)); | 
						|
			foreach (var candidate in userOperatorCandidates) { | 
						|
				userDefinedOperatorOR.AddCandidate(candidate); | 
						|
			} | 
						|
			if (userDefinedOperatorOR.FoundApplicableCandidate) { | 
						|
				return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow)); | 
						|
			} | 
						|
			 | 
						|
			if (lhsType.Kind == TypeKind.Null && rhsType.IsReferenceType == false | 
						|
			    || lhsType.IsReferenceType == false && rhsType.Kind == TypeKind.Null) | 
						|
			{ | 
						|
				isNullable = true; | 
						|
			} | 
						|
			if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight) { | 
						|
				// special case: the shift operators allow "var x = null << null", producing int?. | 
						|
				if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) | 
						|
					isNullable = true; | 
						|
				// for shift operators, do unary promotion independently on both arguments | 
						|
				lhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref lhsType, isNullable, lhs); | 
						|
				rhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref rhsType, isNullable, rhs); | 
						|
			} else { | 
						|
				bool allowNullableConstants = op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality; | 
						|
				if (!BinaryNumericPromotion(isNullable, ref lhs, ref rhs, allowNullableConstants)) | 
						|
					return new ErrorResolveResult(lhs.Type); | 
						|
			} | 
						|
			// re-read underlying types after numeric promotion | 
						|
			lhsType = NullableType.GetUnderlyingType(lhs.Type); | 
						|
			rhsType = NullableType.GetUnderlyingType(rhs.Type); | 
						|
			 | 
						|
			IEnumerable<CSharpOperators.OperatorMethod> methodGroup; | 
						|
			CSharpOperators operators = CSharpOperators.Get(compilation); | 
						|
			switch (op) { | 
						|
				case BinaryOperatorType.Multiply: | 
						|
					methodGroup = operators.MultiplicationOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.Divide: | 
						|
					methodGroup = operators.DivisionOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.Modulus: | 
						|
					methodGroup = operators.RemainderOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.Add: | 
						|
					methodGroup = operators.AdditionOperators; | 
						|
					{ | 
						|
						if (lhsType.Kind == TypeKind.Enum) { | 
						|
							// E operator +(E x, U y); | 
						|
							IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable); | 
						|
							if (TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs)) { | 
						|
								return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
						if (rhsType.Kind == TypeKind.Enum) { | 
						|
							// E operator +(U x, E y); | 
						|
							IType underlyingType = MakeNullable(GetEnumUnderlyingType(rhsType), isNullable); | 
						|
							if (TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs)) { | 
						|
								return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
						 | 
						|
						if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) { | 
						|
							return BinaryOperatorResolveResult(lhsType, lhs, op, rhs); | 
						|
						} else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) { | 
						|
							return BinaryOperatorResolveResult(rhsType, lhs, op, rhs); | 
						|
						} | 
						|
						 | 
						|
						if (lhsType is PointerType) { | 
						|
							methodGroup = new [] { | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int32), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt32), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int64), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt64) | 
						|
							}; | 
						|
						} else if (rhsType is PointerType) { | 
						|
							methodGroup = new [] { | 
						|
								PointerArithmeticOperator(rhsType, KnownTypeCode.Int32, rhsType), | 
						|
								PointerArithmeticOperator(rhsType, KnownTypeCode.UInt32, rhsType), | 
						|
								PointerArithmeticOperator(rhsType, KnownTypeCode.Int64, rhsType), | 
						|
								PointerArithmeticOperator(rhsType, KnownTypeCode.UInt64, rhsType) | 
						|
							}; | 
						|
						} | 
						|
						if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) | 
						|
							return new ErrorResolveResult(SpecialType.NullType); | 
						|
					} | 
						|
					break; | 
						|
				case BinaryOperatorType.Subtract: | 
						|
					methodGroup = operators.SubtractionOperators; | 
						|
					{ | 
						|
						if (lhsType.Kind == TypeKind.Enum) { | 
						|
							// U operator –(E x, E y); | 
						|
							if (TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs, allowConversionFromConstantZero: false)) { | 
						|
								return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs); | 
						|
							} | 
						|
 | 
						|
							// E operator –(E x, U y); | 
						|
							IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable); | 
						|
							if (TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs)) { | 
						|
								return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
						if (rhsType.Kind == TypeKind.Enum) { | 
						|
							// U operator –(E x, E y); | 
						|
							if (TryConvertEnum(ref lhs, rhs.Type, ref isNullable, ref rhs)) { | 
						|
								return HandleEnumSubtraction(isNullable, rhsType, lhs, rhs); | 
						|
							} | 
						|
 | 
						|
							// E operator -(U x, E y); | 
						|
							IType underlyingType = MakeNullable(GetEnumUnderlyingType(rhsType), isNullable); | 
						|
							if (TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs)) { | 
						|
								return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
						 | 
						|
						if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) { | 
						|
							return BinaryOperatorResolveResult(lhsType, lhs, op, rhs); | 
						|
						} else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) { | 
						|
							return BinaryOperatorResolveResult(rhsType, lhs, op, rhs); | 
						|
						} | 
						|
						 | 
						|
						if (lhsType is PointerType) { | 
						|
							if (rhsType is PointerType) { | 
						|
								IType int64 = compilation.FindType(KnownTypeCode.Int64); | 
						|
								if (lhsType.Equals(rhsType)) { | 
						|
									return BinaryOperatorResolveResult(int64, lhs, op, rhs); | 
						|
								} else { | 
						|
									return new ErrorResolveResult(int64); | 
						|
								} | 
						|
							} | 
						|
							methodGroup = new [] { | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int32), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt32), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int64), | 
						|
								PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt64) | 
						|
							}; | 
						|
						} | 
						|
						 | 
						|
						if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) | 
						|
							return new ErrorResolveResult(SpecialType.NullType); | 
						|
					} | 
						|
					break; | 
						|
				case BinaryOperatorType.ShiftLeft: | 
						|
					methodGroup = operators.ShiftLeftOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.ShiftRight: | 
						|
					methodGroup = operators.ShiftRightOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.Equality: | 
						|
				case BinaryOperatorType.InEquality: | 
						|
				case BinaryOperatorType.LessThan: | 
						|
				case BinaryOperatorType.GreaterThan: | 
						|
				case BinaryOperatorType.LessThanOrEqual: | 
						|
				case BinaryOperatorType.GreaterThanOrEqual: | 
						|
					{ | 
						|
						if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) { | 
						|
							// bool operator op(E x, E y); | 
						|
							return HandleEnumComparison(op, lhsType, isNullable, lhs, rhs); | 
						|
						} else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) { | 
						|
							// bool operator op(E x, E y); | 
						|
							return HandleEnumComparison(op, rhsType, isNullable, lhs, rhs); | 
						|
						} else if (lhsType is PointerType && rhsType is PointerType) { | 
						|
							return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs); | 
						|
						} | 
						|
						if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality) { | 
						|
							if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true) { | 
						|
								// If it's a reference comparison | 
						|
								if (op == BinaryOperatorType.Equality) | 
						|
									methodGroup = operators.ReferenceEqualityOperators; | 
						|
								else | 
						|
									methodGroup = operators.ReferenceInequalityOperators; | 
						|
								break; | 
						|
							} else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type) | 
						|
							           || IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null) { | 
						|
								// compare type parameter or nullable type with the null literal | 
						|
								return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs); | 
						|
							} | 
						|
						} | 
						|
						switch (op) { | 
						|
							case BinaryOperatorType.Equality: | 
						|
								methodGroup = operators.ValueEqualityOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.InEquality: | 
						|
								methodGroup = operators.ValueInequalityOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.LessThan: | 
						|
								methodGroup = operators.LessThanOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.GreaterThan: | 
						|
								methodGroup = operators.GreaterThanOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.LessThanOrEqual: | 
						|
								methodGroup = operators.LessThanOrEqualOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.GreaterThanOrEqual: | 
						|
								methodGroup = operators.GreaterThanOrEqualOperators; | 
						|
								break; | 
						|
							default: | 
						|
								throw new InvalidOperationException(); | 
						|
						} | 
						|
					} | 
						|
					break; | 
						|
				case BinaryOperatorType.BitwiseAnd: | 
						|
				case BinaryOperatorType.BitwiseOr: | 
						|
				case BinaryOperatorType.ExclusiveOr: | 
						|
					{ | 
						|
						if (lhsType.Kind == TypeKind.Enum) { | 
						|
							// bool operator op(E x, E y); | 
						|
							if (TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs)) { | 
						|
								return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
 | 
						|
						if (rhsType.Kind == TypeKind.Enum) { | 
						|
							// bool operator op(E x, E y); | 
						|
							if (TryConvertEnum (ref lhs, rhs.Type, ref isNullable, ref rhs)) { | 
						|
								return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs); | 
						|
							} | 
						|
						} | 
						|
						 | 
						|
						switch (op) { | 
						|
							case BinaryOperatorType.BitwiseAnd: | 
						|
								methodGroup = operators.BitwiseAndOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.BitwiseOr: | 
						|
								methodGroup = operators.BitwiseOrOperators; | 
						|
								break; | 
						|
							case BinaryOperatorType.ExclusiveOr: | 
						|
								methodGroup = operators.BitwiseXorOperators; | 
						|
								break; | 
						|
							default: | 
						|
								throw new InvalidOperationException(); | 
						|
						} | 
						|
					} | 
						|
					break; | 
						|
				case BinaryOperatorType.ConditionalAnd: | 
						|
					methodGroup = operators.LogicalAndOperators; | 
						|
					break; | 
						|
				case BinaryOperatorType.ConditionalOr: | 
						|
					methodGroup = operators.LogicalOrOperators; | 
						|
					break; | 
						|
				default: | 
						|
					throw new InvalidOperationException(); | 
						|
			} | 
						|
			OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { lhs, rhs }); | 
						|
			foreach (var candidate in methodGroup) { | 
						|
				builtinOperatorOR.AddCandidate(candidate); | 
						|
			} | 
						|
			CSharpOperators.BinaryOperatorMethod m = (CSharpOperators.BinaryOperatorMethod)builtinOperatorOR.BestCandidate; | 
						|
			IType resultType = m.ReturnType; | 
						|
			if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) { | 
						|
				// If there are any user-defined operators, prefer those over the built-in operators. | 
						|
				// It'll be a more informative error. | 
						|
				if (userDefinedOperatorOR.BestCandidate != null) | 
						|
					return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow)); | 
						|
				else | 
						|
					return new ErrorResolveResult(resultType); | 
						|
			} else if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) { | 
						|
				object val; | 
						|
				try { | 
						|
					val = m.Invoke(this, lhs.ConstantValue, rhs.ConstantValue); | 
						|
				} catch (ArithmeticException) { | 
						|
					return new ErrorResolveResult(resultType); | 
						|
				} | 
						|
				return new ConstantResolveResult(resultType, val); | 
						|
			} else { | 
						|
				lhs = Convert(lhs, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]); | 
						|
				rhs = Convert(rhs, m.Parameters[1].Type, builtinOperatorOR.ArgumentConversions[1]); | 
						|
				return BinaryOperatorResolveResult(resultType, lhs, op, rhs, | 
						|
				                                   builtinOperatorOR.BestCandidate is ILiftedOperator); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		bool IsNullableTypeOrNonValueType(IType type) | 
						|
		{ | 
						|
			return NullableType.IsNullable(type) || type.IsReferenceType != false; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult BinaryOperatorResolveResult(IType resultType, ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs, bool isLifted = false) | 
						|
		{ | 
						|
			return new OperatorResolveResult( | 
						|
				resultType, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow), | 
						|
				null, isLifted, new[] { lhs, rhs }); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Pointer arithmetic | 
						|
		CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, IType inputType1, KnownTypeCode inputType2) | 
						|
		{ | 
						|
			return PointerArithmeticOperator(resultType, inputType1, compilation.FindType(inputType2)); | 
						|
		} | 
						|
		 | 
						|
		CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, KnownTypeCode inputType1, IType inputType2) | 
						|
		{ | 
						|
			return PointerArithmeticOperator(resultType, compilation.FindType(inputType1), inputType2); | 
						|
		} | 
						|
		 | 
						|
		CSharpOperators.BinaryOperatorMethod PointerArithmeticOperator(IType resultType, IType inputType1, IType inputType2) | 
						|
		{ | 
						|
			return new CSharpOperators.BinaryOperatorMethod(compilation) { | 
						|
				ReturnType = resultType, | 
						|
				parameters = { | 
						|
					new DefaultParameter(inputType1, string.Empty), | 
						|
					new DefaultParameter(inputType2, string.Empty) | 
						|
				} | 
						|
			}; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Enum helper methods | 
						|
		IType GetEnumUnderlyingType(IType enumType) | 
						|
		{ | 
						|
			ITypeDefinition def = enumType.GetDefinition(); | 
						|
			return def != null ? def.EnumUnderlyingType : SpecialType.UnknownType; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Handle the case where an enum value is compared with another enum value | 
						|
		/// bool operator op(E x, E y); | 
						|
		/// </summary> | 
						|
		ResolveResult HandleEnumComparison(BinaryOperatorType op, IType enumType, bool isNullable, ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			// evaluate as ((U)x op (U)y) | 
						|
			IType elementType = GetEnumUnderlyingType(enumType); | 
						|
			if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable && elementType.Kind != TypeKind.Enum) { | 
						|
				var rr = ResolveBinaryOperator(op, ResolveCast(elementType, lhs), ResolveCast(elementType, rhs)); | 
						|
				if (rr.IsCompileTimeConstant) | 
						|
					return rr; | 
						|
			} | 
						|
			IType resultType = compilation.FindType(KnownTypeCode.Boolean); | 
						|
			return BinaryOperatorResolveResult(resultType, lhs, op, rhs, isNullable); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Handle the case where an enum value is subtracted from another enum value | 
						|
		/// U operator –(E x, E y); | 
						|
		/// </summary> | 
						|
		ResolveResult HandleEnumSubtraction(bool isNullable, IType enumType, ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			// evaluate as (U)((U)x – (U)y) | 
						|
			IType elementType = GetEnumUnderlyingType(enumType); | 
						|
			if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable && elementType.Kind != TypeKind.Enum) { | 
						|
				var rr = ResolveBinaryOperator(BinaryOperatorType.Subtract, ResolveCast(elementType, lhs), ResolveCast(elementType, rhs)); | 
						|
				rr = WithCheckForOverflow(false).ResolveCast(elementType, rr); | 
						|
				if (rr.IsCompileTimeConstant) | 
						|
					return rr; | 
						|
			} | 
						|
			IType resultType = MakeNullable(elementType, isNullable); | 
						|
			return BinaryOperatorResolveResult(resultType, lhs, BinaryOperatorType.Subtract, rhs, isNullable); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Handle the following enum operators: | 
						|
		/// E operator +(E x, U y); | 
						|
		/// E operator +(U x, E y); | 
						|
		/// E operator –(E x, U y); | 
						|
		/// E operator &(E x, E y); | 
						|
		/// E operator |(E x, E y); | 
						|
		/// E operator ^(E x, E y); | 
						|
		/// </summary> | 
						|
		ResolveResult HandleEnumOperator(bool isNullable, IType enumType, BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			// evaluate as (E)((U)x op (U)y) | 
						|
			if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) { | 
						|
				IType elementType = GetEnumUnderlyingType(enumType); | 
						|
				if (elementType.Kind != TypeKind.Enum) { | 
						|
					var rr = ResolveBinaryOperator(op, ResolveCast(elementType, lhs), ResolveCast(elementType, rhs)); | 
						|
					rr = WithCheckForOverflow(false).ResolveCast(enumType, rr); | 
						|
					if (rr.IsCompileTimeConstant) // only report result if it's a constant; use the regular OperatorResolveResult codepath otherwise | 
						|
						return rr; | 
						|
				} | 
						|
			} | 
						|
			IType resultType = MakeNullable(enumType, isNullable); | 
						|
			return BinaryOperatorResolveResult(resultType, lhs, op, rhs, isNullable); | 
						|
		} | 
						|
		 | 
						|
		IType MakeNullable(IType type, bool isNullable) | 
						|
		{ | 
						|
			if (isNullable) | 
						|
				return NullableType.Create(compilation, type); | 
						|
			else | 
						|
				return type; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region BinaryNumericPromotion | 
						|
		bool BinaryNumericPromotion(bool isNullable, ref ResolveResult lhs, ref ResolveResult rhs, bool allowNullableConstants) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.3.6.2 | 
						|
			TypeCode lhsCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(lhs.Type)); | 
						|
			TypeCode rhsCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(rhs.Type)); | 
						|
			// if one of the inputs is the null literal, promote that to the type of the other operand | 
						|
			if (isNullable && lhs.Type.Kind == TypeKind.Null && rhsCode >= TypeCode.Boolean && rhsCode <= TypeCode.Decimal) { | 
						|
				lhs = CastTo(rhsCode, isNullable, lhs, allowNullableConstants); | 
						|
				lhsCode = rhsCode; | 
						|
			} else if (isNullable && rhs.Type.Kind == TypeKind.Null && lhsCode >= TypeCode.Boolean && lhsCode <= TypeCode.Decimal) { | 
						|
				rhs = CastTo(lhsCode, isNullable, rhs, allowNullableConstants); | 
						|
				rhsCode = lhsCode; | 
						|
			} | 
						|
			bool bindingError = false; | 
						|
			if (lhsCode >= TypeCode.Char && lhsCode <= TypeCode.Decimal | 
						|
			    && rhsCode >= TypeCode.Char && rhsCode <= TypeCode.Decimal) | 
						|
			{ | 
						|
				TypeCode targetType; | 
						|
				if (lhsCode == TypeCode.Decimal || rhsCode == TypeCode.Decimal) { | 
						|
					targetType = TypeCode.Decimal; | 
						|
					bindingError = (lhsCode == TypeCode.Single || lhsCode == TypeCode.Double | 
						|
					                || rhsCode == TypeCode.Single || rhsCode == TypeCode.Double); | 
						|
				} else if (lhsCode == TypeCode.Double || rhsCode == TypeCode.Double) { | 
						|
					targetType = TypeCode.Double; | 
						|
				} else if (lhsCode == TypeCode.Single || rhsCode == TypeCode.Single) { | 
						|
					targetType = TypeCode.Single; | 
						|
				} else if (lhsCode == TypeCode.UInt64 || rhsCode == TypeCode.UInt64) { | 
						|
					targetType = TypeCode.UInt64; | 
						|
					bindingError = IsSigned(lhsCode, lhs) || IsSigned(rhsCode, rhs); | 
						|
				} else if (lhsCode == TypeCode.Int64 || rhsCode == TypeCode.Int64) { | 
						|
					targetType = TypeCode.Int64; | 
						|
				} else if (lhsCode == TypeCode.UInt32 || rhsCode == TypeCode.UInt32) { | 
						|
					targetType = (IsSigned(lhsCode, lhs) || IsSigned(rhsCode, rhs)) ? TypeCode.Int64 : TypeCode.UInt32; | 
						|
				} else { | 
						|
					targetType = TypeCode.Int32; | 
						|
				} | 
						|
				lhs = CastTo(targetType, isNullable, lhs, allowNullableConstants); | 
						|
				rhs = CastTo(targetType, isNullable, rhs, allowNullableConstants); | 
						|
			} | 
						|
			return !bindingError; | 
						|
		} | 
						|
		 | 
						|
		bool IsSigned(TypeCode code, ResolveResult rr) | 
						|
		{ | 
						|
			// Determine whether the rr with code==ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(rr.Type)) | 
						|
			// is a signed primitive type. | 
						|
			switch (code) { | 
						|
				case TypeCode.SByte: | 
						|
				case TypeCode.Int16: | 
						|
					return true; | 
						|
				case TypeCode.Int32: | 
						|
					// for int, consider implicit constant expression conversion | 
						|
					if (rr.IsCompileTimeConstant && rr.ConstantValue != null && (int)rr.ConstantValue >= 0) | 
						|
						return false; | 
						|
					else | 
						|
						return true; | 
						|
				case TypeCode.Int64: | 
						|
					// for long, consider implicit constant expression conversion | 
						|
					if (rr.IsCompileTimeConstant && rr.ConstantValue != null && (long)rr.ConstantValue >= 0) | 
						|
						return false; | 
						|
					else | 
						|
						return true; | 
						|
				default: | 
						|
					return false; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult CastTo(TypeCode targetType, bool isNullable, ResolveResult expression, bool allowNullableConstants) | 
						|
		{ | 
						|
			IType elementType = compilation.FindType(targetType); | 
						|
			IType nullableType = MakeNullable(elementType, isNullable); | 
						|
			if (nullableType.Equals(expression.Type)) | 
						|
				return expression; | 
						|
			if (allowNullableConstants && expression.IsCompileTimeConstant) { | 
						|
				if (expression.ConstantValue == null) | 
						|
					return new ConstantResolveResult(nullableType, null); | 
						|
				ResolveResult rr = ResolveCast(elementType, expression); | 
						|
				if (rr.IsError) | 
						|
					return rr; | 
						|
				Debug.Assert(rr.IsCompileTimeConstant); | 
						|
				return new ConstantResolveResult(nullableType, rr.ConstantValue); | 
						|
			} else { | 
						|
				return Convert(expression, nullableType, | 
						|
				               isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region GetOverloadableOperatorName | 
						|
		static string GetOverloadableOperatorName(BinaryOperatorType op) | 
						|
		{ | 
						|
			switch (op) { | 
						|
				case BinaryOperatorType.Add: | 
						|
					return "op_Addition"; | 
						|
				case BinaryOperatorType.Subtract: | 
						|
					return "op_Subtraction"; | 
						|
				case BinaryOperatorType.Multiply: | 
						|
					return "op_Multiply"; | 
						|
				case BinaryOperatorType.Divide: | 
						|
					return "op_Division"; | 
						|
				case BinaryOperatorType.Modulus: | 
						|
					return "op_Modulus"; | 
						|
				case BinaryOperatorType.BitwiseAnd: | 
						|
					return "op_BitwiseAnd"; | 
						|
				case BinaryOperatorType.BitwiseOr: | 
						|
					return "op_BitwiseOr"; | 
						|
				case BinaryOperatorType.ExclusiveOr: | 
						|
					return "op_ExclusiveOr"; | 
						|
				case BinaryOperatorType.ShiftLeft: | 
						|
					return "op_LeftShift"; | 
						|
				case BinaryOperatorType.ShiftRight: | 
						|
					return "op_RightShift"; | 
						|
				case BinaryOperatorType.Equality: | 
						|
					return "op_Equality"; | 
						|
				case BinaryOperatorType.InEquality: | 
						|
					return "op_Inequality"; | 
						|
				case BinaryOperatorType.GreaterThan: | 
						|
					return "op_GreaterThan"; | 
						|
				case BinaryOperatorType.LessThan: | 
						|
					return "op_LessThan"; | 
						|
				case BinaryOperatorType.GreaterThanOrEqual: | 
						|
					return "op_GreaterThanOrEqual"; | 
						|
				case BinaryOperatorType.LessThanOrEqual: | 
						|
					return "op_LessThanOrEqual"; | 
						|
				default: | 
						|
					return null; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Null coalescing operator | 
						|
		ResolveResult ResolveNullCoalescingOperator(ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			if (NullableType.IsNullable(lhs.Type)) { | 
						|
				IType a0 = NullableType.GetUnderlyingType(lhs.Type); | 
						|
				if (TryConvert(ref rhs, a0)) { | 
						|
					return BinaryOperatorResolveResult(a0, lhs, BinaryOperatorType.NullCoalescing, rhs); | 
						|
				} | 
						|
			} | 
						|
			if (TryConvert(ref rhs, lhs.Type)) { | 
						|
				return BinaryOperatorResolveResult(lhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs); | 
						|
			} | 
						|
			if (TryConvert(ref lhs, rhs.Type)) { | 
						|
				return BinaryOperatorResolveResult(rhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs); | 
						|
			} else { | 
						|
				return new ErrorResolveResult(lhs.Type); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		#endregion | 
						|
		 | 
						|
		#region Get user-defined operator candidates | 
						|
		IEnumerable<IParameterizedMember> GetUserDefinedOperatorCandidates(IType type, string operatorName) | 
						|
		{ | 
						|
			if (operatorName == null) | 
						|
				return EmptyList<IMethod>.Instance; | 
						|
			TypeCode c = ReflectionHelper.GetTypeCode(type); | 
						|
			if (TypeCode.Boolean <= c && c <= TypeCode.Decimal || c == TypeCode.String) { | 
						|
				// The .NET framework contains some of C#'s built-in operators as user-defined operators. | 
						|
				// However, we must not use those as user-defined operators (we would skip numeric promotion). | 
						|
				return EmptyList<IMethod>.Instance; | 
						|
			} | 
						|
			// C# 4.0 spec: §7.3.5 Candidate user-defined operators | 
						|
			var operators = type.GetMethods(m => m.IsOperator && m.Name == operatorName).ToList(); | 
						|
			LiftUserDefinedOperators(operators); | 
						|
			return operators; | 
						|
		} | 
						|
		 | 
						|
		void LiftUserDefinedOperators(List<IMethod> operators) | 
						|
		{ | 
						|
			int nonLiftedMethodCount = operators.Count; | 
						|
			// Construct lifted operators | 
						|
			for (int i = 0; i < nonLiftedMethodCount; i++) { | 
						|
				var liftedMethod = CSharpOperators.LiftUserDefinedOperator(operators[i]); | 
						|
				if (liftedMethod != null) | 
						|
					operators.Add(liftedMethod); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult CreateResolveResultForUserDefinedOperator(OverloadResolution r, System.Linq.Expressions.ExpressionType operatorType) | 
						|
		{ | 
						|
			if (r.BestCandidateErrors != OverloadResolutionErrors.None) | 
						|
				return r.CreateResolveResult(null); | 
						|
			IMethod method = (IMethod)r.BestCandidate; | 
						|
			return new OperatorResolveResult(method.ReturnType, operatorType, method, | 
						|
			                                 isLiftedOperator: method is ILiftedOperator, | 
						|
			                                 operands: r.GetArgumentsWithConversions()); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveCast | 
						|
		bool TryConvert(ref ResolveResult rr, IType targetType) | 
						|
		{ | 
						|
			Conversion c = conversions.ImplicitConversion(rr, targetType); | 
						|
			if (c.IsValid) { | 
						|
				rr = Convert(rr, targetType, c); | 
						|
				return true; | 
						|
			} else { | 
						|
				return false; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		///  | 
						|
		/// </summary> | 
						|
		/// <param name="rr">The input resolve result that should be converted. | 
						|
		/// If a conversion exists, it is applied to the resolve result</param> | 
						|
		/// <param name="targetType">The target type that we should convert to</param> | 
						|
		/// <param name="isNullable">Whether we are dealing with a lifted operator</param> | 
						|
		/// <param name="enumRR">The resolve result that is enum-typed. | 
						|
		/// If necessary, a nullable conversion is applied.</param> | 
						|
		/// <param name="allowConversionFromConstantZero"> | 
						|
		/// Whether the conversion from the constant zero is allowed. | 
						|
		/// </param> | 
						|
		/// <returns>True if the conversion is successful; false otherwise. | 
						|
		/// If the conversion is not successful, the ref parameters will not be modified.</returns> | 
						|
		bool TryConvertEnum(ref ResolveResult rr, IType targetType, ref bool isNullable, ref ResolveResult enumRR, bool allowConversionFromConstantZero = true) | 
						|
		{ | 
						|
			Conversion c; | 
						|
			if (!isNullable) { | 
						|
				// Try non-nullable | 
						|
				c = conversions.ImplicitConversion(rr, targetType); | 
						|
				if (c.IsValid && (allowConversionFromConstantZero || !c.IsEnumerationConversion)) { | 
						|
					rr = Convert(rr, targetType, c); | 
						|
					return true; | 
						|
				} | 
						|
			} | 
						|
			// make targetType nullable if it isn't already: | 
						|
			if (!targetType.IsKnownType(KnownTypeCode.NullableOfT)) | 
						|
				targetType = NullableType.Create(compilation, targetType); | 
						|
			 | 
						|
			c = conversions.ImplicitConversion(rr, targetType); | 
						|
			if (c.IsValid && (allowConversionFromConstantZero || !c.IsEnumerationConversion)) { | 
						|
				rr = Convert(rr, targetType, c); | 
						|
				isNullable = true; | 
						|
				// Also convert the enum-typed RR to nullable, if it isn't already | 
						|
				if (!enumRR.Type.IsKnownType(KnownTypeCode.NullableOfT)) { | 
						|
					var nullableType = NullableType.Create(compilation, enumRR.Type); | 
						|
					enumRR = new ConversionResolveResult(nullableType, enumRR, Conversion.ImplicitNullableConversion); | 
						|
				} | 
						|
				return true; | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult Convert(ResolveResult rr, IType targetType) | 
						|
		{ | 
						|
			return Convert(rr, targetType, conversions.ImplicitConversion(rr, targetType)); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult Convert(ResolveResult rr, IType targetType, Conversion c) | 
						|
		{ | 
						|
			if (c == Conversion.IdentityConversion) | 
						|
				return rr; | 
						|
			else if (rr.IsCompileTimeConstant && c != Conversion.None && !c.IsUserDefined) | 
						|
				return ResolveCast(targetType, rr); | 
						|
			else | 
						|
				return new ConversionResolveResult(targetType, rr, c, checkForOverflow); | 
						|
		} | 
						|
		 | 
						|
		public ResolveResult ResolveCast(IType targetType, ResolveResult expression) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.7.6 Cast expressions | 
						|
			Conversion c = conversions.ExplicitConversion(expression, targetType); | 
						|
			if (expression.IsCompileTimeConstant && !c.IsUserDefined) { | 
						|
				TypeCode code = ReflectionHelper.GetTypeCode(targetType); | 
						|
				if (code >= TypeCode.Boolean && code <= TypeCode.Decimal && expression.ConstantValue != null) { | 
						|
					try { | 
						|
						return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue)); | 
						|
					} catch (OverflowException) { | 
						|
						return new ErrorResolveResult(targetType); | 
						|
					} catch (InvalidCastException) { | 
						|
						return new ErrorResolveResult(targetType); | 
						|
					} | 
						|
				} else if (code == TypeCode.String) { | 
						|
					if (expression.ConstantValue == null || expression.ConstantValue is string) | 
						|
						return new ConstantResolveResult(targetType, expression.ConstantValue); | 
						|
					else | 
						|
						return new ErrorResolveResult(targetType); | 
						|
				} else if (targetType.Kind == TypeKind.Enum) { | 
						|
					code = ReflectionHelper.GetTypeCode(GetEnumUnderlyingType(targetType)); | 
						|
					if (code >= TypeCode.SByte && code <= TypeCode.UInt64 && expression.ConstantValue != null) { | 
						|
						try { | 
						|
							return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue)); | 
						|
						} catch (OverflowException) { | 
						|
							return new ErrorResolveResult(targetType); | 
						|
						} catch (InvalidCastException) { | 
						|
							return new ErrorResolveResult(targetType); | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			return new ConversionResolveResult(targetType, expression, c, checkForOverflow); | 
						|
		} | 
						|
		 | 
						|
		internal object CSharpPrimitiveCast(TypeCode targetType, object input) | 
						|
		{ | 
						|
			return Util.CSharpPrimitiveCast.Cast(targetType, input, this.CheckForOverflow); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveSimpleName | 
						|
		public ResolveResult ResolveSimpleName(string identifier, IReadOnlyList<IType> typeArguments, bool isInvocationTarget = false) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.6.2 Simple Names | 
						|
			 | 
						|
			return LookupSimpleNameOrTypeName( | 
						|
				identifier, typeArguments, | 
						|
				isInvocationTarget ? NameLookupMode.InvocationTarget : NameLookupMode.Expression); | 
						|
		} | 
						|
		 | 
						|
		public ResolveResult LookupSimpleNameOrTypeName(string identifier, IReadOnlyList<IType> typeArguments, NameLookupMode lookupMode) | 
						|
		{ | 
						|
			// C# 4.0 spec: §3.8 Namespace and type names; §7.6.2 Simple Names | 
						|
			 | 
						|
			if (identifier == null) | 
						|
				throw new ArgumentNullException("identifier"); | 
						|
			if (typeArguments == null) | 
						|
				throw new ArgumentNullException("typeArguments"); | 
						|
			 | 
						|
			int k = typeArguments.Count; | 
						|
			 | 
						|
			if (k == 0) { | 
						|
				if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget) { | 
						|
					// Look in local variables | 
						|
					foreach (IVariable v in this.LocalVariables) { | 
						|
						if (v.Name == identifier) { | 
						|
							return new LocalResolveResult(v); | 
						|
						} | 
						|
					} | 
						|
					// Look in parameters of current method | 
						|
					IParameterizedMember parameterizedMember = this.CurrentMember as IParameterizedMember; | 
						|
					if (parameterizedMember != null) { | 
						|
						foreach (IParameter p in parameterizedMember.Parameters) { | 
						|
							if (p.Name == identifier) { | 
						|
								return new LocalResolveResult(p); | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				 | 
						|
				// look in type parameters of current method | 
						|
				IMethod m = this.CurrentMember as IMethod; | 
						|
				if (m != null) { | 
						|
					foreach (ITypeParameter tp in m.TypeParameters) { | 
						|
						if (tp.Name == identifier) | 
						|
							return new TypeResolveResult(tp); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			bool parameterizeResultType = !(typeArguments.Count != 0 && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument)); | 
						|
			 | 
						|
			ResolveResult r = null; | 
						|
			if (currentTypeDefinitionCache != null) { | 
						|
				Dictionary<string, ResolveResult> cache = null; | 
						|
				bool foundInCache = false; | 
						|
				if (k == 0) { | 
						|
					switch (lookupMode) { | 
						|
						case NameLookupMode.Expression: | 
						|
							cache = currentTypeDefinitionCache.SimpleNameLookupCacheExpression; | 
						|
							break; | 
						|
						case NameLookupMode.InvocationTarget: | 
						|
							cache = currentTypeDefinitionCache.SimpleNameLookupCacheInvocationTarget; | 
						|
							break; | 
						|
						case NameLookupMode.Type: | 
						|
							cache = currentTypeDefinitionCache.SimpleTypeLookupCache; | 
						|
							break; | 
						|
					} | 
						|
					if (cache != null) { | 
						|
						lock (cache) | 
						|
							foundInCache = cache.TryGetValue(identifier, out r); | 
						|
					} | 
						|
				} | 
						|
				if (foundInCache) { | 
						|
					r = (r != null ? r.ShallowClone() : null); | 
						|
				} else { | 
						|
					r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType); | 
						|
					if (cache != null) { | 
						|
						// also cache missing members (r==null) | 
						|
						lock (cache) | 
						|
							cache[identifier] = r; | 
						|
					} | 
						|
				} | 
						|
				if (r != null) | 
						|
					return r; | 
						|
			} | 
						|
			 | 
						|
			if (context.CurrentUsingScope == null) { | 
						|
				// If no using scope was specified, we still need to look in the global namespace: | 
						|
				r = LookInUsingScopeNamespace(null, compilation.RootNamespace, identifier, typeArguments, parameterizeResultType); | 
						|
			} else { | 
						|
				if (k == 0 && lookupMode != NameLookupMode.TypeInUsingDeclaration) { | 
						|
					if (context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) { | 
						|
						r = (r != null ? r.ShallowClone() : null); | 
						|
					} else { | 
						|
						r = LookInCurrentUsingScope(identifier, typeArguments, false, false); | 
						|
						context.CurrentUsingScope.ResolveCache.TryAdd(identifier, r); | 
						|
					} | 
						|
				} else { | 
						|
					r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == NameLookupMode.TypeInUsingDeclaration, parameterizeResultType); | 
						|
				} | 
						|
			} | 
						|
			if (r != null) | 
						|
				return r; | 
						|
			 | 
						|
			if (typeArguments.Count == 0 && identifier == "dynamic") { | 
						|
				return new TypeResolveResult(SpecialType.Dynamic); | 
						|
			} else { | 
						|
				return new UnknownIdentifierResolveResult(identifier, typeArguments.Count); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		public bool IsVariableReferenceWithSameType (ResolveResult rr, string identifier, out TypeResolveResult trr) | 
						|
		{ | 
						|
			if (!(rr is MemberResolveResult || rr is LocalResolveResult)) { | 
						|
				trr = null; | 
						|
				return false; | 
						|
			} | 
						|
			trr = LookupSimpleNameOrTypeName (identifier, EmptyList<IType>.Instance, NameLookupMode.Type) as TypeResolveResult; | 
						|
			return trr != null && trr.Type.Equals (rr.Type); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult LookInCurrentType(string identifier, IReadOnlyList<IType> typeArguments, NameLookupMode lookupMode, bool parameterizeResultType) | 
						|
		{ | 
						|
			int k = typeArguments.Count; | 
						|
			MemberLookup lookup = CreateMemberLookup(lookupMode); | 
						|
			// look in current type definitions | 
						|
			for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) { | 
						|
				if (k == 0) { | 
						|
					// Look for type parameter with that name | 
						|
					var typeParameters = t.TypeParameters; | 
						|
					// Look at all type parameters, including those copied from outer classes, | 
						|
					// so that we can fetch the version with the correct owner. | 
						|
					for (int i = 0; i < typeParameters.Count; i++) { | 
						|
						if (typeParameters[i].Name == identifier) | 
						|
							return new TypeResolveResult(typeParameters[i]); | 
						|
					} | 
						|
				} | 
						|
				 | 
						|
				if (lookupMode == NameLookupMode.BaseTypeReference && t == this.CurrentTypeDefinition) { | 
						|
					// don't look in current type when resolving a base type reference | 
						|
					continue; | 
						|
				} | 
						|
				 | 
						|
				ResolveResult r; | 
						|
				if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget) { | 
						|
					var targetResolveResult = (t == this.CurrentTypeDefinition ? ResolveThisReference() : new TypeResolveResult(t)); | 
						|
					r = lookup.Lookup(targetResolveResult, identifier, typeArguments, lookupMode == NameLookupMode.InvocationTarget); | 
						|
				} else { | 
						|
					r = lookup.LookupType(t, identifier, typeArguments, parameterizeResultType); | 
						|
				} | 
						|
				if (!(r is UnknownMemberResolveResult)) // but do return AmbiguousMemberResolveResult | 
						|
					return r; | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult LookInCurrentUsingScope(string identifier, IReadOnlyList<IType> typeArguments, bool isInUsingDeclaration, bool parameterizeResultType) | 
						|
		{ | 
						|
			// look in current namespace definitions | 
						|
			ResolvedUsingScope currentUsingScope = this.CurrentUsingScope; | 
						|
			for (ResolvedUsingScope u = currentUsingScope; u != null; u = u.Parent) { | 
						|
				var resultInNamespace = LookInUsingScopeNamespace(u, u.Namespace, identifier, typeArguments, parameterizeResultType); | 
						|
				if (resultInNamespace != null) | 
						|
					return resultInNamespace; | 
						|
				// then look for aliases: | 
						|
				if (typeArguments.Count == 0) { | 
						|
					if (u.ExternAliases.Contains(identifier)) { | 
						|
						return ResolveExternAlias(identifier); | 
						|
					} | 
						|
					if (!(isInUsingDeclaration && u == currentUsingScope)) { | 
						|
						foreach (var pair in u.UsingAliases) { | 
						|
							if (pair.Key == identifier) { | 
						|
								return pair.Value.ShallowClone(); | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				// finally, look in the imported namespaces: | 
						|
				if (!(isInUsingDeclaration && u == currentUsingScope)) { | 
						|
					IType firstResult = null; | 
						|
					foreach (var importedNamespace in u.Usings) { | 
						|
						ITypeDefinition def = importedNamespace.GetTypeDefinition(identifier, typeArguments.Count); | 
						|
						if (def != null) { | 
						|
							IType resultType; | 
						|
							if (parameterizeResultType && typeArguments.Count > 0) | 
						|
								resultType = new ParameterizedType(def, typeArguments); | 
						|
							else | 
						|
								resultType = def; | 
						|
							 | 
						|
							if (firstResult == null || !TopLevelTypeDefinitionIsAccessible(firstResult.GetDefinition())) { | 
						|
								if (TopLevelTypeDefinitionIsAccessible(resultType.GetDefinition())) | 
						|
									firstResult = resultType; | 
						|
							} else if (TopLevelTypeDefinitionIsAccessible(def)) { | 
						|
								return new AmbiguousTypeResolveResult(firstResult); | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
					if (firstResult != null) | 
						|
						return new TypeResolveResult(firstResult); | 
						|
				} | 
						|
				// if we didn't find anything: repeat lookup with parent namespace | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
 | 
						|
		ResolveResult LookInUsingScopeNamespace(ResolvedUsingScope usingScope, INamespace n, string identifier, IReadOnlyList<IType> typeArguments, bool parameterizeResultType) | 
						|
		{ | 
						|
			if (n == null) | 
						|
				return null; | 
						|
			// first look for a namespace | 
						|
			int k = typeArguments.Count; | 
						|
			if (k == 0) { | 
						|
				INamespace childNamespace = n.GetChildNamespace(identifier); | 
						|
				if (childNamespace != null) { | 
						|
					if (usingScope != null && usingScope.HasAlias(identifier)) | 
						|
						return new AmbiguousTypeResolveResult(new UnknownType(null, identifier)); | 
						|
					return new NamespaceResolveResult(childNamespace); | 
						|
				} | 
						|
			} | 
						|
			// then look for a type | 
						|
			ITypeDefinition def = n.GetTypeDefinition(identifier, k); | 
						|
			if (def != null) { | 
						|
				IType result = def; | 
						|
				if (parameterizeResultType && k > 0) { | 
						|
					result = new ParameterizedType(def, typeArguments); | 
						|
				} | 
						|
				if (usingScope != null && usingScope.HasAlias(identifier)) | 
						|
					return new AmbiguousTypeResolveResult(result); | 
						|
				else | 
						|
					return new TypeResolveResult(result); | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		bool TopLevelTypeDefinitionIsAccessible(ITypeDefinition typeDef) | 
						|
		{ | 
						|
			if (typeDef.IsInternal) { | 
						|
				return typeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly); | 
						|
			} | 
						|
			return true; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Looks up an alias (identifier in front of :: operator) | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveAlias(string identifier) | 
						|
		{ | 
						|
			if (identifier == "global") | 
						|
				return new NamespaceResolveResult(compilation.RootNamespace); | 
						|
			 | 
						|
			for (ResolvedUsingScope n = this.CurrentUsingScope; n != null; n = n.Parent) { | 
						|
				if (n.ExternAliases.Contains(identifier)) { | 
						|
					return ResolveExternAlias(identifier); | 
						|
				} | 
						|
				foreach (var pair in n.UsingAliases) { | 
						|
					if (pair.Key == identifier) { | 
						|
						return (pair.Value as NamespaceResolveResult) ?? ErrorResult; | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			return ErrorResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ResolveExternAlias(string alias) | 
						|
		{ | 
						|
			INamespace ns = compilation.GetNamespaceForExternAlias(alias); | 
						|
			if (ns != null) | 
						|
				return new NamespaceResolveResult(ns); | 
						|
			else | 
						|
				return ErrorResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveMemberAccess | 
						|
		public ResolveResult ResolveMemberAccess(ResolveResult target, string identifier, IReadOnlyList<IType> typeArguments, NameLookupMode lookupMode = NameLookupMode.Expression) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.6.4 | 
						|
			 | 
						|
			bool parameterizeResultType = !(typeArguments.Count != 0 && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument)); | 
						|
			NamespaceResolveResult nrr = target as NamespaceResolveResult; | 
						|
			if (nrr != null) { | 
						|
				return ResolveMemberAccessOnNamespace(nrr, identifier, typeArguments, parameterizeResultType); | 
						|
			} | 
						|
			 | 
						|
			if (target.Type.Kind == TypeKind.Dynamic) | 
						|
				return new DynamicMemberResolveResult(target, identifier); | 
						|
			 | 
						|
			MemberLookup lookup = CreateMemberLookup(lookupMode); | 
						|
			ResolveResult result; | 
						|
			switch (lookupMode) { | 
						|
				case NameLookupMode.Expression: | 
						|
					result = lookup.Lookup(target, identifier, typeArguments, isInvocation: false); | 
						|
					break; | 
						|
				case NameLookupMode.InvocationTarget: | 
						|
					result = lookup.Lookup(target, identifier, typeArguments, isInvocation: true); | 
						|
					break; | 
						|
				case NameLookupMode.Type: | 
						|
				case NameLookupMode.TypeInUsingDeclaration: | 
						|
				case NameLookupMode.BaseTypeReference: | 
						|
					// Don't do the UnknownMemberResolveResult/MethodGroupResolveResult processing, | 
						|
					// it's only relevant for expressions. | 
						|
					return lookup.LookupType(target.Type, identifier, typeArguments, parameterizeResultType); | 
						|
				default: | 
						|
					throw new NotSupportedException("Invalid value for NameLookupMode"); | 
						|
			} | 
						|
			if (result is UnknownMemberResolveResult) { | 
						|
				// We intentionally use all extension methods here, not just the eligible ones. | 
						|
				// Proper eligibility checking is only possible for the full invocation | 
						|
				// (after we know the remaining arguments). | 
						|
				// The eligibility check in GetExtensionMethods is only intended for code completion. | 
						|
				var extensionMethods = GetExtensionMethods(identifier, typeArguments); | 
						|
				if (extensionMethods.Count > 0) { | 
						|
					return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) { | 
						|
						extensionMethods = extensionMethods | 
						|
					}; | 
						|
				} | 
						|
			} else { | 
						|
				MethodGroupResolveResult mgrr = result as MethodGroupResolveResult; | 
						|
				if (mgrr != null) { | 
						|
					Debug.Assert(mgrr.extensionMethods == null); | 
						|
					// set the values that are necessary to make MethodGroupResolveResult.GetExtensionMethods() work | 
						|
					mgrr.resolver = this; | 
						|
				} | 
						|
			} | 
						|
			return result; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ResolveMemberAccessOnNamespace(NamespaceResolveResult nrr, string identifier, IReadOnlyList<IType> typeArguments, bool parameterizeResultType) | 
						|
		{ | 
						|
			if (typeArguments.Count == 0) { | 
						|
				INamespace childNamespace = nrr.Namespace.GetChildNamespace(identifier); | 
						|
				if (childNamespace != null) | 
						|
					return new NamespaceResolveResult(childNamespace); | 
						|
			} | 
						|
			ITypeDefinition def = nrr.Namespace.GetTypeDefinition(identifier, typeArguments.Count); | 
						|
			if (def != null) { | 
						|
				if (parameterizeResultType && typeArguments.Count > 0) | 
						|
					return new TypeResolveResult(new ParameterizedType(def, typeArguments)); | 
						|
				else | 
						|
					return new TypeResolveResult(def); | 
						|
			} | 
						|
			return ErrorResult; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Creates a MemberLookup instance using this resolver's settings. | 
						|
		/// </summary> | 
						|
		public MemberLookup CreateMemberLookup() | 
						|
		{ | 
						|
			ITypeDefinition currentTypeDefinition = this.CurrentTypeDefinition; | 
						|
			bool isInEnumMemberInitializer = this.CurrentMember != null && this.CurrentMember.SymbolKind == SymbolKind.Field | 
						|
				&& currentTypeDefinition != null && currentTypeDefinition.Kind == TypeKind.Enum; | 
						|
			return new MemberLookup(currentTypeDefinition, this.Compilation.MainAssembly, isInEnumMemberInitializer); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Creates a MemberLookup instance using this resolver's settings. | 
						|
		/// </summary> | 
						|
		public MemberLookup CreateMemberLookup(NameLookupMode lookupMode) | 
						|
		{ | 
						|
			if (lookupMode == NameLookupMode.BaseTypeReference && this.CurrentTypeDefinition != null) { | 
						|
				// When looking up a base type reference, treat us as being outside the current type definition | 
						|
				// for accessibility purposes. | 
						|
				// This avoids a stack overflow when referencing a protected class nested inside the base class | 
						|
				// of a parent class. (NameLookupTests.InnerClassInheritingFromProtectedBaseInnerClassShouldNotCauseStackOverflow) | 
						|
				return new MemberLookup(this.CurrentTypeDefinition.DeclaringTypeDefinition, this.Compilation.MainAssembly, false); | 
						|
			} else { | 
						|
				return CreateMemberLookup(); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveIdentifierInObjectInitializer | 
						|
		public ResolveResult ResolveIdentifierInObjectInitializer(string identifier) | 
						|
		{ | 
						|
			MemberLookup memberLookup = CreateMemberLookup(); | 
						|
			return memberLookup.Lookup(this.CurrentObjectInitializer, identifier, EmptyList<IType>.Instance, false); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region GetExtensionMethods | 
						|
		/// <summary> | 
						|
		/// Gets all extension methods that are available in the current context. | 
						|
		/// </summary> | 
						|
		/// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param> | 
						|
		/// <param name="typeArguments">Explicitly provided type arguments. | 
						|
		/// An empty list will return all matching extension method definitions; | 
						|
		/// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods | 
						|
		/// with the matching number of type parameters.</param> | 
						|
		/// <remarks> | 
						|
		/// The results are stored in nested lists because they are grouped by using scope. | 
						|
		/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }", | 
						|
		/// the return value will be | 
						|
		/// new List { | 
						|
		///    new List { all extensions from MoreExtensions }, | 
						|
		///    new List { all extensions from SomeExtensions } | 
						|
		/// } | 
						|
		/// </remarks> | 
						|
		public List<List<IMethod>> GetExtensionMethods(string name = null, IReadOnlyList<IType> typeArguments = null) | 
						|
		{ | 
						|
			return GetExtensionMethods(null, name, typeArguments); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the extension methods that are called 'name' | 
						|
		/// and are applicable with a first argument type of 'targetType'. | 
						|
		/// </summary> | 
						|
		/// <param name="targetType">Type of the 'this' argument</param> | 
						|
		/// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param> | 
						|
		/// <param name="typeArguments">Explicitly provided type arguments. | 
						|
		/// An empty list will return all matching extension method definitions; | 
						|
		/// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods | 
						|
		/// with the matching number of type parameters.</param> | 
						|
		/// <param name="substituteInferredTypes"> | 
						|
		/// Specifies whether to produce a <see cref="SpecializedMethod"/> | 
						|
		/// when type arguments could be inferred from <paramref name="targetType"/>. This parameter | 
						|
		/// is only used for inferred types and has no effect if <paramref name="typeArguments"/> is non-empty. | 
						|
		/// </param> | 
						|
		/// <remarks> | 
						|
		/// The results are stored in nested lists because they are grouped by using scope. | 
						|
		/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }", | 
						|
		/// the return value will be | 
						|
		/// new List { | 
						|
		///    new List { all extensions from MoreExtensions }, | 
						|
		///    new List { all extensions from SomeExtensions } | 
						|
		/// } | 
						|
		/// </remarks> | 
						|
		public List<List<IMethod>> GetExtensionMethods(IType targetType, string name = null, IReadOnlyList<IType> typeArguments = null, bool substituteInferredTypes = false) | 
						|
		{ | 
						|
			var lookup = CreateMemberLookup(); | 
						|
			List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); | 
						|
			foreach (var inputGroup in GetAllExtensionMethods(lookup)) { | 
						|
				List<IMethod> outputGroup = new List<IMethod>(); | 
						|
				foreach (var method in inputGroup) { | 
						|
					if (name != null && method.Name != name) | 
						|
						continue; | 
						|
					if (!lookup.IsAccessible(method, false)) | 
						|
						continue; | 
						|
					IType[] inferredTypes; | 
						|
					if (typeArguments != null && typeArguments.Count > 0) { | 
						|
						if (method.TypeParameters.Count != typeArguments.Count) | 
						|
							continue; | 
						|
						var sm = method.Specialize(new TypeParameterSubstitution(null, typeArguments)); | 
						|
						if (IsEligibleExtensionMethod(compilation, conversions, targetType, sm, false, out inferredTypes)) | 
						|
							outputGroup.Add(sm); | 
						|
					} else { | 
						|
						if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, true, out inferredTypes)) { | 
						|
							if (substituteInferredTypes && inferredTypes != null) { | 
						|
								outputGroup.Add(method.Specialize(new TypeParameterSubstitution(null, inferredTypes))); | 
						|
							} else { | 
						|
								outputGroup.Add(method); | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				if (outputGroup.Count > 0) | 
						|
					extensionMethodGroups.Add(outputGroup); | 
						|
			} | 
						|
			return extensionMethodGroups; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Checks whether the specified extension method is eligible on the target type. | 
						|
		/// </summary> | 
						|
		/// <param name="targetType">Target type that is passed as first argument to the extension method.</param> | 
						|
		/// <param name="method">The extension method.</param> | 
						|
		/// <param name="useTypeInference">Whether to perform type inference for the method. | 
						|
		/// Use <c>false</c> if <paramref name="method"/> is already parameterized (e.g. when type arguments were given explicitly). | 
						|
		/// Otherwise, use <c>true</c>. | 
						|
		/// </param> | 
						|
		/// <param name="outInferredTypes">If the method is generic and <paramref name="useTypeInference"/> is <c>true</c>, | 
						|
		/// and at least some of the type arguments could be inferred, this parameter receives the inferred type arguments. | 
						|
		/// Since only the type for the first parameter is considered, not all type arguments may be inferred. | 
						|
		/// If an array is returned, any slot with an uninferred type argument will be set to the method's | 
						|
		/// corresponding type parameter. | 
						|
		/// </param> | 
						|
		public static bool IsEligibleExtensionMethod(IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes) | 
						|
		{ | 
						|
			if (targetType == null) | 
						|
				throw new ArgumentNullException("targetType"); | 
						|
			if (method == null) | 
						|
				throw new ArgumentNullException("method"); | 
						|
			var compilation = method.Compilation; | 
						|
			return IsEligibleExtensionMethod(compilation, CSharpConversions.Get(compilation), targetType, method, useTypeInference, out outInferredTypes); | 
						|
		} | 
						|
		 | 
						|
		static bool IsEligibleExtensionMethod(ICompilation compilation, CSharpConversions conversions, IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes) | 
						|
		{ | 
						|
			outInferredTypes = null; | 
						|
			if (targetType == null) | 
						|
				return true; | 
						|
			if (method.Parameters.Count == 0) | 
						|
				return false; | 
						|
			IType thisParameterType = method.Parameters[0].Type; | 
						|
			if (useTypeInference && method.TypeParameters.Count > 0) { | 
						|
				// We need to infer type arguments from targetType: | 
						|
				TypeInference ti = new TypeInference(compilation, conversions); | 
						|
				ResolveResult[] arguments = { new ResolveResult(targetType) }; | 
						|
				IType[] parameterTypes = { method.Parameters[0].Type }; | 
						|
				bool success; | 
						|
				var inferredTypes = ti.InferTypeArguments(method.TypeParameters, arguments, parameterTypes, out success); | 
						|
				var substitution = new TypeParameterSubstitution(null, inferredTypes); | 
						|
				// Validate that the types that could be inferred (aren't unknown) satisfy the constraints: | 
						|
				bool hasInferredTypes = false; | 
						|
				for (int i = 0; i < inferredTypes.Length; i++) { | 
						|
					if (inferredTypes[i].Kind != TypeKind.Unknown && inferredTypes[i].Kind != TypeKind.UnboundTypeArgument) { | 
						|
						hasInferredTypes = true; | 
						|
						if (!OverloadResolution.ValidateConstraints(method.TypeParameters[i], inferredTypes[i], substitution, conversions)) | 
						|
							return false; | 
						|
					} else { | 
						|
						inferredTypes[i] = method.TypeParameters[i]; // do not substitute types that could not be inferred | 
						|
					} | 
						|
				} | 
						|
				if (hasInferredTypes) | 
						|
					outInferredTypes = inferredTypes; | 
						|
				thisParameterType = thisParameterType.AcceptVisitor(substitution); | 
						|
			} | 
						|
			Conversion c = conversions.ImplicitConversion(targetType, thisParameterType); | 
						|
			return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets all extension methods available in the current using scope. | 
						|
		/// This list includes inaccessible methods. | 
						|
		/// </summary> | 
						|
		IList<List<IMethod>> GetAllExtensionMethods(MemberLookup lookup) | 
						|
		{ | 
						|
			var currentUsingScope = context.CurrentUsingScope; | 
						|
			if (currentUsingScope == null) | 
						|
				return EmptyList<List<IMethod>>.Instance; | 
						|
			List<List<IMethod>> extensionMethodGroups = LazyInit.VolatileRead(ref currentUsingScope.AllExtensionMethods); | 
						|
			if (extensionMethodGroups != null) { | 
						|
				return extensionMethodGroups; | 
						|
			} | 
						|
			extensionMethodGroups = new List<List<IMethod>>(); | 
						|
			List<IMethod> m; | 
						|
			for (ResolvedUsingScope scope = currentUsingScope; scope != null; scope = scope.Parent) { | 
						|
				INamespace ns = scope.Namespace; | 
						|
				if (ns != null) { | 
						|
					m = GetExtensionMethods(lookup, ns).ToList(); | 
						|
					if (m.Count > 0) | 
						|
						extensionMethodGroups.Add(m); | 
						|
				} | 
						|
				 | 
						|
				m = scope.Usings | 
						|
					.Distinct() | 
						|
					.SelectMany(importedNamespace =>  GetExtensionMethods(lookup, importedNamespace)) | 
						|
					.ToList(); | 
						|
				if (m.Count > 0) | 
						|
					extensionMethodGroups.Add(m); | 
						|
			} | 
						|
			return LazyInit.GetOrSet(ref currentUsingScope.AllExtensionMethods, extensionMethodGroups); | 
						|
		} | 
						|
		 | 
						|
		IEnumerable<IMethod> GetExtensionMethods(MemberLookup lookup, INamespace ns) | 
						|
		{ | 
						|
			// TODO: maybe make this a property on INamespace? | 
						|
			return | 
						|
				from c in ns.Types | 
						|
				where c.IsStatic && c.HasExtensionMethods && c.TypeParameters.Count == 0 && lookup.IsAccessible(c, false) | 
						|
				from m in c.Methods | 
						|
				where m.IsExtensionMethod | 
						|
				select m; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveInvocation | 
						|
 | 
						|
		IList<ResolveResult> AddArgumentNamesIfNecessary(ResolveResult[] arguments, string[] argumentNames) { | 
						|
			if (argumentNames == null) { | 
						|
				return arguments; | 
						|
			} | 
						|
			else { | 
						|
				var result = new ResolveResult[arguments.Length]; | 
						|
				for (int i = 0; i < arguments.Length; i++) { | 
						|
					result[i] = (argumentNames[i] != null ? new NamedArgumentResolveResult(argumentNames[i], arguments[i]) : arguments[i]); | 
						|
				} | 
						|
				return result; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		private ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames, bool allowOptionalParameters) | 
						|
		{ | 
						|
			// C# 4.0 spec: §7.6.5 | 
						|
			 | 
						|
			if (target.Type.Kind == TypeKind.Dynamic) { | 
						|
				return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames)); | 
						|
			} | 
						|
			 | 
						|
			bool isDynamic = arguments.Any(a => a.Type.Kind == TypeKind.Dynamic); | 
						|
			MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; | 
						|
			if (mgrr != null) { | 
						|
				if (isDynamic) { | 
						|
					// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method. | 
						|
					var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray()); | 
						|
					var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList(); | 
						|
 | 
						|
					if (applicableMethods.Count > 1) { | 
						|
						ResolveResult actualTarget; | 
						|
						if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult)) | 
						|
							actualTarget = new TypeResolveResult(mgrr.TargetType); | 
						|
						else | 
						|
							actualTarget = mgrr.TargetResult; | 
						|
 | 
						|
						var l = new List<MethodListWithDeclaringType>(); | 
						|
						foreach (var m in applicableMethods) { | 
						|
							if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType) | 
						|
								l.Add(new MethodListWithDeclaringType(m.DeclaringType)); | 
						|
							l[l.Count - 1].Add(m.Method); | 
						|
						} | 
						|
						return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames)); | 
						|
					} | 
						|
				} | 
						|
 | 
						|
				OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions, allowOptionalParameters: allowOptionalParameters); | 
						|
				if (or.BestCandidate != null) { | 
						|
					if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult)) | 
						|
						return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType), returnTypeOverride: isDynamic ? SpecialType.Dynamic : null); | 
						|
					else | 
						|
						return or.CreateResolveResult(mgrr.TargetResult, returnTypeOverride: isDynamic ? SpecialType.Dynamic : null); | 
						|
				} else { | 
						|
					// No candidate found at all (not even an inapplicable one). | 
						|
					// This can happen with empty method groups (as sometimes used with extension methods) | 
						|
					return new UnknownMethodResolveResult( | 
						|
						mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)); | 
						|
				} | 
						|
			} | 
						|
			UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult; | 
						|
			if (umrr != null) { | 
						|
				return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames)); | 
						|
			} | 
						|
			UnknownIdentifierResolveResult uirr = target as UnknownIdentifierResolveResult; | 
						|
			if (uirr != null && CurrentTypeDefinition != null) { | 
						|
				return new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames)); | 
						|
			} | 
						|
			IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); | 
						|
			if (invokeMethod != null) { | 
						|
				OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); | 
						|
				or.AddCandidate(invokeMethod); | 
						|
				return new CSharpInvocationResolveResult( | 
						|
					target, invokeMethod, //invokeMethod.ReturnType.Resolve(context), | 
						|
					or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors, | 
						|
					isExpandedForm: or.BestCandidateIsExpandedForm, | 
						|
					isDelegateInvocation: true, | 
						|
					argumentToParameterMap: or.GetArgumentToParameterMap(), | 
						|
					returnTypeOverride: isDynamic ? SpecialType.Dynamic : null); | 
						|
			} | 
						|
			return ErrorResult; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Resolves an invocation. | 
						|
		/// </summary> | 
						|
		/// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param> | 
						|
		/// <param name="arguments"> | 
						|
		/// Arguments passed to the method. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		/// <param name="argumentNames"> | 
						|
		/// The argument names. Pass the null string for positional arguments. | 
						|
		/// </param> | 
						|
		/// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns> | 
						|
		public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null) | 
						|
		{ | 
						|
			return ResolveInvocation(target, arguments, argumentNames, allowOptionalParameters: true); | 
						|
		} | 
						|
		 | 
						|
		List<IParameter> CreateParameters(ResolveResult[] arguments, string[] argumentNames) | 
						|
		{ | 
						|
			List<IParameter> list = new List<IParameter>(); | 
						|
			if (argumentNames == null) { | 
						|
				argumentNames = new string[arguments.Length]; | 
						|
			} else { | 
						|
				if (argumentNames.Length != arguments.Length) | 
						|
					throw new ArgumentException(); | 
						|
				argumentNames = (string[])argumentNames.Clone(); | 
						|
			} | 
						|
			for (int i = 0; i < arguments.Length; i++) { | 
						|
				// invent argument names where necessary: | 
						|
				if (argumentNames[i] == null) { | 
						|
					string newArgumentName = GuessParameterName(arguments[i]); | 
						|
					if (argumentNames.Contains(newArgumentName)) { | 
						|
						// disambiguate argument name (e.g. add a number) | 
						|
						int num = 1; | 
						|
						string newName; | 
						|
						do { | 
						|
							newName = newArgumentName + num.ToString(); | 
						|
							num++; | 
						|
						} while(argumentNames.Contains(newName)); | 
						|
						newArgumentName = newName; | 
						|
					} | 
						|
					argumentNames[i] = newArgumentName; | 
						|
				} | 
						|
				 | 
						|
				// create the parameter: | 
						|
				ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult; | 
						|
				if (brrr != null) { | 
						|
					list.Add(new DefaultParameter(arguments[i].Type, argumentNames[i], isRef: brrr.IsRef, isOut: brrr.IsOut)); | 
						|
				} else { | 
						|
					// argument might be a lambda or delegate type, so we have to try to guess the delegate type | 
						|
					IType type = arguments[i].Type; | 
						|
					if (type.Kind == TypeKind.Null || type.Kind == TypeKind.None) { | 
						|
						list.Add(new DefaultParameter(compilation.FindType(KnownTypeCode.Object), argumentNames[i])); | 
						|
					} else { | 
						|
						list.Add(new DefaultParameter(type, argumentNames[i])); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			return list; | 
						|
		} | 
						|
		 | 
						|
		static string GuessParameterName(ResolveResult rr) | 
						|
		{ | 
						|
			MemberResolveResult mrr = rr as MemberResolveResult; | 
						|
			if (mrr != null) | 
						|
				return mrr.Member.Name; | 
						|
			 | 
						|
			UnknownMemberResolveResult umrr = rr as UnknownMemberResolveResult; | 
						|
			if (umrr != null) | 
						|
				return umrr.MemberName; | 
						|
			 | 
						|
			MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; | 
						|
			if (mgrr != null) | 
						|
				return mgrr.MethodName; | 
						|
			 | 
						|
			LocalResolveResult vrr = rr as LocalResolveResult; | 
						|
			if (vrr != null) | 
						|
				return MakeParameterName(vrr.Variable.Name); | 
						|
			 | 
						|
			if (rr.Type.Kind != TypeKind.Unknown && !string.IsNullOrEmpty(rr.Type.Name)) { | 
						|
				return MakeParameterName(rr.Type.Name); | 
						|
			} else { | 
						|
				return "parameter"; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		static string MakeParameterName(string variableName) | 
						|
		{ | 
						|
			if (string.IsNullOrEmpty(variableName)) | 
						|
				return "parameter"; | 
						|
			if (variableName.Length > 1 && variableName[0] == '_') | 
						|
				variableName = variableName.Substring(1); | 
						|
			return char.ToLower(variableName[0]) + variableName.Substring(1); | 
						|
		} | 
						|
		 | 
						|
		OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null) | 
						|
		{ | 
						|
			var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions); | 
						|
			or.CheckForOverflow = checkForOverflow; | 
						|
			return or; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveIndexer | 
						|
		/// <summary> | 
						|
		/// Resolves an indexer access. | 
						|
		/// </summary> | 
						|
		/// <param name="target">Target expression.</param> | 
						|
		/// <param name="arguments"> | 
						|
		/// Arguments passed to the indexer. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		/// <param name="argumentNames"> | 
						|
		/// The argument names. Pass the null string for positional arguments. | 
						|
		/// </param> | 
						|
		/// <returns>ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult</returns> | 
						|
		public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null) | 
						|
		{ | 
						|
			switch (target.Type.Kind) { | 
						|
				case TypeKind.Dynamic: | 
						|
					return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames)); | 
						|
					 | 
						|
				case TypeKind.Array: | 
						|
				case TypeKind.Pointer: | 
						|
					// §7.6.6.1 Array access / §18.5.3 Pointer element access | 
						|
					AdjustArrayAccessArguments(arguments); | 
						|
					return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments); | 
						|
			} | 
						|
			 | 
						|
			// §7.6.6.2 Indexer access | 
						|
 | 
						|
			MemberLookup lookup = CreateMemberLookup(); | 
						|
			var indexers = lookup.LookupIndexers(target); | 
						|
 | 
						|
			if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) { | 
						|
				// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer. | 
						|
				var or2 = CreateOverloadResolution(arguments, argumentNames, null); | 
						|
				var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList(); | 
						|
 | 
						|
				if (applicableIndexers.Count > 1) { | 
						|
					return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames)); | 
						|
				} | 
						|
			} | 
						|
 | 
						|
			OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); | 
						|
			or.AddMethodLists(indexers); | 
						|
			if (or.BestCandidate != null) { | 
						|
				return or.CreateResolveResult(target); | 
						|
			} else { | 
						|
				return ErrorResult; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Converts all arguments to int,uint,long or ulong. | 
						|
		/// </summary> | 
						|
		void AdjustArrayAccessArguments(ResolveResult[] arguments) | 
						|
		{ | 
						|
			for (int i = 0; i < arguments.Length; i++) { | 
						|
				if (!(TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.Int32)) || | 
						|
				      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.UInt32)) || | 
						|
				      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.Int64)) || | 
						|
				      TryConvert(ref arguments[i], compilation.FindType(KnownTypeCode.UInt64)))) | 
						|
				{ | 
						|
					// conversion failed | 
						|
					arguments[i] = Convert(arguments[i], compilation.FindType(KnownTypeCode.Int32), Conversion.None); | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveObjectCreation | 
						|
		/// <summary> | 
						|
		/// Resolves an object creation. | 
						|
		/// </summary> | 
						|
		/// <param name="type">Type of the object to create.</param> | 
						|
		/// <param name="arguments"> | 
						|
		/// Arguments passed to the constructor. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		/// <param name="argumentNames"> | 
						|
		/// The argument names. Pass the null string for positional arguments. | 
						|
		/// </param> | 
						|
		/// <param name="allowProtectedAccess"> | 
						|
		/// Whether to allow calling protected constructors. | 
						|
		/// This should be false except when resolving constructor initializers. | 
						|
		/// </param> | 
						|
		/// <param name="initializerStatements"> | 
						|
		/// Statements for Objects/Collections initializer. | 
						|
		/// <see cref="InvocationResolveResult.InitializerStatements"/> | 
						|
		/// </param> | 
						|
		/// <returns>InvocationResolveResult or ErrorResolveResult</returns> | 
						|
		public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null) | 
						|
		{ | 
						|
			if (type.Kind == TypeKind.Delegate && arguments.Length == 1) { | 
						|
				ResolveResult input = arguments[0]; | 
						|
				IMethod invoke = input.Type.GetDelegateInvokeMethod(); | 
						|
				if (invoke != null) { | 
						|
					input = new MethodGroupResolveResult( | 
						|
						input, invoke.Name, | 
						|
						methods: new[] { new MethodListWithDeclaringType(input.Type) { invoke } }, | 
						|
						typeArguments: EmptyList<IType>.Instance | 
						|
					); | 
						|
				} | 
						|
				return Convert(input, type); | 
						|
			} | 
						|
			OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); | 
						|
			MemberLookup lookup = CreateMemberLookup(); | 
						|
			var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null); | 
						|
			foreach (IMethod ctor in type.GetConstructors()) { | 
						|
				if (lookup.IsAccessible(ctor, allowProtectedAccess)) { | 
						|
					var orErrors = or.AddCandidate(ctor); | 
						|
					if (allApplicable != null && OverloadResolution.IsApplicable(orErrors)) | 
						|
						allApplicable.Add(ctor); | 
						|
				} | 
						|
				else | 
						|
					or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible); | 
						|
			} | 
						|
 | 
						|
			if (allApplicable != null && allApplicable.Count > 1) { | 
						|
				// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor. | 
						|
				return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, AddArgumentNamesIfNecessary(arguments, argumentNames), initializerStatements); | 
						|
			} | 
						|
 | 
						|
			if (or.BestCandidate != null) { | 
						|
				return or.CreateResolveResult(null, initializerStatements); | 
						|
			} else { | 
						|
				return new ErrorResolveResult(type); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveSizeOf | 
						|
		/// <summary> | 
						|
		/// Resolves 'sizeof(type)'. | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveSizeOf(IType type) | 
						|
		{ | 
						|
			IType int32 = compilation.FindType(KnownTypeCode.Int32); | 
						|
			int? size = null; | 
						|
			var typeForConstant = (type.Kind == TypeKind.Enum) ? type.GetDefinition().EnumUnderlyingType : type; | 
						|
 | 
						|
			switch (ReflectionHelper.GetTypeCode(typeForConstant)) { | 
						|
				case TypeCode.Boolean: | 
						|
				case TypeCode.SByte: | 
						|
				case TypeCode.Byte: | 
						|
					size = 1; | 
						|
					break; | 
						|
				case TypeCode.Char: | 
						|
				case TypeCode.Int16: | 
						|
				case TypeCode.UInt16: | 
						|
					size = 2; | 
						|
					break; | 
						|
				case TypeCode.Int32: | 
						|
				case TypeCode.UInt32: | 
						|
				case TypeCode.Single: | 
						|
					size = 4; | 
						|
					break; | 
						|
				case TypeCode.Int64: | 
						|
				case TypeCode.UInt64: | 
						|
				case TypeCode.Double: | 
						|
					size = 8; | 
						|
					break; | 
						|
			} | 
						|
			return new SizeOfResolveResult(int32, type, size); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Resolve This/Base Reference | 
						|
		/// <summary> | 
						|
		/// Resolves 'this'. | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveThisReference() | 
						|
		{ | 
						|
			ITypeDefinition t = CurrentTypeDefinition; | 
						|
			if (t != null) { | 
						|
				if (t.TypeParameterCount != 0) { | 
						|
					// Self-parameterize the type | 
						|
					return new ThisResolveResult(new ParameterizedType(t, t.TypeParameters)); | 
						|
				} else { | 
						|
					return new ThisResolveResult(t); | 
						|
				} | 
						|
			} | 
						|
			return ErrorResult; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Resolves 'base'. | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveBaseReference() | 
						|
		{ | 
						|
			ITypeDefinition t = CurrentTypeDefinition; | 
						|
			if (t != null) { | 
						|
				foreach (IType baseType in t.DirectBaseTypes) { | 
						|
					if (baseType.Kind != TypeKind.Unknown && baseType.Kind != TypeKind.Interface) { | 
						|
						return new ThisResolveResult(baseType, causesNonVirtualInvocation: true); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			return ErrorResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveConditional | 
						|
		/// <summary> | 
						|
		/// Converts the input to <c>bool</c> using the rules for boolean expressions. | 
						|
		/// That is, <c>operator true</c> is used if a regular conversion to <c>bool</c> is not possible. | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveCondition(ResolveResult input) | 
						|
		{ | 
						|
			if (input == null) | 
						|
				throw new ArgumentNullException("input"); | 
						|
			IType boolean = compilation.FindType(KnownTypeCode.Boolean); | 
						|
			Conversion c = conversions.ImplicitConversion(input, boolean); | 
						|
			if (!c.IsValid) { | 
						|
				var opTrue = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_True").FirstOrDefault(); | 
						|
				if (opTrue != null) { | 
						|
					c = Conversion.UserDefinedConversion(opTrue, isImplicit: true, conversionBeforeUserDefinedOperator: Conversion.None, conversionAfterUserDefinedOperator: Conversion.None); | 
						|
				} | 
						|
			} | 
						|
			return Convert(input, boolean, c); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Converts the negated input to <c>bool</c> using the rules for boolean expressions. | 
						|
		/// Computes <c>!(bool)input</c> if the implicit cast to bool is valid; otherwise | 
						|
		/// computes <c>input.operator false()</c>. | 
						|
		/// </summary> | 
						|
		public ResolveResult ResolveConditionFalse(ResolveResult input) | 
						|
		{ | 
						|
			if (input == null) | 
						|
				throw new ArgumentNullException("input"); | 
						|
			IType boolean = compilation.FindType(KnownTypeCode.Boolean); | 
						|
			Conversion c = conversions.ImplicitConversion(input, boolean); | 
						|
			if (!c.IsValid) { | 
						|
				var opFalse = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_False").FirstOrDefault(); | 
						|
				if (opFalse != null) { | 
						|
					c = Conversion.UserDefinedConversion(opFalse, isImplicit: true, conversionBeforeUserDefinedOperator: Conversion.None, conversionAfterUserDefinedOperator: Conversion.None); | 
						|
					return Convert(input, boolean, c); | 
						|
				} | 
						|
			} | 
						|
			return ResolveUnaryOperator(UnaryOperatorType.Not, Convert(input, boolean, c)); | 
						|
		} | 
						|
		 | 
						|
		public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression) | 
						|
		{ | 
						|
			// C# 4.0 spec §7.14: Conditional operator | 
						|
			 | 
						|
			bool isValid; | 
						|
			IType resultType; | 
						|
			if (trueExpression.Type.Kind == TypeKind.Dynamic || falseExpression.Type.Kind == TypeKind.Dynamic) { | 
						|
				resultType = SpecialType.Dynamic; | 
						|
				isValid = TryConvert(ref trueExpression, resultType) & TryConvert(ref falseExpression, resultType); | 
						|
			} else if (HasType(trueExpression) && HasType(falseExpression)) { | 
						|
				Conversion t2f = conversions.ImplicitConversion(trueExpression, falseExpression.Type); | 
						|
				Conversion f2t = conversions.ImplicitConversion(falseExpression, trueExpression.Type); | 
						|
				// The operator is valid: | 
						|
				// a) if there's a conversion in one direction but not the other | 
						|
				// b) if there are conversions in both directions, and the types are equivalent | 
						|
				if (IsBetterConditionalConversion(t2f, f2t)) { | 
						|
					resultType = falseExpression.Type; | 
						|
					isValid = true; | 
						|
					trueExpression = Convert(trueExpression, resultType, t2f); | 
						|
				} else if (IsBetterConditionalConversion(f2t, t2f)) { | 
						|
					resultType = trueExpression.Type; | 
						|
					isValid = true; | 
						|
					falseExpression = Convert(falseExpression, resultType, f2t); | 
						|
				} else { | 
						|
					resultType = trueExpression.Type; | 
						|
					isValid = trueExpression.Type.Equals(falseExpression.Type); | 
						|
				} | 
						|
			} else if (HasType(trueExpression)) { | 
						|
				resultType = trueExpression.Type; | 
						|
				isValid = TryConvert(ref falseExpression, resultType); | 
						|
			} else if (HasType(falseExpression)) { | 
						|
				resultType = falseExpression.Type; | 
						|
				isValid = TryConvert(ref trueExpression, resultType); | 
						|
			} else { | 
						|
				return ErrorResult; | 
						|
			} | 
						|
			condition = ResolveCondition(condition); | 
						|
			if (isValid) { | 
						|
				if (condition.IsCompileTimeConstant && trueExpression.IsCompileTimeConstant && falseExpression.IsCompileTimeConstant) { | 
						|
					bool? val = condition.ConstantValue as bool?; | 
						|
					if (val == true) | 
						|
						return trueExpression; | 
						|
					else if (val == false) | 
						|
						return falseExpression; | 
						|
				} | 
						|
				return new OperatorResolveResult(resultType, System.Linq.Expressions.ExpressionType.Conditional, | 
						|
				                                 condition, trueExpression, falseExpression); | 
						|
			} else { | 
						|
				return new ErrorResolveResult(resultType); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		bool IsBetterConditionalConversion(Conversion c1, Conversion c2) | 
						|
		{ | 
						|
			// Valid is better than ImplicitConstantExpressionConversion is better than invalid | 
						|
			if (!c1.IsValid) | 
						|
				return false; | 
						|
			if (c1 != Conversion.ImplicitConstantExpressionConversion && c2 == Conversion.ImplicitConstantExpressionConversion) | 
						|
				return true; | 
						|
			return !c2.IsValid; | 
						|
		} | 
						|
		 | 
						|
		bool HasType(ResolveResult r) | 
						|
		{ | 
						|
			return r.Type.Kind != TypeKind.None && r.Type.Kind != TypeKind.Null; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolvePrimitive | 
						|
		public ResolveResult ResolvePrimitive(object value) | 
						|
		{ | 
						|
			if (value == null) { | 
						|
				return new ResolveResult(SpecialType.NullType); | 
						|
			} else { | 
						|
				TypeCode typeCode = Type.GetTypeCode(value.GetType()); | 
						|
				IType type = compilation.FindType(typeCode); | 
						|
				return new ConstantResolveResult(type, value); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveDefaultValue | 
						|
		public ResolveResult ResolveDefaultValue(IType type) | 
						|
		{ | 
						|
			return new ConstantResolveResult(type, GetDefaultValue(type)); | 
						|
		} | 
						|
		 | 
						|
		public static object GetDefaultValue(IType type) | 
						|
		{ | 
						|
			ITypeDefinition typeDef = type.GetDefinition(); | 
						|
			if (typeDef == null) | 
						|
				return null; | 
						|
			if (typeDef.Kind == TypeKind.Enum) { | 
						|
				typeDef = typeDef.EnumUnderlyingType.GetDefinition(); | 
						|
				if (typeDef == null) | 
						|
					return null; | 
						|
			} | 
						|
			switch (typeDef.KnownTypeCode) { | 
						|
				case KnownTypeCode.Boolean: | 
						|
					return false; | 
						|
				case KnownTypeCode.Char: | 
						|
					return '\0'; | 
						|
				case KnownTypeCode.SByte: | 
						|
					return (sbyte)0; | 
						|
				case KnownTypeCode.Byte: | 
						|
					return (byte)0; | 
						|
				case KnownTypeCode.Int16: | 
						|
					return (short)0; | 
						|
				case KnownTypeCode.UInt16: | 
						|
					return (ushort)0; | 
						|
				case KnownTypeCode.Int32: | 
						|
					return 0; | 
						|
				case KnownTypeCode.UInt32: | 
						|
					return 0U; | 
						|
				case KnownTypeCode.Int64: | 
						|
					return 0L; | 
						|
				case KnownTypeCode.UInt64: | 
						|
					return 0UL; | 
						|
				case KnownTypeCode.Single: | 
						|
					return 0f; | 
						|
				case KnownTypeCode.Double: | 
						|
					return 0.0; | 
						|
				case KnownTypeCode.Decimal: | 
						|
					return 0m; | 
						|
				default: | 
						|
					return null; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResolveArrayCreation | 
						|
		/// <summary> | 
						|
		/// Resolves an array creation. | 
						|
		/// </summary> | 
						|
		/// <param name="elementType"> | 
						|
		/// The array element type. | 
						|
		/// Pass null to resolve an implicitly-typed array creation. | 
						|
		/// </param> | 
						|
		/// <param name="sizeArguments"> | 
						|
		/// The size arguments. | 
						|
		/// The length of this array will be used as the number of dimensions of the array type. | 
						|
		/// Negative values will be treated as errors. | 
						|
		/// </param> | 
						|
		/// <param name="initializerElements"> | 
						|
		/// The initializer elements. May be null if no array initializer was specified. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int[] sizeArguments, ResolveResult[] initializerElements = null) | 
						|
		{ | 
						|
			ResolveResult[] sizeArgResults = new ResolveResult[sizeArguments.Length]; | 
						|
			for (int i = 0; i < sizeArguments.Length; i++) { | 
						|
				if (sizeArguments[i] < 0) | 
						|
					sizeArgResults[i] = ErrorResolveResult.UnknownError; | 
						|
				else | 
						|
					sizeArgResults[i] = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), sizeArguments[i]); | 
						|
			} | 
						|
			return ResolveArrayCreation(elementType, sizeArgResults, initializerElements); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Resolves an array creation. | 
						|
		/// </summary> | 
						|
		/// <param name="elementType"> | 
						|
		/// The array element type. | 
						|
		/// Pass null to resolve an implicitly-typed array creation. | 
						|
		/// </param> | 
						|
		/// <param name="sizeArguments"> | 
						|
		/// The size arguments. | 
						|
		/// The length of this array will be used as the number of dimensions of the array type. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		/// <param name="initializerElements"> | 
						|
		/// The initializer elements. May be null if no array initializer was specified. | 
						|
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! | 
						|
		/// </param> | 
						|
		public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, ResolveResult[] sizeArguments, ResolveResult[] initializerElements = null) | 
						|
		{ | 
						|
			int dimensions = sizeArguments.Length; | 
						|
			if (dimensions == 0) | 
						|
				throw new ArgumentException("sizeArguments.Length must not be 0"); | 
						|
			if (elementType == null) { | 
						|
				TypeInference typeInference = new TypeInference(compilation, conversions); | 
						|
				bool success; | 
						|
				elementType = typeInference.GetBestCommonType(initializerElements, out success); | 
						|
			} | 
						|
			IType arrayType = new ArrayType(compilation, elementType, dimensions); | 
						|
			 | 
						|
			AdjustArrayAccessArguments(sizeArguments); | 
						|
			 | 
						|
			if (initializerElements != null) { | 
						|
				for (int i = 0; i < initializerElements.Length; i++) { | 
						|
					initializerElements[i] = Convert(initializerElements[i], elementType); | 
						|
				} | 
						|
			} | 
						|
			return new ArrayCreateResolveResult(arrayType, sizeArguments, initializerElements); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		public ResolveResult ResolveTypeOf(IType referencedType) | 
						|
		{ | 
						|
			return new TypeOfResolveResult(compilation.FindType(KnownTypeCode.Type), referencedType); | 
						|
		} | 
						|
		 | 
						|
		#region ResolveAssignment | 
						|
		public ResolveResult ResolveAssignment(AssignmentOperatorType op, ResolveResult lhs, ResolveResult rhs) | 
						|
		{ | 
						|
			var linqOp = AssignmentExpression.GetLinqNodeType(op, this.CheckForOverflow); | 
						|
			var bop = AssignmentExpression.GetCorrespondingBinaryOperator(op); | 
						|
			if (bop == null) { | 
						|
				return new OperatorResolveResult(lhs.Type, linqOp, lhs, this.Convert(rhs, lhs.Type)); | 
						|
			} | 
						|
			ResolveResult bopResult = ResolveBinaryOperator(bop.Value, lhs, rhs); | 
						|
			OperatorResolveResult opResult = bopResult as OperatorResolveResult; | 
						|
			if (opResult == null || opResult.Operands.Count != 2) | 
						|
				return bopResult; | 
						|
			return new OperatorResolveResult(lhs.Type, linqOp, opResult.UserDefinedOperatorMethod, opResult.IsLiftedOperator, | 
						|
			                                 new [] { lhs, opResult.Operands[1] }); | 
						|
		} | 
						|
		#endregion | 
						|
	} | 
						|
}
 | 
						|
 |