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.
		
		
		
		
		
			
		
			
				
					
					
						
							4005 lines
						
					
					
						
							148 KiB
						
					
					
				
			
		
		
	
	
							4005 lines
						
					
					
						
							148 KiB
						
					
					
				// Copyright (c) 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.Diagnostics; | 
						|
using System.Linq; | 
						|
using System.Text; | 
						|
using System.Threading; | 
						|
using ICSharpCode.NRefactory.CSharp.Analysis; | 
						|
using ICSharpCode.NRefactory.CSharp.TypeSystem; | 
						|
using ICSharpCode.NRefactory.Semantics; | 
						|
using ICSharpCode.NRefactory.TypeSystem; | 
						|
using ICSharpCode.NRefactory.TypeSystem.Implementation; | 
						|
 | 
						|
namespace ICSharpCode.NRefactory.CSharp.Resolver | 
						|
{ | 
						|
	/// <summary> | 
						|
	/// Traverses the DOM and resolves expressions. | 
						|
	/// </summary> | 
						|
	/// <remarks> | 
						|
	/// The ResolveVisitor does two jobs at the same time: it tracks the resolve context (properties on CSharpResolver) | 
						|
	/// and it resolves the expressions visited. | 
						|
	/// To allow using the context tracking without having to resolve every expression in the file (e.g. when you want to resolve | 
						|
	/// only a single node deep within the DOM), you can use the <see cref="IResolveVisitorNavigator"/> interface. | 
						|
	/// The navigator allows you to switch the between scanning mode and resolving mode. | 
						|
	/// In scanning mode, the context is tracked (local variables registered etc.), but nodes are not resolved. | 
						|
	/// While scanning, the navigator will get asked about every node that the resolve visitor is about to enter. | 
						|
	/// This allows the navigator whether to keep scanning, whether switch to resolving mode, or whether to completely skip the | 
						|
	/// subtree rooted at that node. | 
						|
	///  | 
						|
	/// In resolving mode, the context is tracked and nodes will be resolved. | 
						|
	/// The resolve visitor may decide that it needs to resolve other nodes as well in order to resolve the current node. | 
						|
	/// In this case, those nodes will be resolved automatically, without asking the navigator interface. | 
						|
	/// For child nodes that are not essential to resolving, the resolve visitor will switch back to scanning mode (and thus will | 
						|
	/// ask the navigator for further instructions). | 
						|
	///  | 
						|
	/// Moreover, there is the <c>ResolveAll</c> mode - it works similar to resolving mode, but will not switch back to scanning mode. | 
						|
	/// The whole subtree will be resolved without notifying the navigator. | 
						|
	/// </remarks> | 
						|
	sealed class ResolveVisitor : IAstVisitor<ResolveResult> | 
						|
	{ | 
						|
		// The ResolveVisitor is also responsible for handling lambda expressions. | 
						|
		 | 
						|
		static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError; | 
						|
		 | 
						|
		CSharpResolver resolver; | 
						|
		/// <summary>Resolve result of the current LINQ query.</summary> | 
						|
		/// <remarks>We do not have to put this into the stored state (resolver) because | 
						|
		/// query expressions are always resolved in a single operation.</remarks> | 
						|
		ResolveResult currentQueryResult; | 
						|
		readonly CSharpUnresolvedFile unresolvedFile; | 
						|
		readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>(); | 
						|
		readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>(); | 
						|
		readonly Dictionary<AstNode, CSharpResolver> resolverAfterDict = new Dictionary<AstNode, CSharpResolver>(); | 
						|
		readonly Dictionary<Expression, ConversionWithTargetType> conversionDict = new Dictionary<Expression, ConversionWithTargetType>(); | 
						|
		 | 
						|
		internal struct ConversionWithTargetType | 
						|
		{ | 
						|
			public readonly Conversion Conversion; | 
						|
			public readonly IType TargetType; | 
						|
			 | 
						|
			public ConversionWithTargetType(Conversion conversion, IType targetType) | 
						|
			{ | 
						|
				this.Conversion = conversion; | 
						|
				this.TargetType = targetType; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		IResolveVisitorNavigator navigator; | 
						|
		bool resolverEnabled; | 
						|
		List<LambdaBase> undecidedLambdas; | 
						|
		internal CancellationToken cancellationToken; | 
						|
		 | 
						|
		#region Constructor | 
						|
		static readonly IResolveVisitorNavigator skipAllNavigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null); | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Creates a new ResolveVisitor instance. | 
						|
		/// </summary> | 
						|
		public ResolveVisitor(CSharpResolver resolver, CSharpUnresolvedFile unresolvedFile) | 
						|
		{ | 
						|
			if (resolver == null) | 
						|
				throw new ArgumentNullException("resolver"); | 
						|
			this.resolver = resolver; | 
						|
			this.unresolvedFile = unresolvedFile; | 
						|
			this.navigator = skipAllNavigator; | 
						|
		} | 
						|
		 | 
						|
		internal void SetNavigator(IResolveVisitorNavigator navigator) | 
						|
		{ | 
						|
			this.navigator = navigator ?? skipAllNavigator; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult voidResult { | 
						|
			get { | 
						|
				return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void)); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region ResetContext | 
						|
		/// <summary> | 
						|
		/// Resets the visitor to the stored position, runs the action, and then reverts the visitor to the previous position. | 
						|
		/// </summary> | 
						|
		void ResetContext(CSharpResolver storedContext, Action action) | 
						|
		{ | 
						|
			var oldResolverEnabled = this.resolverEnabled; | 
						|
			var oldResolver = this.resolver; | 
						|
			var oldQueryResult = this.currentQueryResult; | 
						|
			try { | 
						|
				this.resolverEnabled = false; | 
						|
				this.resolver = storedContext; | 
						|
				this.currentQueryResult = null; | 
						|
				 | 
						|
				action(); | 
						|
			} finally { | 
						|
				this.resolverEnabled = oldResolverEnabled; | 
						|
				this.resolver = oldResolver; | 
						|
				this.currentQueryResult = oldQueryResult; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Scan / Resolve | 
						|
		/// <summary> | 
						|
		/// Scans the AST rooted at the given node. | 
						|
		/// </summary> | 
						|
		public void Scan(AstNode node) | 
						|
		{ | 
						|
			if (node == null || node.IsNull) | 
						|
				return; | 
						|
			switch (node.NodeType) { | 
						|
				case NodeType.Token: | 
						|
				case NodeType.Whitespace: | 
						|
					return; // skip tokens, identifiers, comments, etc. | 
						|
			} | 
						|
			// don't Scan again if the node was already resolved | 
						|
			if (resolveResultCache.ContainsKey(node)) { | 
						|
				// Restore state change caused by this node: | 
						|
				CSharpResolver newResolver; | 
						|
				if (resolverAfterDict.TryGetValue(node, out newResolver)) | 
						|
					resolver = newResolver; | 
						|
				return; | 
						|
			} | 
						|
			 | 
						|
			var mode = navigator.Scan(node); | 
						|
			switch (mode) { | 
						|
				case ResolveVisitorNavigationMode.Skip: | 
						|
					if (node is VariableDeclarationStatement || node is SwitchSection) { | 
						|
						// Enforce scanning of variable declarations. | 
						|
						goto case ResolveVisitorNavigationMode.Scan; | 
						|
					} | 
						|
					StoreCurrentState(node); | 
						|
					break; | 
						|
				case ResolveVisitorNavigationMode.Scan: | 
						|
					bool oldResolverEnabled = resolverEnabled; | 
						|
					var oldResolver = resolver; | 
						|
					resolverEnabled = false; | 
						|
					StoreCurrentState(node); | 
						|
					ResolveResult result = node.AcceptVisitor(this); | 
						|
					if (result != null) { | 
						|
						// If the node was resolved, store the result even though it wasn't requested. | 
						|
						// This is necessary so that Visit-methods that decide to always resolve are | 
						|
						// guaranteed to get called only once. | 
						|
						// This is used for lambda registration. | 
						|
						StoreResult(node, result); | 
						|
						if (resolver != oldResolver) { | 
						|
							// The node changed the resolver state: | 
						|
							resolverAfterDict.Add(node, resolver); | 
						|
						} | 
						|
						cancellationToken.ThrowIfCancellationRequested(); | 
						|
					} | 
						|
					resolverEnabled = oldResolverEnabled; | 
						|
					break; | 
						|
				case ResolveVisitorNavigationMode.Resolve: | 
						|
					Resolve(node); | 
						|
					break; | 
						|
				default: | 
						|
					throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode"); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Equivalent to 'Scan', but also resolves the node at the same time. | 
						|
		/// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set | 
						|
		/// to the correct state. | 
						|
		/// Otherwise, use <c>resolver.Scan(syntaxTree); var result = resolver.GetResolveResult(node);</c> | 
						|
		/// instead. | 
						|
		/// -- | 
						|
		/// This method now is internal, because it is difficult to use correctly. | 
						|
		/// Users of the public API should use Scan()+GetResolveResult() instead. | 
						|
		/// </summary> | 
						|
		internal ResolveResult Resolve(AstNode node) | 
						|
		{ | 
						|
			if (node == null || node.IsNull) | 
						|
				return errorResult; | 
						|
			bool oldResolverEnabled = resolverEnabled; | 
						|
			resolverEnabled = true; | 
						|
			ResolveResult result; | 
						|
			if (!resolveResultCache.TryGetValue(node, out result)) { | 
						|
				cancellationToken.ThrowIfCancellationRequested(); | 
						|
				StoreCurrentState(node); | 
						|
				var oldResolver = resolver; | 
						|
				result = node.AcceptVisitor(this) ?? errorResult; | 
						|
				StoreResult(node, result); | 
						|
				if (resolver != oldResolver) { | 
						|
					// The node changed the resolver state: | 
						|
					resolverAfterDict.Add(node, resolver); | 
						|
				} | 
						|
			} | 
						|
			resolverEnabled = oldResolverEnabled; | 
						|
			return result; | 
						|
		} | 
						|
		 | 
						|
		IType ResolveType(AstType type) | 
						|
		{ | 
						|
			return Resolve(type).Type; | 
						|
		} | 
						|
		 | 
						|
		void StoreCurrentState(AstNode node) | 
						|
		{ | 
						|
			// It's possible that we re-visit an expression that we scanned over earlier, | 
						|
			// so we might have to overwrite an existing state. | 
						|
			 | 
						|
			#if DEBUG | 
						|
			CSharpResolver oldResolver; | 
						|
			if (resolverBeforeDict.TryGetValue(node, out oldResolver)) { | 
						|
				Debug.Assert(oldResolver.LocalVariables.SequenceEqual(resolver.LocalVariables)); | 
						|
			} | 
						|
			#endif | 
						|
			 | 
						|
			resolverBeforeDict[node] = resolver; | 
						|
		} | 
						|
		 | 
						|
		void StoreResult(AstNode node, ResolveResult result) | 
						|
		{ | 
						|
			Debug.Assert(result != null); | 
						|
			if (node.IsNull) | 
						|
				return; | 
						|
			Log.WriteLine("Resolved '{0}' to {1}", node, result); | 
						|
			Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node)); | 
						|
			// The state should be stored before the result is. | 
						|
			Debug.Assert(resolverBeforeDict.ContainsKey(node)); | 
						|
			// Don't store results twice. | 
						|
			Debug.Assert(!resolveResultCache.ContainsKey(node)); | 
						|
			resolveResultCache[node] = result; | 
						|
			if (navigator != null) | 
						|
				navigator.Resolved(node, result); | 
						|
		} | 
						|
		 | 
						|
		void ScanChildren(AstNode node) | 
						|
		{ | 
						|
			for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { | 
						|
				Scan(child); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Process Conversions | 
						|
		sealed class AnonymousFunctionConversion : Conversion | 
						|
		{ | 
						|
			public readonly IType ReturnType; | 
						|
			public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda; | 
						|
			public readonly LambdaTypeHypothesis Hypothesis; | 
						|
			readonly bool isValid; | 
						|
			 | 
						|
			public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid) | 
						|
			{ | 
						|
				if (returnType == null) | 
						|
					throw new ArgumentNullException("returnType"); | 
						|
				this.ReturnType = returnType; | 
						|
				this.Hypothesis = hypothesis; | 
						|
				this.isValid = isValid; | 
						|
			} | 
						|
			 | 
						|
			public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid) | 
						|
			{ | 
						|
				if (returnType == null) | 
						|
					throw new ArgumentNullException("returnType"); | 
						|
				this.ReturnType = returnType; | 
						|
				this.ExplicitlyTypedLambda = explicitlyTypedLambda; | 
						|
				this.isValid = isValid; | 
						|
			} | 
						|
			 | 
						|
			public override bool IsValid { | 
						|
				get { return isValid; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsImplicit { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAnonymousFunctionConversion { | 
						|
				get { return true; } | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Convert 'rr' to the target type using the specified conversion. | 
						|
		/// </summary> | 
						|
		void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType) | 
						|
		{ | 
						|
			AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion; | 
						|
			if (afc != null) { | 
						|
				Log.WriteLine("Processing conversion of anonymous function to " + targetType + "..."); | 
						|
				 | 
						|
				Log.Indent(); | 
						|
				if (afc.Hypothesis != null) | 
						|
					afc.Hypothesis.MergeInto(this, afc.ReturnType); | 
						|
				if (afc.ExplicitlyTypedLambda != null) | 
						|
					afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType); | 
						|
				Log.Unindent(); | 
						|
			} | 
						|
			if (expr != null && !expr.IsNull && conversion != Conversion.IdentityConversion) { | 
						|
				navigator.ProcessConversion(expr, rr, conversion, targetType); | 
						|
				conversionDict[expr] = new ConversionWithTargetType(conversion, targetType); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void ImportConversions(ResolveVisitor childVisitor) | 
						|
		{ | 
						|
			foreach (var pair in childVisitor.conversionDict) { | 
						|
				conversionDict.Add(pair.Key, pair.Value); | 
						|
				navigator.ProcessConversion(pair.Key, resolveResultCache[pair.Key], pair.Value.Conversion, pair.Value.TargetType); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Convert 'rr' to the target type. | 
						|
		/// </summary> | 
						|
		void ProcessConversion(Expression expr, ResolveResult rr, IType targetType) | 
						|
		{ | 
						|
			if (expr == null || expr.IsNull) | 
						|
				return; | 
						|
			ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Resolves the specified expression and processes the conversion to targetType. | 
						|
		/// </summary> | 
						|
		void ResolveAndProcessConversion(Expression expr, IType targetType) | 
						|
		{ | 
						|
			if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void) { | 
						|
				// no need to resolve the expression right now | 
						|
				Scan(expr); | 
						|
			} else { | 
						|
				ProcessConversion(expr, Resolve(expr), targetType); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void ProcessConversionResult(Expression expr, ConversionResolveResult rr) | 
						|
		{ | 
						|
			if (rr != null) | 
						|
				ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type); | 
						|
		} | 
						|
		 | 
						|
		void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults) | 
						|
		{ | 
						|
			Debug.Assert(expr.Count() == conversionResolveResults.Count()); | 
						|
			using (var e1 = expr.GetEnumerator()) { | 
						|
				using (var e2 = conversionResolveResults.GetEnumerator()) { | 
						|
					while (e1.MoveNext() && e2.MoveNext()) { | 
						|
						ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void MarkUnknownNamedArguments(IEnumerable<Expression> arguments) | 
						|
		{ | 
						|
			foreach (var nae in arguments.OfType<NamedArgumentExpression>()) { | 
						|
				StoreCurrentState(nae); | 
						|
				StoreResult(nae, new NamedArgumentResolveResult(nae.Name, resolveResultCache[nae.Expression])); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void ProcessInvocationResult(Expression target, IEnumerable<Expression> arguments, ResolveResult invocation) | 
						|
		{ | 
						|
			if (invocation is CSharpInvocationResolveResult || invocation is DynamicInvocationResolveResult) { | 
						|
				int i = 0; | 
						|
				IList<ResolveResult> argumentsRR; | 
						|
				if (invocation is CSharpInvocationResolveResult) { | 
						|
					var csi = (CSharpInvocationResolveResult)invocation; | 
						|
					if (csi.IsExtensionMethodInvocation) { | 
						|
						Debug.Assert(arguments.Count() + 1 == csi.Arguments.Count); | 
						|
						ProcessConversionResult(target, csi.Arguments[0] as ConversionResolveResult); | 
						|
						i = 1; | 
						|
					} else { | 
						|
						Debug.Assert(arguments.Count() == csi.Arguments.Count); | 
						|
					} | 
						|
					argumentsRR = csi.Arguments; | 
						|
				} | 
						|
				else { | 
						|
					argumentsRR = ((DynamicInvocationResolveResult)invocation).Arguments; | 
						|
				} | 
						|
 | 
						|
				foreach (Expression arg in arguments) { | 
						|
					ResolveResult argRR = argumentsRR[i++]; | 
						|
					NamedArgumentExpression nae = arg as NamedArgumentExpression; | 
						|
					NamedArgumentResolveResult nrr = argRR as NamedArgumentResolveResult; | 
						|
					Debug.Assert((nae == null) == (nrr == null)); | 
						|
					if (nae != null && nrr != null) { | 
						|
						StoreCurrentState(nae); | 
						|
						StoreResult(nae, nrr); | 
						|
						ProcessConversionResult(nae.Expression, nrr.Argument as ConversionResolveResult); | 
						|
					} else { | 
						|
						ProcessConversionResult(arg, argRR as ConversionResolveResult); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			else { | 
						|
				MarkUnknownNamedArguments(arguments); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region GetResolveResult | 
						|
		/// <summary> | 
						|
		/// Gets the resolve result for the specified node. | 
						|
		/// If the node was not resolved by the navigator, this method will resolve it. | 
						|
		/// </summary> | 
						|
		public ResolveResult GetResolveResult(AstNode node) | 
						|
		{ | 
						|
			Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node)); | 
						|
			 | 
						|
			MergeUndecidedLambdas(); | 
						|
			ResolveResult result; | 
						|
			if (resolveResultCache.TryGetValue(node, out result)) | 
						|
				return result; | 
						|
			 | 
						|
			AstNode parent; | 
						|
			CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent); | 
						|
			ResetContext( | 
						|
				storedResolver, | 
						|
				delegate { | 
						|
					navigator = new NodeListResolveVisitorNavigator(node); | 
						|
					Debug.Assert(!resolverEnabled); | 
						|
					Scan(parent); | 
						|
					navigator = skipAllNavigator; | 
						|
				}); | 
						|
			 | 
						|
			MergeUndecidedLambdas(); | 
						|
			return resolveResultCache[node]; | 
						|
		} | 
						|
		 | 
						|
		CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent) | 
						|
		{ | 
						|
			parent = node; | 
						|
			CSharpResolver storedResolver; | 
						|
			while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) { | 
						|
				parent = parent.Parent; | 
						|
				if (parent == null) | 
						|
					throw new InvalidOperationException("Could not find a resolver state for any parent of the specified node. Are you trying to resolve a node that is not a descendant of the CSharpAstResolver's root node?"); | 
						|
			} | 
						|
			return storedResolver; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the resolver state in front of the specified node. | 
						|
		/// If the node was not visited by a previous scanning process, the | 
						|
		/// AST will be scanned again to determine the state. | 
						|
		/// </summary> | 
						|
		public CSharpResolver GetResolverStateBefore(AstNode node) | 
						|
		{ | 
						|
			MergeUndecidedLambdas(); | 
						|
			CSharpResolver r; | 
						|
			if (resolverBeforeDict.TryGetValue(node, out r)) | 
						|
				return r; | 
						|
			 | 
						|
			AstNode parent; | 
						|
			CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent); | 
						|
			ResetContext( | 
						|
				storedResolver, | 
						|
				delegate { | 
						|
					navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true); | 
						|
					Debug.Assert(!resolverEnabled); | 
						|
					// parent might already be resolved if 'node' is an unresolvable node | 
						|
					Scan(parent); | 
						|
					navigator = skipAllNavigator; | 
						|
				}); | 
						|
			 | 
						|
			MergeUndecidedLambdas(); | 
						|
			while (node != null) { | 
						|
				if (resolverBeforeDict.TryGetValue(node, out r)) | 
						|
					return r; | 
						|
				node = node.Parent; | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		public CSharpResolver GetResolverStateAfter(AstNode node) | 
						|
		{ | 
						|
			// Resolve the node to fill the resolverAfterDict | 
						|
			GetResolveResult(node); | 
						|
			CSharpResolver result; | 
						|
			if (resolverAfterDict.TryGetValue(node, out result)) | 
						|
				return result; | 
						|
			else | 
						|
				return GetResolverStateBefore(node); | 
						|
		} | 
						|
		 | 
						|
		public ConversionWithTargetType GetConversionWithTargetType(Expression expr) | 
						|
		{ | 
						|
			GetResolverStateBefore(expr); | 
						|
			ResolveParentForConversion(expr); | 
						|
			ConversionWithTargetType result; | 
						|
			if (conversionDict.TryGetValue(expr, out result)) { | 
						|
				return result; | 
						|
			} else { | 
						|
				ResolveResult rr = GetResolveResult(expr); | 
						|
				return new ConversionWithTargetType(Conversion.IdentityConversion, rr.Type); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Track UsingScope | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitSyntaxTree(SyntaxTree unit) | 
						|
		{ | 
						|
			CSharpResolver previousResolver = resolver; | 
						|
			try { | 
						|
				if (unresolvedFile != null) { | 
						|
					resolver = resolver.WithCurrentUsingScope(unresolvedFile.RootUsingScope.Resolve(resolver.Compilation)); | 
						|
				} else { | 
						|
					var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty); | 
						|
					ApplyVisitorToUsings(cv, unit.Children); | 
						|
					PushUsingScope(cv.UnresolvedFile.RootUsingScope); | 
						|
				} | 
						|
				ScanChildren(unit); | 
						|
				return voidResult; | 
						|
			} finally { | 
						|
				resolver = previousResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> children) | 
						|
		{ | 
						|
			foreach (var child in children) { | 
						|
				if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) { | 
						|
					child.AcceptVisitor(visitor); | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void PushUsingScope(UsingScope usingScope) | 
						|
		{ | 
						|
			usingScope.Freeze(); | 
						|
			resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope)); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) | 
						|
		{ | 
						|
			CSharpResolver previousResolver = resolver; | 
						|
			try { | 
						|
				if (unresolvedFile != null) { | 
						|
					resolver = resolver.WithCurrentUsingScope(unresolvedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation)); | 
						|
				} else { | 
						|
					string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty; | 
						|
					// Fetch parent using scope | 
						|
					// Create root using scope if necessary | 
						|
					if (resolver.CurrentUsingScope == null) | 
						|
						PushUsingScope(new UsingScope()); | 
						|
					 | 
						|
					// Create child using scope | 
						|
					DomRegion region = namespaceDeclaration.GetRegion(); | 
						|
					var identifiers = namespaceDeclaration.Identifiers.ToList(); | 
						|
					// For all but the last identifier: | 
						|
					UsingScope usingScope; | 
						|
					for (int i = 0; i < identifiers.Count - 1; i++) { | 
						|
						usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i].Name); | 
						|
						usingScope.Region = region; | 
						|
						PushUsingScope(usingScope); | 
						|
					} | 
						|
					// Last using scope: | 
						|
					usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last().Name); | 
						|
					usingScope.Region = region; | 
						|
					var cv = new TypeSystemConvertVisitor(new CSharpUnresolvedFile(region.FileName ?? string.Empty), usingScope); | 
						|
					ApplyVisitorToUsings(cv, namespaceDeclaration.Children); | 
						|
					PushUsingScope(usingScope); | 
						|
				} | 
						|
				ScanChildren(namespaceDeclaration); | 
						|
				// merge undecided lambdas before leaving the using scope so that | 
						|
				// the resolver can make better use of its cache | 
						|
				MergeUndecidedLambdas(); | 
						|
				if (resolver.CurrentUsingScope != null && resolver.CurrentUsingScope.Namespace != null) | 
						|
					return new NamespaceResolveResult(resolver.CurrentUsingScope.Namespace); | 
						|
				else | 
						|
					return null; | 
						|
			} finally { | 
						|
				resolver = previousResolver; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Track CurrentTypeDefinition | 
						|
		ResolveResult VisitTypeOrDelegate(AstNode typeDeclaration, string name, int typeParameterCount) | 
						|
		{ | 
						|
			CSharpResolver previousResolver = resolver; | 
						|
			try { | 
						|
				ITypeDefinition newTypeDefinition = null; | 
						|
				if (resolver.CurrentTypeDefinition != null) { | 
						|
					int totalTypeParameterCount = resolver.CurrentTypeDefinition.TypeParameterCount + typeParameterCount; | 
						|
					foreach (ITypeDefinition nestedType in resolver.CurrentTypeDefinition.NestedTypes) { | 
						|
						if (nestedType.Name == name && nestedType.TypeParameterCount == totalTypeParameterCount) { | 
						|
							newTypeDefinition = nestedType; | 
						|
							break; | 
						|
						} | 
						|
					} | 
						|
				} else if (resolver.CurrentUsingScope != null) { | 
						|
					newTypeDefinition = resolver.CurrentUsingScope.Namespace.GetTypeDefinition(name, typeParameterCount); | 
						|
				} | 
						|
				if (newTypeDefinition != null) | 
						|
					resolver = resolver.WithCurrentTypeDefinition(newTypeDefinition); | 
						|
				 | 
						|
				ScanChildren(typeDeclaration); | 
						|
				 | 
						|
				// merge undecided lambdas before leaving the type definition so that | 
						|
				// the resolver can make better use of its cache | 
						|
				MergeUndecidedLambdas(); | 
						|
				 | 
						|
				return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult; | 
						|
			} finally { | 
						|
				resolver = previousResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitTypeDeclaration(TypeDeclaration typeDeclaration) | 
						|
		{ | 
						|
			return VisitTypeOrDelegate(typeDeclaration, typeDeclaration.Name, typeDeclaration.TypeParameters.Count); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) | 
						|
		{ | 
						|
			return VisitTypeOrDelegate(delegateDeclaration, delegateDeclaration.Name, delegateDeclaration.TypeParameters.Count); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Track CurrentMember | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration) | 
						|
		{ | 
						|
			return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) | 
						|
		{ | 
						|
			return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration) | 
						|
		{ | 
						|
			return VisitFieldOrEventDeclaration(eventDeclaration, EntityType.Event); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, EntityType entityType) | 
						|
		{ | 
						|
			//int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count; | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) { | 
						|
				if (node.Role == Roles.Variable) { | 
						|
					IMember member; | 
						|
					if (unresolvedFile != null) { | 
						|
						member = GetMemberFromLocation(node); | 
						|
					} else { | 
						|
						string name = ((VariableInitializer)node).Name; | 
						|
						member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, name); | 
						|
					} | 
						|
					resolver = resolver.WithCurrentMember(member); | 
						|
					 | 
						|
					Scan(node); | 
						|
					 | 
						|
					resolver = oldResolver; | 
						|
				} else { | 
						|
					Scan(node); | 
						|
				} | 
						|
			} | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		IMember GetMemberFromLocation(AstNode node) | 
						|
		{ | 
						|
			ITypeDefinition typeDef = resolver.CurrentTypeDefinition; | 
						|
			if (typeDef == null) | 
						|
				return null; | 
						|
			TextLocation location = TypeSystemConvertVisitor.GetStartLocationAfterAttributes(node); | 
						|
			return typeDef.GetMembers( | 
						|
				delegate (IUnresolvedMember m) { | 
						|
					if (m.UnresolvedFile != unresolvedFile) | 
						|
						return false; | 
						|
					DomRegion region = m.Region; | 
						|
					return !region.IsEmpty && region.Begin <= location && region.End > location; | 
						|
				}, | 
						|
				GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions | 
						|
			).FirstOrDefault(); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitVariableInitializer(VariableInitializer variableInitializer) | 
						|
		{ | 
						|
			// Within the variable initializer, the newly declared variable is not yet available: | 
						|
			var resolverWithVariable = resolver; | 
						|
			if (variableInitializer.Parent is VariableDeclarationStatement) | 
						|
				resolver = resolver.PopLastVariable(); | 
						|
			 | 
						|
			ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression; | 
						|
			if (resolverEnabled || aie != null) { | 
						|
				ResolveResult result = errorResult; | 
						|
				if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) { | 
						|
					if (resolver.CurrentMember != null) { | 
						|
						result = new MemberResolveResult(null, resolver.CurrentMember, false); | 
						|
					} | 
						|
				} else { | 
						|
					string identifier = variableInitializer.Name; | 
						|
					foreach (IVariable v in resolverWithVariable.LocalVariables) { | 
						|
						if (v.Name == identifier) { | 
						|
							result = new LocalResolveResult(v); | 
						|
							break; | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				ArrayType arrayType = result.Type as ArrayType; | 
						|
				if (aie != null && arrayType != null) { | 
						|
					StoreCurrentState(aie); | 
						|
					List<Expression> initializerElements = new List<Expression>(); | 
						|
					UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions, true); | 
						|
					ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count]; | 
						|
					for (int i = 0; i < initializerElementResults.Length; i++) { | 
						|
						initializerElementResults[i] = Resolve(initializerElements[i]); | 
						|
					} | 
						|
					var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElementResults); | 
						|
					StoreResult(aie, arrayCreation); | 
						|
					ProcessConversionResults(initializerElements, arrayCreation.InitializerElements); | 
						|
				} else if (variableInitializer.Parent is FixedStatement) { | 
						|
					var initRR = Resolve(variableInitializer.Initializer); | 
						|
					PointerType pointerType; | 
						|
					if (initRR.Type.Kind == TypeKind.Array) { | 
						|
						pointerType = new PointerType(((ArrayType)initRR.Type).ElementType); | 
						|
					} else if (ReflectionHelper.GetTypeCode(initRR.Type) == TypeCode.String) { | 
						|
						pointerType = new PointerType(resolver.Compilation.FindType(KnownTypeCode.Char)); | 
						|
					} else { | 
						|
						pointerType = null; | 
						|
						ProcessConversion(variableInitializer.Initializer, initRR, result.Type); | 
						|
					} | 
						|
					if (pointerType != null) { | 
						|
						var conversion = resolver.conversions.ImplicitConversion(pointerType, result.Type); | 
						|
						if (conversion.IsIdentityConversion) | 
						|
							conversion = Conversion.ImplicitPointerConversion; | 
						|
						ProcessConversion(variableInitializer.Initializer, initRR, conversion, result.Type); | 
						|
					} | 
						|
				} else { | 
						|
					ResolveAndProcessConversion(variableInitializer.Initializer, result.Type); | 
						|
				} | 
						|
				resolver = resolverWithVariable; | 
						|
				return result; | 
						|
			} else { | 
						|
				Scan(variableInitializer.Initializer); | 
						|
				resolver = resolverWithVariable; | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveResult result = errorResult; | 
						|
				if (resolver.CurrentMember != null) { | 
						|
					result = new MemberResolveResult(null, resolver.CurrentMember, false); | 
						|
				} | 
						|
				ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32)); | 
						|
				return result; | 
						|
			} else { | 
						|
				ScanChildren(fixedVariableInitializer); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				IMember member; | 
						|
				if (unresolvedFile != null) { | 
						|
					member = GetMemberFromLocation(memberDeclaration); | 
						|
				} else { | 
						|
					// Re-discover the method: | 
						|
					EntityType entityType = memberDeclaration.EntityType; | 
						|
					var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter)); | 
						|
					if (entityType == EntityType.Constructor) { | 
						|
						string name = memberDeclaration.HasModifier(Modifiers.Static) ? ".cctor" : ".ctor"; | 
						|
						member = AbstractUnresolvedMember.Resolve( | 
						|
							resolver.CurrentTypeResolveContext, entityType, name, | 
						|
							parameterTypeReferences: parameterTypes); | 
						|
					} else if (entityType == EntityType.Destructor) { | 
						|
						member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, "Finalize"); | 
						|
					} else { | 
						|
						string[] typeParameterNames = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).Select(tp => tp.Name).ToArray(); | 
						|
						AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole); | 
						|
						ITypeReference explicitInterfaceType = null; | 
						|
						if (!explicitInterfaceAstType.IsNull) { | 
						|
							explicitInterfaceType = explicitInterfaceAstType.ToTypeReference(); | 
						|
						} | 
						|
						member = AbstractUnresolvedMember.Resolve( | 
						|
							resolver.CurrentTypeResolveContext, entityType, memberDeclaration.Name, | 
						|
							explicitInterfaceType, typeParameterNames, parameterTypes); | 
						|
					} | 
						|
				} | 
						|
				resolver = resolver.WithCurrentMember(member); | 
						|
				ScanChildren(memberDeclaration); | 
						|
				 | 
						|
				if (member != null) | 
						|
					return new MemberResolveResult(null, member, false); | 
						|
				else | 
						|
					return errorResult; | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration) | 
						|
		{ | 
						|
			return VisitMethodMember(methodDeclaration); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration) | 
						|
		{ | 
						|
			return VisitMethodMember(operatorDeclaration); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) | 
						|
		{ | 
						|
			return VisitMethodMember(constructorDeclaration); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration) | 
						|
		{ | 
						|
			return VisitMethodMember(destructorDeclaration); | 
						|
		} | 
						|
		 | 
						|
		// handle properties/indexers | 
						|
		ResolveResult VisitPropertyMember(EntityDeclaration propertyOrIndexerDeclaration) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				IMember member; | 
						|
				if (unresolvedFile != null) { | 
						|
					member = GetMemberFromLocation(propertyOrIndexerDeclaration); | 
						|
				} else { | 
						|
					// Re-discover the property: | 
						|
					string name = propertyOrIndexerDeclaration.Name; | 
						|
					var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter)); | 
						|
					AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole); | 
						|
					ITypeReference explicitInterfaceType = null; | 
						|
					if (!explicitInterfaceAstType.IsNull) { | 
						|
						explicitInterfaceType = explicitInterfaceAstType.ToTypeReference(); | 
						|
					} | 
						|
					member = AbstractUnresolvedMember.Resolve( | 
						|
						resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.EntityType, name, | 
						|
						explicitInterfaceType, parameterTypeReferences: parameterTypeReferences); | 
						|
				} | 
						|
				// We need to use the property as current member so that indexer parameters can be resolved correctly. | 
						|
				resolver = resolver.WithCurrentMember(member); | 
						|
				var resolverWithPropertyAsMember = resolver; | 
						|
				 | 
						|
				for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) { | 
						|
					if (node.Role == PropertyDeclaration.GetterRole && member is IProperty) { | 
						|
						resolver = resolver.WithCurrentMember(((IProperty)member).Getter); | 
						|
						Scan(node); | 
						|
						resolver = resolverWithPropertyAsMember; | 
						|
					} else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) { | 
						|
						resolver = resolver.WithCurrentMember(((IProperty)member).Setter); | 
						|
						Scan(node); | 
						|
						resolver = resolverWithPropertyAsMember; | 
						|
					} else { | 
						|
						Scan(node); | 
						|
					} | 
						|
				} | 
						|
				if (member != null) | 
						|
					return new MemberResolveResult(null, member, false); | 
						|
				else | 
						|
					return errorResult; | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) | 
						|
		{ | 
						|
			return VisitPropertyMember(propertyDeclaration); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) | 
						|
		{ | 
						|
			return VisitPropertyMember(indexerDeclaration); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				IMember member; | 
						|
				if (unresolvedFile != null) { | 
						|
					member = GetMemberFromLocation(eventDeclaration); | 
						|
				} else { | 
						|
					string name = eventDeclaration.Name; | 
						|
					AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType; | 
						|
					if (explicitInterfaceAstType.IsNull) { | 
						|
						member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name); | 
						|
					} else { | 
						|
						member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name, | 
						|
						                                          explicitInterfaceAstType.ToTypeReference()); | 
						|
					} | 
						|
				} | 
						|
				resolver = resolver.WithCurrentMember(member); | 
						|
				var resolverWithEventAsMember = resolver; | 
						|
				 | 
						|
				for (AstNode node = eventDeclaration.FirstChild; node != null; node = node.NextSibling) { | 
						|
					if (node.Role == CustomEventDeclaration.AddAccessorRole && member is IEvent) { | 
						|
						resolver = resolver.WithCurrentMember(((IEvent)member).AddAccessor); | 
						|
						Scan(node); | 
						|
						resolver = resolverWithEventAsMember; | 
						|
					} else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) { | 
						|
						resolver = resolver.WithCurrentMember(((IEvent)member).RemoveAccessor); | 
						|
						Scan(node); | 
						|
						resolver = resolverWithEventAsMember; | 
						|
					} else { | 
						|
						Scan(node); | 
						|
					} | 
						|
				} | 
						|
 | 
						|
				if (member != null) | 
						|
					return new MemberResolveResult(null, member, false); | 
						|
				else | 
						|
					return errorResult; | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) | 
						|
		{ | 
						|
			ScanChildren(parameterDeclaration); | 
						|
			if (resolverEnabled) { | 
						|
				string name = parameterDeclaration.Name; | 
						|
				 | 
						|
				if (parameterDeclaration.Parent is DocumentationReference) { | 
						|
					// create a dummy parameter | 
						|
					IType type = ResolveType(parameterDeclaration.Type); | 
						|
					switch (parameterDeclaration.ParameterModifier) { | 
						|
						case ParameterModifier.Ref: | 
						|
						case ParameterModifier.Out: | 
						|
							type = new ByReferenceType(type); | 
						|
							break; | 
						|
					} | 
						|
					return new LocalResolveResult(new DefaultParameter( | 
						|
						type, name, | 
						|
						isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref, | 
						|
						isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out, | 
						|
						isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params)); | 
						|
				} | 
						|
				 | 
						|
				// Look in lambda parameters: | 
						|
				foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) { | 
						|
					if (p.Name == name) | 
						|
						return new LocalResolveResult(p); | 
						|
				} | 
						|
				 | 
						|
				IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember; | 
						|
				if (pm == null && resolver.CurrentTypeDefinition != null) { | 
						|
					// Also consider delegate parameters: | 
						|
					pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod(); | 
						|
					// pm will be null if the current type isn't a delegate | 
						|
				} | 
						|
				if (pm != null) { | 
						|
					foreach (IParameter p in pm.Parameters) { | 
						|
						if (p.Name == name) { | 
						|
							return new LocalResolveResult(p); | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				 | 
						|
				return errorResult; | 
						|
			} else { | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) | 
						|
		{ | 
						|
			ScanChildren(typeParameterDeclaration); | 
						|
			if (resolverEnabled) { | 
						|
				string name = typeParameterDeclaration.Name; | 
						|
				IMethod m = resolver.CurrentMember as IMethod; | 
						|
				if (m != null) { | 
						|
					foreach (var tp in m.TypeParameters) { | 
						|
						if (tp.Name == name) | 
						|
							return new TypeResolveResult(tp); | 
						|
					} | 
						|
				} | 
						|
				if (resolver.CurrentTypeDefinition != null) { | 
						|
					var typeParameters = resolver.CurrentTypeDefinition.TypeParameters; | 
						|
					// look backwards so that TPs in the current type take precedence over those copied from outer types | 
						|
					for (int i = typeParameters.Count - 1; i >= 0; i--) { | 
						|
						if (typeParameters[i].Name == name) | 
						|
							return new TypeResolveResult(typeParameters[i]); | 
						|
					} | 
						|
				} | 
						|
				return errorResult; | 
						|
			} else { | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				// Scan enum member attributes before setting resolver.CurrentMember, so that | 
						|
				// enum values used as attribute arguments have the correct type. | 
						|
				// (within an enum member, all other enum members are treated as having their underlying type) | 
						|
				foreach (var attributeSection in enumMemberDeclaration.Attributes) | 
						|
					Scan(attributeSection); | 
						|
				 | 
						|
				IMember member = null; | 
						|
				if (unresolvedFile != null) { | 
						|
					member = GetMemberFromLocation(enumMemberDeclaration); | 
						|
				} else if (resolver.CurrentTypeDefinition != null) { | 
						|
					string name = enumMemberDeclaration.Name; | 
						|
					member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); | 
						|
				} | 
						|
				resolver = resolver.WithCurrentMember(member); | 
						|
				 | 
						|
				if (resolverEnabled && resolver.CurrentTypeDefinition != null) { | 
						|
					ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType); | 
						|
					if (resolverEnabled && member != null) | 
						|
						return new MemberResolveResult(null, member, false); | 
						|
					else | 
						|
						return errorResult; | 
						|
				} else { | 
						|
					Scan(enumMemberDeclaration.Initializer); | 
						|
					return null; | 
						|
				} | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Track CheckForOverflow | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCheckedExpression(CheckedExpression checkedExpression) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				resolver = resolver.WithCheckForOverflow(true); | 
						|
				if (resolverEnabled) { | 
						|
					return Resolve(checkedExpression.Expression); | 
						|
				} else { | 
						|
					ScanChildren(checkedExpression); | 
						|
					return null; | 
						|
				} | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedExpression(UncheckedExpression uncheckedExpression) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				resolver = resolver.WithCheckForOverflow(false); | 
						|
				if (resolverEnabled) { | 
						|
					return Resolve(uncheckedExpression.Expression); | 
						|
				} else { | 
						|
					ScanChildren(uncheckedExpression); | 
						|
					return null; | 
						|
				} | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCheckedStatement(CheckedStatement checkedStatement) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				resolver = resolver.WithCheckForOverflow(true); | 
						|
				ScanChildren(checkedStatement); | 
						|
				return voidResult; | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedStatement(UncheckedStatement uncheckedStatement) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			try { | 
						|
				resolver = resolver.WithCheckForOverflow(false); | 
						|
				ScanChildren(uncheckedStatement); | 
						|
				return voidResult; | 
						|
			} finally { | 
						|
				resolver = oldResolver; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Visit AnonymousTypeCreateExpression | 
						|
		static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr) | 
						|
		{ | 
						|
			if (expr is NamedExpression) { | 
						|
				var namedArgExpr = (NamedExpression)expr; | 
						|
				resolveExpr = namedArgExpr.Expression; | 
						|
				return namedArgExpr.Name; | 
						|
			} | 
						|
			// no name given, so it's a projection initializer | 
						|
			if (expr is MemberReferenceExpression) { | 
						|
				resolveExpr = expr; | 
						|
				return ((MemberReferenceExpression)expr).MemberName; | 
						|
			} | 
						|
			if (expr is IdentifierExpression) { | 
						|
				resolveExpr = expr; | 
						|
				return ((IdentifierExpression)expr).Identifier; | 
						|
			} | 
						|
			resolveExpr = null; | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		class AnonymousTypeMember | 
						|
		{ | 
						|
			public readonly Expression Expression; | 
						|
			public readonly ResolveResult Initializer; | 
						|
			 | 
						|
			public AnonymousTypeMember(Expression expression, ResolveResult initializer) | 
						|
			{ | 
						|
				this.Expression = expression; | 
						|
				this.Initializer = initializer; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression) | 
						|
		{ | 
						|
			// 7.6.10.6 Anonymous object creation expressions | 
						|
			List<IUnresolvedProperty> unresolvedProperties = new List<IUnresolvedProperty>(); | 
						|
			List<AnonymousTypeMember> members = new List<AnonymousTypeMember>(); | 
						|
			foreach (var expr in anonymousTypeCreateExpression.Initializers) { | 
						|
				Expression resolveExpr; | 
						|
				var name = GetAnonymousTypePropertyName(expr, out resolveExpr); | 
						|
				if (resolveExpr != null) { | 
						|
					var initRR = Resolve(resolveExpr); | 
						|
					var returnTypeRef = initRR.Type.ToTypeReference(); | 
						|
					var property = new DefaultUnresolvedProperty { | 
						|
						Name = name, | 
						|
						Accessibility = Accessibility.Public, | 
						|
						ReturnType = returnTypeRef, | 
						|
						Getter = new DefaultUnresolvedMethod { | 
						|
							Name = "get_" + name, | 
						|
							Accessibility = Accessibility.Public, | 
						|
							ReturnType = returnTypeRef | 
						|
						} | 
						|
					}; | 
						|
					unresolvedProperties.Add(property); | 
						|
					members.Add(new AnonymousTypeMember(expr, initRR)); | 
						|
				} else { | 
						|
					Scan(expr); | 
						|
				} | 
						|
			} | 
						|
			var anonymousType = new AnonymousType(resolver.Compilation, unresolvedProperties); | 
						|
			var properties = anonymousType.GetProperties().ToList(); | 
						|
			Debug.Assert(properties.Count == members.Count); | 
						|
			List<ResolveResult> assignments = new List<ResolveResult>(); | 
						|
			for (int i = 0; i < members.Count; i++) { | 
						|
				ResolveResult lhs = new MemberResolveResult(new InitializedObjectResolveResult(anonymousType), properties[i]); | 
						|
				ResolveResult rhs = members[i].Initializer; | 
						|
				ResolveResult assignment = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhs, rhs); | 
						|
				var ne = members[i].Expression as NamedExpression; | 
						|
				if (ne != null) { | 
						|
					StoreCurrentState(ne); | 
						|
					// ne.Expression was already resolved by the first loop | 
						|
					StoreResult(ne, lhs); | 
						|
				} | 
						|
				assignments.Add(assignment); | 
						|
			} | 
						|
			var anonymousCtor = DefaultResolvedMethod.GetDummyConstructor(resolver.Compilation, anonymousType); | 
						|
			return new InvocationResolveResult(null, anonymousCtor, initializerStatements: assignments); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Visit Expressions | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression) | 
						|
		{ | 
						|
			int dimensions = arrayCreateExpression.Arguments.Count; | 
						|
			ResolveResult[] sizeArguments; | 
						|
			IEnumerable<ArraySpecifier> additionalArraySpecifiers; | 
						|
			if (dimensions == 0) { | 
						|
				var firstSpecifier = arrayCreateExpression.AdditionalArraySpecifiers.FirstOrDefault(); | 
						|
				if (firstSpecifier != null) { | 
						|
					dimensions = firstSpecifier.Dimensions; | 
						|
					additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers.Skip(1); | 
						|
				} else { | 
						|
					dimensions = 0; | 
						|
					additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; | 
						|
				} | 
						|
				sizeArguments = null; | 
						|
			} else { | 
						|
				sizeArguments = new ResolveResult[dimensions]; | 
						|
				int pos = 0; | 
						|
				foreach (var node in arrayCreateExpression.Arguments) | 
						|
					sizeArguments[pos++] = Resolve(node); | 
						|
				additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; | 
						|
			} | 
						|
			 | 
						|
			List<Expression> initializerElements; | 
						|
			ResolveResult[] initializerElementResults; | 
						|
			if (arrayCreateExpression.Initializer.IsNull) { | 
						|
				initializerElements = null; | 
						|
				initializerElementResults = null; | 
						|
			} else { | 
						|
				StoreCurrentState(arrayCreateExpression.Initializer); | 
						|
				 | 
						|
				initializerElements = new List<Expression>(); | 
						|
				UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions, true); | 
						|
				initializerElementResults = new ResolveResult[initializerElements.Count]; | 
						|
				for (int i = 0; i < initializerElementResults.Length; i++) { | 
						|
					initializerElementResults[i] = Resolve(initializerElements[i]); | 
						|
				} | 
						|
				StoreResult(arrayCreateExpression.Initializer, voidResult); | 
						|
			} | 
						|
			 | 
						|
			ArrayCreateResolveResult acrr; | 
						|
			if (arrayCreateExpression.Type.IsNull) { | 
						|
				acrr = resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElementResults); | 
						|
			} else { | 
						|
				IType elementType = ResolveType(arrayCreateExpression.Type); | 
						|
				foreach (var spec in additionalArraySpecifiers.Reverse()) { | 
						|
					elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions); | 
						|
				} | 
						|
				acrr = resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElementResults); | 
						|
			} | 
						|
			return acrr; | 
						|
		} | 
						|
		 | 
						|
		void UnpackArrayInitializer(List<Expression> elementList, ArrayInitializerExpression initializer, int dimensions, bool resolveNestedInitializesToVoid) | 
						|
		{ | 
						|
			Debug.Assert(dimensions >= 1); | 
						|
			if (dimensions > 1) { | 
						|
				foreach (var node in initializer.Elements) { | 
						|
					ArrayInitializerExpression aie = node as ArrayInitializerExpression; | 
						|
					if (aie != null) { | 
						|
						if (resolveNestedInitializesToVoid) { | 
						|
							StoreCurrentState(aie); | 
						|
							StoreResult(aie, voidResult); | 
						|
						} | 
						|
						UnpackArrayInitializer(elementList, aie, dimensions - 1, resolveNestedInitializesToVoid); | 
						|
					} else { | 
						|
						elementList.Add(node); | 
						|
					} | 
						|
				} | 
						|
			} else { | 
						|
				foreach (var expr in initializer.Elements) | 
						|
					elementList.Add(expr); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression) | 
						|
		{ | 
						|
			// Array initializers are handled by their parent expression. | 
						|
			ScanChildren(arrayInitializerExpression); | 
						|
			return errorResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAsExpression(AsExpression asExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveResult input = Resolve(asExpression.Expression); | 
						|
				var targetType = ResolveType(asExpression.Type); | 
						|
				return new ConversionResolveResult(targetType, input, Conversion.TryCast, resolver.CheckForOverflow); | 
						|
			} else { | 
						|
				ScanChildren(asExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAssignmentExpression(AssignmentExpression assignmentExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				Expression left = assignmentExpression.Left; | 
						|
				Expression right = assignmentExpression.Right; | 
						|
				ResolveResult leftResult = Resolve(left); | 
						|
				ResolveResult rightResult = Resolve(right); | 
						|
				ResolveResult rr = resolver.ResolveAssignment(assignmentExpression.Operator, leftResult, rightResult); | 
						|
				ProcessConversionsInBinaryOperatorResult(left, right, rr); | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(assignmentExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				return resolver.ResolveBaseReference(); | 
						|
			} else { | 
						|
				ScanChildren(baseReferenceExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				Expression left = binaryOperatorExpression.Left; | 
						|
				Expression right = binaryOperatorExpression.Right; | 
						|
				ResolveResult leftResult = Resolve(left); | 
						|
				ResolveResult rightResult = Resolve(right); | 
						|
				ResolveResult rr = resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, leftResult, rightResult); | 
						|
				ProcessConversionsInBinaryOperatorResult(left, right, rr); | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(binaryOperatorExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ProcessConversionsInBinaryOperatorResult(Expression left, Expression right, ResolveResult rr) | 
						|
		{ | 
						|
			OperatorResolveResult orr = rr as OperatorResolveResult; | 
						|
			if (orr != null && orr.Operands.Count == 2) { | 
						|
				ProcessConversionResult(left, orr.Operands[0] as ConversionResolveResult); | 
						|
				ProcessConversionResult(right, orr.Operands[1] as ConversionResolveResult); | 
						|
			} else { | 
						|
				InvocationResolveResult irr = rr as InvocationResolveResult; | 
						|
				if (irr != null && irr.Arguments.Count == 2) { | 
						|
					ProcessConversionResult(left, irr.Arguments[0] as ConversionResolveResult); | 
						|
					ProcessConversionResult(right, irr.Arguments[1] as ConversionResolveResult); | 
						|
				} | 
						|
			} | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCastExpression(CastExpression castExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				IType targetType = ResolveType(castExpression.Type); | 
						|
				Expression expr = castExpression.Expression; | 
						|
				ResolveResult rr = resolver.ResolveCast(targetType, Resolve(expr)); | 
						|
				ProcessConversionResult(expr, rr as ConversionResolveResult); | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(castExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				Expression condition = conditionalExpression.Condition; | 
						|
				Expression trueExpr = conditionalExpression.TrueExpression; | 
						|
				Expression falseExpr = conditionalExpression.FalseExpression; | 
						|
				 | 
						|
				ResolveResult rr = resolver.ResolveConditional(Resolve(condition), Resolve(trueExpr), Resolve(falseExpr)); | 
						|
				OperatorResolveResult corr = rr as OperatorResolveResult; | 
						|
				if (corr != null && corr.Operands.Count == 3) { | 
						|
					ProcessConversionResult(condition, corr.Operands[0] as ConversionResolveResult); | 
						|
					ProcessConversionResult(trueExpr, corr.Operands[1] as ConversionResolveResult); | 
						|
					ProcessConversionResult(falseExpr, corr.Operands[2] as ConversionResolveResult); | 
						|
				} | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(conditionalExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				return resolver.ResolveDefaultValue(ResolveType(defaultValueExpression.Type)); | 
						|
			} else { | 
						|
				ScanChildren(defaultValueExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDirectionExpression(DirectionExpression directionExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveResult rr = Resolve(directionExpression.Expression); | 
						|
				return new ByReferenceResolveResult(rr, directionExpression.FieldDirection == FieldDirection.Out); | 
						|
			} else { | 
						|
				ScanChildren(directionExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitEmptyExpression(EmptyExpression emptyExpression) | 
						|
		{ | 
						|
			return errorResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression) | 
						|
		{ | 
						|
			if (resolverEnabled || NeedsResolvingDueToNamedArguments(indexerExpression)) { | 
						|
				Expression target = indexerExpression.Target; | 
						|
				ResolveResult targetResult = Resolve(target); | 
						|
				string[] argumentNames; | 
						|
				ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames); | 
						|
				ResolveResult rr = resolver.ResolveIndexer(targetResult, arguments, argumentNames); | 
						|
				ArrayAccessResolveResult aarr = rr as ArrayAccessResolveResult; | 
						|
				if (aarr != null) { | 
						|
					MarkUnknownNamedArguments(indexerExpression.Arguments); | 
						|
					ProcessConversionResults(indexerExpression.Arguments, aarr.Indexes); | 
						|
				} else { | 
						|
					ProcessInvocationResult(target, indexerExpression.Arguments, rr); | 
						|
				} | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(indexerExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIsExpression(IsExpression isExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveResult input = Resolve(isExpression.Expression); | 
						|
				IType targetType = ResolveType(isExpression.Type); | 
						|
				IType booleanType = resolver.Compilation.FindType(KnownTypeCode.Boolean); | 
						|
				return new TypeIsResolveResult(input, targetType, booleanType); | 
						|
			} else { | 
						|
				ScanChildren(isExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		// NamedArgumentExpression is "identifier: Expression" | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression) | 
						|
		{ | 
						|
			// The parent expression takes care of handling NamedArgumentExpressions | 
						|
			// by calling GetArguments(). | 
						|
			// This method gets called only when scanning, or when the named argument is used | 
						|
			// in an invalid context. | 
						|
			if (resolverEnabled) { | 
						|
				return new NamedArgumentResolveResult(namedArgumentExpression.Name, Resolve(namedArgumentExpression.Expression)); | 
						|
			} else { | 
						|
				Scan(namedArgumentExpression.Expression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		// NamedExpression is "identifier = Expression" in object initializers and attributes | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitNamedExpression(NamedExpression namedExpression) | 
						|
		{ | 
						|
			// The parent expression takes care of handling NamedExpression | 
						|
			// by calling HandleObjectInitializer() or HandleNamedExpression(). | 
						|
			// This method gets called only when scanning, or when the named expression is used | 
						|
			// in an invalid context. | 
						|
			ScanChildren(namedExpression); | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		void HandleNamedExpression(NamedExpression namedExpression, List<ResolveResult> initializerStatements) | 
						|
		{ | 
						|
			StoreCurrentState(namedExpression); | 
						|
			Expression rhs = namedExpression.Expression; | 
						|
			ResolveResult lhsRR = resolver.ResolveIdentifierInObjectInitializer(namedExpression.Name); | 
						|
			if (rhs is ArrayInitializerExpression) { | 
						|
				HandleObjectInitializer(lhsRR, (ArrayInitializerExpression)rhs, initializerStatements); | 
						|
			} else { | 
						|
				var rhsRR = Resolve(rhs); | 
						|
				var rr = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhsRR, rhsRR) as OperatorResolveResult; | 
						|
				if (rr != null) { | 
						|
					ProcessConversionResult(rhs, rr.Operands[1] as ConversionResolveResult); | 
						|
					initializerStatements.Add(rr); | 
						|
				} | 
						|
			} | 
						|
			StoreResult(namedExpression, lhsRR); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression) | 
						|
		{ | 
						|
			return resolver.ResolvePrimitive(null); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) | 
						|
		{ | 
						|
			var typeResolveResult = Resolve(objectCreateExpression.Type); | 
						|
			if (typeResolveResult.IsError) { | 
						|
				ScanChildren (objectCreateExpression); | 
						|
				return typeResolveResult; | 
						|
			} | 
						|
			IType type = typeResolveResult.Type; | 
						|
			 | 
						|
			List<ResolveResult> initializerStatements = null; | 
						|
			var initializer = objectCreateExpression.Initializer; | 
						|
			if (!initializer.IsNull) { | 
						|
				initializerStatements = new List<ResolveResult>(); | 
						|
				HandleObjectInitializer(new InitializedObjectResolveResult(type), initializer, initializerStatements); | 
						|
			} | 
						|
			 | 
						|
			string[] argumentNames; | 
						|
			ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames); | 
						|
			 | 
						|
			ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); | 
						|
			if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) { | 
						|
				MarkUnknownNamedArguments(objectCreateExpression.Arguments); | 
						|
				// Apply conversion to argument if it directly wraps the argument | 
						|
				// (but not when creating a delegate from a delegate, as then there would be a MGRR for .Invoke in between) | 
						|
				// This is necessary for lambda type inference. | 
						|
				var crr = rr as ConversionResolveResult; | 
						|
				if (crr != null && crr.Input == arguments[0]) { | 
						|
					ProcessConversionResult(objectCreateExpression.Arguments.Single(), crr); | 
						|
					 | 
						|
					// wrap the result so that the delegate creation is not handled as a reference | 
						|
					// to the target method - otherwise FindReferencedEntities would produce two results for | 
						|
					// the same delegate creation. | 
						|
					return WrapResult(rr); | 
						|
				} else { | 
						|
					return rr; | 
						|
				} | 
						|
			} else { | 
						|
				// process conversions in all other cases | 
						|
				ProcessInvocationResult(null, objectCreateExpression.Arguments, rr); | 
						|
				return rr; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void HandleObjectInitializer(ResolveResult initializedObject, ArrayInitializerExpression initializer, List<ResolveResult> initializerStatements) | 
						|
		{ | 
						|
			StoreCurrentState(initializer); | 
						|
			resolver = resolver.PushObjectInitializer(initializedObject); | 
						|
			foreach (Expression element in initializer.Elements) { | 
						|
				ArrayInitializerExpression aie = element as ArrayInitializerExpression; | 
						|
				if (aie != null) { | 
						|
					StoreCurrentState(aie); | 
						|
					// constructor argument list in collection initializer | 
						|
					ResolveResult[] addArguments = new ResolveResult[aie.Elements.Count]; | 
						|
					int i = 0; | 
						|
					foreach (var addArgument in aie.Elements) { | 
						|
						addArguments[i++] = Resolve(addArgument); | 
						|
					} | 
						|
					MemberLookup memberLookup = resolver.CreateMemberLookup(); | 
						|
					var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true); | 
						|
					var mgrr = addRR as MethodGroupResolveResult; | 
						|
					if (mgrr != null) { | 
						|
						OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.CheckForOverflow, resolver.conversions); | 
						|
						var invocationRR = or.CreateResolveResult(initializedObject); | 
						|
						StoreResult(aie, invocationRR); | 
						|
						ProcessInvocationResult(null, aie.Elements, invocationRR); | 
						|
						initializerStatements.Add(invocationRR); | 
						|
					} else { | 
						|
						StoreResult(aie, addRR); | 
						|
					} | 
						|
				} else if (element is NamedExpression) { | 
						|
					HandleNamedExpression((NamedExpression)element, initializerStatements); | 
						|
				} else { | 
						|
					// unknown kind of expression | 
						|
					Scan(element); | 
						|
				} | 
						|
			} | 
						|
			resolver = resolver.PopObjectInitializer(); | 
						|
			StoreResult(initializer, voidResult); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				return Resolve(parenthesizedExpression.Expression); | 
						|
			} else { | 
						|
				Scan(parenthesizedExpression.Expression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveResult target = Resolve(pointerReferenceExpression.Target); | 
						|
				ResolveResult deferencedTarget = resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, target); | 
						|
				List<IType> typeArguments = new List<IType>(); | 
						|
				foreach (AstType typeArgument in pointerReferenceExpression.TypeArguments) { | 
						|
					typeArguments.Add(ResolveType(typeArgument)); | 
						|
				} | 
						|
				return resolver.ResolveMemberAccess(deferencedTarget, pointerReferenceExpression.MemberName, | 
						|
				                                    typeArguments, | 
						|
				                                    GetNameLookupMode(pointerReferenceExpression)); | 
						|
			} else { | 
						|
				ScanChildren(pointerReferenceExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression) | 
						|
		{ | 
						|
			return resolver.ResolvePrimitive(primitiveExpression.Value); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitSizeOfExpression(SizeOfExpression sizeOfExpression) | 
						|
		{ | 
						|
			return resolver.ResolveSizeOf(ResolveType(sizeOfExpression.Type)); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitStackAllocExpression(StackAllocExpression stackAllocExpression) | 
						|
		{ | 
						|
			ResolveAndProcessConversion(stackAllocExpression.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32)); | 
						|
			return new ResolveResult(new PointerType(ResolveType(stackAllocExpression.Type))); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression) | 
						|
		{ | 
						|
			return resolver.ResolveThisReference(); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitTypeOfExpression(TypeOfExpression typeOfExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				return resolver.ResolveTypeOf(ResolveType(typeOfExpression.Type)); | 
						|
			} else { | 
						|
				Scan(typeOfExpression.Type); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				return Resolve(typeReferenceExpression.Type).ShallowClone(); | 
						|
			} else { | 
						|
				Scan(typeReferenceExpression.Type); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				Expression expr = unaryOperatorExpression.Expression; | 
						|
				ResolveResult input = Resolve(expr); | 
						|
				ITypeDefinition inputTypeDef = input.Type.GetDefinition(); | 
						|
				if (input.IsCompileTimeConstant && expr is PrimitiveExpression && inputTypeDef != null) { | 
						|
					// Special cases for int.MinValue and long.MinValue | 
						|
					if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt32 && 2147483648.Equals(input.ConstantValue)) { | 
						|
						return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int32), -2147483648); | 
						|
					} else if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt64 && 9223372036854775808.Equals(input.ConstantValue)) { | 
						|
						return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int64), -9223372036854775808); | 
						|
					} | 
						|
				} | 
						|
				ResolveResult rr = resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, input); | 
						|
				OperatorResolveResult uorr = rr as OperatorResolveResult; | 
						|
				if (uorr != null && uorr.Operands.Count == 1) { | 
						|
					ProcessConversionResult(expr, uorr.Operands[0] as ConversionResolveResult); | 
						|
				} else { | 
						|
					InvocationResolveResult irr = rr as InvocationResolveResult; | 
						|
					if (irr != null && irr.Arguments.Count == 1) { | 
						|
						ProcessConversionResult(expr, irr.Arguments[0] as ConversionResolveResult); | 
						|
					} | 
						|
				} | 
						|
				return rr; | 
						|
			} else { | 
						|
				ScanChildren(unaryOperatorExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression) | 
						|
		{ | 
						|
			ScanChildren(undocumentedExpression); | 
						|
			IType resultType; | 
						|
			switch (undocumentedExpression.UndocumentedExpressionType) { | 
						|
				case UndocumentedExpressionType.ArgListAccess: | 
						|
				case UndocumentedExpressionType.ArgList: | 
						|
					resultType = resolver.Compilation.FindType(typeof(RuntimeArgumentHandle)); | 
						|
					break; | 
						|
				case UndocumentedExpressionType.RefValue: | 
						|
					var tre = undocumentedExpression.Arguments.ElementAtOrDefault(1) as TypeReferenceExpression; | 
						|
					if (tre != null) | 
						|
						resultType = ResolveType(tre.Type); | 
						|
					else | 
						|
						resultType = SpecialType.UnknownType; | 
						|
					break; | 
						|
				case UndocumentedExpressionType.RefType: | 
						|
					resultType = resolver.Compilation.FindType(KnownTypeCode.Type); | 
						|
					break; | 
						|
				case UndocumentedExpressionType.MakeRef: | 
						|
					resultType = resolver.Compilation.FindType(typeof(TypedReference)); | 
						|
					break; | 
						|
				default: | 
						|
					throw new InvalidOperationException("Invalid value for UndocumentedExpressionType"); | 
						|
			} | 
						|
			return new ResolveResult(resultType); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Visit Identifier/MemberReference/Invocation-Expression | 
						|
		// IdentifierExpression, MemberReferenceExpression and InvocationExpression | 
						|
		// are grouped together because they have to work together for | 
						|
		// "7.6.4.1 Identical simple names and type names" support | 
						|
		List<IType> ResolveTypeArguments(IEnumerable<AstType> typeArguments) | 
						|
		{ | 
						|
			List<IType> result = new List<IType>(); | 
						|
			foreach (AstType typeArgument in typeArguments) { | 
						|
				result.Add(ResolveType(typeArgument)); | 
						|
			} | 
						|
			return result; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets and resolves the arguments; unpacking any NamedArgumentExpressions. | 
						|
		/// </summary> | 
						|
		/// <remarks> | 
						|
		/// Callers of GetArguments must also call either ProcessConversionsInInvocation or MarkUnknownNamedArguments | 
						|
		/// to ensure the named arguments get resolved. | 
						|
		/// Also, as named arguments get resolved by the parent node, the parent node must not scan | 
						|
		/// into the argument list without being resolved - see NeedsResolvingDueToNamedArguments(). | 
						|
		/// </remarks> | 
						|
		ResolveResult[] GetArguments(IEnumerable<Expression> argumentExpressions, out string[] argumentNames) | 
						|
		{ | 
						|
			argumentNames = null; | 
						|
			ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; | 
						|
			int i = 0; | 
						|
			foreach (AstNode argument in argumentExpressions) { | 
						|
				NamedArgumentExpression nae = argument as NamedArgumentExpression; | 
						|
				AstNode argumentValue; | 
						|
				if (nae != null) { | 
						|
					if (argumentNames == null) | 
						|
						argumentNames = new string[arguments.Length]; | 
						|
					argumentNames[i] = nae.Name; | 
						|
					argumentValue = nae.Expression; | 
						|
				} else { | 
						|
					argumentValue = argument; | 
						|
				} | 
						|
				arguments[i++] = Resolve(argumentValue); | 
						|
			} | 
						|
			return arguments; | 
						|
		} | 
						|
		 | 
						|
		bool NeedsResolvingDueToNamedArguments(Expression nodeWithArguments) | 
						|
		{ | 
						|
			for (AstNode child = nodeWithArguments.FirstChild; child != null; child = child.NextSibling) { | 
						|
				if (child is NamedArgumentExpression) | 
						|
					return true; | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
		 | 
						|
		static NameLookupMode GetNameLookupMode(Expression expr) | 
						|
		{ | 
						|
			InvocationExpression ie = expr.Parent as InvocationExpression; | 
						|
			if (ie != null && ie.Target == expr) | 
						|
				return NameLookupMode.InvocationTarget; | 
						|
			else | 
						|
				return NameLookupMode.Expression; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether 'rr' is considered a static access on the target identifier. | 
						|
		/// </summary> | 
						|
		/// <param name="rr">Resolve Result of the MemberReferenceExpression</param> | 
						|
		/// <param name="invocationRR">Resolve Result of the InvocationExpression</param> | 
						|
		bool IsStaticResult(ResolveResult rr, ResolveResult invocationRR) | 
						|
		{ | 
						|
			if (rr is TypeResolveResult) | 
						|
				return true; | 
						|
			MemberResolveResult mrr = (rr is MethodGroupResolveResult ? invocationRR : rr) as MemberResolveResult; | 
						|
			return mrr != null && mrr.Member.IsStatic; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIdentifierExpression(IdentifierExpression identifierExpression) | 
						|
		{ | 
						|
			// Note: this method is not called when it occurs in a situation where an ambiguity between | 
						|
			// simple names and type names might occur. | 
						|
			if (resolverEnabled) { | 
						|
				var typeArguments = ResolveTypeArguments(identifierExpression.TypeArguments); | 
						|
				var lookupMode = GetNameLookupMode(identifierExpression); | 
						|
				return resolver.LookupSimpleNameOrTypeName( | 
						|
					identifierExpression.Identifier, typeArguments, lookupMode); | 
						|
			} else { | 
						|
				ScanChildren(identifierExpression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression) | 
						|
		{ | 
						|
			// target = Resolve(identifierExpression = memberReferenceExpression.Target) | 
						|
			// trr = ResolveType(identifierExpression) | 
						|
			// rr = Resolve(memberReferenceExpression) | 
						|
			 | 
						|
			IdentifierExpression identifierExpression = memberReferenceExpression.Target as IdentifierExpression; | 
						|
			if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { | 
						|
				// Special handling for §7.6.4.1 Identicial simple names and type names | 
						|
				StoreCurrentState(identifierExpression); | 
						|
				ResolveResult target = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance); | 
						|
				TypeResolveResult trr; | 
						|
				if (resolver.IsVariableReferenceWithSameType(target, identifierExpression.Identifier, out trr)) { | 
						|
					// It's ambiguous | 
						|
					ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); | 
						|
					ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target; | 
						|
					Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR); | 
						|
					StoreResult(identifierExpression, simpleNameRR); | 
						|
					return rr; | 
						|
				} else { | 
						|
					// It's not ambiguous | 
						|
					Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target); | 
						|
					StoreResult(identifierExpression, target); | 
						|
					return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); | 
						|
				} | 
						|
			} else { | 
						|
				// Regular code path | 
						|
				if (resolverEnabled) { | 
						|
					ResolveResult target = Resolve(memberReferenceExpression.Target); | 
						|
					return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); | 
						|
				} else { | 
						|
					ScanChildren(memberReferenceExpression); | 
						|
					return null; | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ResolveMemberReferenceOnGivenTarget(ResolveResult target, MemberReferenceExpression memberReferenceExpression) | 
						|
		{ | 
						|
			var typeArguments = ResolveTypeArguments(memberReferenceExpression.TypeArguments); | 
						|
			return resolver.ResolveMemberAccess( | 
						|
				target, memberReferenceExpression.MemberName, typeArguments, | 
						|
				GetNameLookupMode(memberReferenceExpression)); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitInvocationExpression(InvocationExpression invocationExpression) | 
						|
		{ | 
						|
			// rr = Resolve(invocationExpression) | 
						|
			// target = Resolve(memberReferenceExpression = invocationExpression.Target) | 
						|
			// idRR = Resolve(identifierExpression = memberReferenceExpression.Target) | 
						|
			// trr = ResolveType(identifierExpression) | 
						|
			 | 
						|
			MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression; | 
						|
			IdentifierExpression identifierExpression = mre != null ? mre.Target as IdentifierExpression : null; | 
						|
			if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { | 
						|
				// Special handling for §7.6.4.1 Identicial simple names and type names | 
						|
				 | 
						|
				StoreCurrentState(identifierExpression); | 
						|
				StoreCurrentState(mre); | 
						|
				 | 
						|
				ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance); | 
						|
				ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre); | 
						|
				Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target); | 
						|
				StoreResult(mre, target); | 
						|
				TypeResolveResult trr; | 
						|
				if (resolver.IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) { | 
						|
					// It's ambiguous | 
						|
					ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression); | 
						|
					ResolveResult simpleNameRR = IsStaticResult(target, rr) ? trr : idRR; | 
						|
					Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", | 
						|
					              identifierExpression, simpleNameRR); | 
						|
					StoreResult(identifierExpression, simpleNameRR); | 
						|
					return rr; | 
						|
				} else { | 
						|
					// It's not ambiguous | 
						|
					Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR); | 
						|
					StoreResult(identifierExpression, idRR); | 
						|
					return ResolveInvocationOnGivenTarget(target, invocationExpression); | 
						|
				} | 
						|
			} else { | 
						|
				// Regular code path | 
						|
				if (resolverEnabled || NeedsResolvingDueToNamedArguments(invocationExpression)) { | 
						|
					ResolveResult target = Resolve(invocationExpression.Target); | 
						|
					return ResolveInvocationOnGivenTarget(target, invocationExpression); | 
						|
				} else { | 
						|
					ScanChildren(invocationExpression); | 
						|
					return null; | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ResolveInvocationOnGivenTarget(ResolveResult target, InvocationExpression invocationExpression) | 
						|
		{ | 
						|
			string[] argumentNames; | 
						|
			ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames); | 
						|
			ResolveResult rr = resolver.ResolveInvocation(target, arguments, argumentNames); | 
						|
			ProcessInvocationResult(invocationExpression.Target, invocationExpression.Arguments, rr); | 
						|
			return rr; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Lamdbas / Anonymous Functions | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) | 
						|
		{ | 
						|
			return HandleExplicitlyTypedLambda( | 
						|
				anonymousMethodExpression.Parameters, anonymousMethodExpression.Body, | 
						|
				isAnonymousMethod: true, | 
						|
				hasParameterList: anonymousMethodExpression.HasParameterList, | 
						|
				isAsync: anonymousMethodExpression.IsAsync); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitLambdaExpression(LambdaExpression lambdaExpression) | 
						|
		{ | 
						|
			bool isExplicitlyTyped = false; | 
						|
			bool isImplicitlyTyped = false; | 
						|
			foreach (var p in lambdaExpression.Parameters) { | 
						|
				isImplicitlyTyped |= p.Type.IsNull; | 
						|
				isExplicitlyTyped |= !p.Type.IsNull; | 
						|
			} | 
						|
			if (isExplicitlyTyped || !isImplicitlyTyped) { | 
						|
				return HandleExplicitlyTypedLambda( | 
						|
					lambdaExpression.Parameters, lambdaExpression.Body, | 
						|
					isAnonymousMethod: false, hasParameterList: true, isAsync: lambdaExpression.IsAsync); | 
						|
			} else { | 
						|
				return new ImplicitlyTypedLambda(lambdaExpression, this); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		#region Explicitly typed | 
						|
		ExplicitlyTypedLambda HandleExplicitlyTypedLambda( | 
						|
			AstNodeCollection<ParameterDeclaration> parameterDeclarations, | 
						|
			AstNode body, bool isAnonymousMethod, bool hasParameterList, bool isAsync) | 
						|
		{ | 
						|
			CSharpResolver oldResolver = resolver; | 
						|
			List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null; | 
						|
			//bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression; | 
						|
			resolver = resolver.WithIsWithinLambdaExpression(true); | 
						|
			foreach (var pd in parameterDeclarations) { | 
						|
				IType type = ResolveType(pd.Type); | 
						|
				if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out) | 
						|
					type = new ByReferenceType(type); | 
						|
				 | 
						|
				IParameter p = new DefaultParameter(type, pd.Name, MakeRegion(pd), | 
						|
				                                    isRef: pd.ParameterModifier == ParameterModifier.Ref, | 
						|
				                                    isOut: pd.ParameterModifier == ParameterModifier.Out); | 
						|
				// The parameter declaration must be scanned in the current context (without the new parameter) | 
						|
				// in order to be consistent with the context in which we resolved pd.Type. | 
						|
				StoreCurrentState(pd); | 
						|
				StoreResult(pd, new LocalResolveResult(p)); | 
						|
				ScanChildren(pd); | 
						|
				 | 
						|
				resolver = resolver.AddVariable(p); | 
						|
				parameters.Add(p); | 
						|
			} | 
						|
			 | 
						|
			var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, isAsync, resolver, this, body); | 
						|
			 | 
						|
			// Don't scan the lambda body here - we'll do that later when analyzing the ExplicitlyTypedLambda. | 
						|
			 | 
						|
			resolver = oldResolver; | 
						|
			return lambda; | 
						|
		} | 
						|
		 | 
						|
		DomRegion MakeRegion(AstNode node) | 
						|
		{ | 
						|
			if (unresolvedFile != null) | 
						|
				return new DomRegion(unresolvedFile.FileName, node.StartLocation, node.EndLocation); | 
						|
			else | 
						|
				return node.GetRegion(); | 
						|
		} | 
						|
		 | 
						|
		sealed class ExplicitlyTypedLambda : LambdaBase | 
						|
		{ | 
						|
			readonly IList<IParameter> parameters; | 
						|
			readonly bool isAnonymousMethod; | 
						|
			readonly bool isAsync; | 
						|
			 | 
						|
			CSharpResolver storedContext; | 
						|
			ResolveVisitor visitor; | 
						|
			AstNode body; | 
						|
			 | 
						|
			IType inferredReturnType; | 
						|
			IList<Expression> returnExpressions; | 
						|
			IList<ResolveResult> returnValues; | 
						|
			bool isValidAsVoidMethod; | 
						|
			bool isEndpointUnreachable; | 
						|
			 | 
						|
			// The actual return type is set when the lambda is applied by the conversion. | 
						|
			IType actualReturnType; | 
						|
			 | 
						|
			internal override bool IsUndecided { | 
						|
				get { return actualReturnType == null; } | 
						|
			} | 
						|
			 | 
						|
			internal override AstNode LambdaExpression { | 
						|
				get { return body.Parent; } | 
						|
			} | 
						|
			 | 
						|
			internal override AstNode BodyExpression { | 
						|
				get { return body; } | 
						|
			} | 
						|
			 | 
						|
			public override ResolveResult Body { | 
						|
				get { | 
						|
					if (body is Expression) { | 
						|
						Analyze(); | 
						|
						if (returnValues.Count == 1) | 
						|
							return returnValues[0]; | 
						|
					} | 
						|
					return visitor.voidResult; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			public ExplicitlyTypedLambda(IList<IParameter> parameters, bool isAnonymousMethod, bool isAsync, CSharpResolver storedContext, ResolveVisitor visitor, AstNode body) | 
						|
			{ | 
						|
				this.parameters = parameters; | 
						|
				this.isAnonymousMethod = isAnonymousMethod; | 
						|
				this.isAsync = isAsync; | 
						|
				this.storedContext = storedContext; | 
						|
				this.visitor = visitor; | 
						|
				this.body = body; | 
						|
				 | 
						|
				if (visitor.undecidedLambdas == null) | 
						|
					visitor.undecidedLambdas = new List<LambdaBase>(); | 
						|
				visitor.undecidedLambdas.Add(this); | 
						|
				Log.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression); | 
						|
			} | 
						|
			 | 
						|
			public override IList<IParameter> Parameters { | 
						|
				get { | 
						|
					return parameters ?? EmptyList<IParameter>.Instance; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			bool Analyze() | 
						|
			{ | 
						|
				// If it's not already analyzed | 
						|
				if (inferredReturnType == null) { | 
						|
					Log.WriteLine("Analyzing " + this.LambdaExpression + "..."); | 
						|
					Log.Indent(); | 
						|
					 | 
						|
					visitor.ResetContext( | 
						|
						storedContext, | 
						|
						delegate { | 
						|
							var oldNavigator = visitor.navigator; | 
						|
							visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator); | 
						|
							visitor.AnalyzeLambda(body, isAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); | 
						|
							visitor.navigator = oldNavigator; | 
						|
						}); | 
						|
					Log.Unindent(); | 
						|
					Log.WriteLine("Finished analyzing " + this.LambdaExpression); | 
						|
					 | 
						|
					if (inferredReturnType == null) | 
						|
						throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType"); | 
						|
				} | 
						|
				return true; | 
						|
			} | 
						|
			 | 
						|
			public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) | 
						|
			{ | 
						|
				Log.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType); | 
						|
				Log.Indent(); | 
						|
				bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions); | 
						|
				Log.Unindent(); | 
						|
				Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType); | 
						|
				return new AnonymousFunctionConversion(returnType, this, valid); | 
						|
			} | 
						|
			 | 
						|
			public override IType GetInferredReturnType(IType[] parameterTypes) | 
						|
			{ | 
						|
				Analyze(); | 
						|
				return inferredReturnType; | 
						|
			} | 
						|
			 | 
						|
			public override bool IsImplicitlyTyped { | 
						|
				get { return false; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAsync { | 
						|
				get { return isAsync; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAnonymousMethod { | 
						|
				get { return isAnonymousMethod; } | 
						|
			} | 
						|
			 | 
						|
			public override bool HasParameterList { | 
						|
				get { return parameters != null; } | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return "[ExplicitlyTypedLambda " + this.LambdaExpression + "]"; | 
						|
			} | 
						|
			 | 
						|
			public void ApplyReturnType(ResolveVisitor parentVisitor, IType returnType) | 
						|
			{ | 
						|
				if (returnType == null) | 
						|
					throw new ArgumentNullException("returnType"); | 
						|
				if (parentVisitor != visitor) { | 
						|
					// Explicitly typed lambdas do not use a nested visitor | 
						|
					throw new InvalidOperationException(); | 
						|
				} | 
						|
				if (actualReturnType != null) { | 
						|
					if (actualReturnType.Equals(returnType)) | 
						|
						return; // return type already set | 
						|
					throw new InvalidOperationException("inconsistent return types for explicitly-typed lambda"); | 
						|
				} | 
						|
				actualReturnType = returnType; | 
						|
				visitor.undecidedLambdas.Remove(this); | 
						|
				Analyze(); | 
						|
				Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression); | 
						|
				if (isAsync) | 
						|
					returnType = parentVisitor.UnpackTask(returnType); | 
						|
				if (returnType.Kind != TypeKind.Void) { | 
						|
					for (int i = 0; i < returnExpressions.Count; i++) { | 
						|
						visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			internal override void EnforceMerge(ResolveVisitor parentVisitor) | 
						|
			{ | 
						|
				ApplyReturnType(parentVisitor, SpecialType.UnknownType); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Implicitly typed | 
						|
		// Implicitly-typed lambdas are really complex, as the lambda depends on the target type (the delegate to which | 
						|
		// the lambda is converted), but figuring out the target type might involve overload resolution (for method | 
						|
		// calls in which the lambda is used as argument), which requires knowledge about the lamdba. | 
						|
		//  | 
						|
		// The implementation in NRefactory works like this: | 
						|
		// 1. The lambda resolves to a ImplicitlyTypedLambda (derived from LambdaResolveResult). | 
						|
		//     The lambda body is not resolved yet (one of the few places where ResolveVisitor | 
						|
		//     deviates from the usual depth-first AST traversal). | 
						|
		// 2. The parent statement is resolved as usual. This might require analyzing the lambda in detail (for example | 
						|
		//    as part of overload resolution). Such analysis happens using LambdaResolveResult.IsValid, where the caller | 
						|
		//    (i.e. the overload resolution algorithm) supplies the parameter types to the lambda body. For every IsValid() | 
						|
		//    call, a nested LambdaTypeHypothesis is constructed for analyzing the lambda using the supplied type assignment. | 
						|
		//    Multiple IsValid() calls may use several LambdaTypeHypothesis instances, one for each set of parameter types. | 
						|
		// 3. When the resolver reports the conversions that occurred as part of the parent statement (as with any | 
						|
		//    conversions), the results from the LambdaTypeHypothesis corresponding to the actually chosen | 
						|
		//    conversion are merged into the main resolver. | 
						|
		// 4. LambdaResolveResult.Body is set to the main resolve result from the chosen nested resolver. I think this | 
						|
		//    is the only place where NRefactory is mutating a ResolveResult (normally all resolve results are immutable). | 
						|
		//    As this step is guaranteed to occur before the resolver returns the LamdbaResolveResult to user code, the | 
						|
		//    mutation shouldn't cause any problems. | 
						|
		sealed class ImplicitlyTypedLambda : LambdaBase | 
						|
		{ | 
						|
			readonly LambdaExpression lambda; | 
						|
			readonly QuerySelectClause selectClause; | 
						|
			 | 
						|
			readonly CSharpResolver storedContext; | 
						|
			readonly CSharpUnresolvedFile unresolvedFile; | 
						|
			readonly List<LambdaTypeHypothesis> hypotheses = new List<LambdaTypeHypothesis>(); | 
						|
			internal IList<IParameter> parameters = new List<IParameter>(); | 
						|
			 | 
						|
			internal LambdaTypeHypothesis winningHypothesis; | 
						|
			internal ResolveResult bodyResult; | 
						|
			internal readonly ResolveVisitor parentVisitor; | 
						|
			 | 
						|
			internal override bool IsUndecided { | 
						|
				get { return winningHypothesis == null;  } | 
						|
			} | 
						|
			 | 
						|
			internal override AstNode LambdaExpression { | 
						|
				get { | 
						|
					if (selectClause != null) | 
						|
						return selectClause.Expression; | 
						|
					else | 
						|
						return lambda; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			internal override AstNode BodyExpression { | 
						|
				get { | 
						|
					if (selectClause != null) | 
						|
						return selectClause.Expression; | 
						|
					else | 
						|
						return lambda.Body; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			public override ResolveResult Body { | 
						|
				get { return bodyResult; } | 
						|
			} | 
						|
			 | 
						|
			private ImplicitlyTypedLambda(ResolveVisitor parentVisitor) | 
						|
			{ | 
						|
				this.parentVisitor = parentVisitor; | 
						|
				this.storedContext = parentVisitor.resolver; | 
						|
				this.unresolvedFile = parentVisitor.unresolvedFile; | 
						|
				this.bodyResult = parentVisitor.voidResult; | 
						|
			} | 
						|
			 | 
						|
			public ImplicitlyTypedLambda(LambdaExpression lambda, ResolveVisitor parentVisitor) | 
						|
				: this(parentVisitor) | 
						|
			{ | 
						|
				this.lambda = lambda; | 
						|
				foreach (var pd in lambda.Parameters) { | 
						|
					parameters.Add(new DefaultParameter(SpecialType.UnknownType, pd.Name, parentVisitor.MakeRegion(pd))); | 
						|
				} | 
						|
				RegisterUndecidedLambda(); | 
						|
			} | 
						|
			 | 
						|
			public ImplicitlyTypedLambda(QuerySelectClause selectClause, IEnumerable<IParameter> parameters, ResolveVisitor parentVisitor) | 
						|
				: this(parentVisitor) | 
						|
			{ | 
						|
				this.selectClause = selectClause; | 
						|
				foreach (IParameter p in parameters) | 
						|
					this.parameters.Add(p); | 
						|
				 | 
						|
				RegisterUndecidedLambda(); | 
						|
			} | 
						|
			 | 
						|
			void RegisterUndecidedLambda() | 
						|
			{ | 
						|
				if (parentVisitor.undecidedLambdas == null) | 
						|
					parentVisitor.undecidedLambdas = new List<LambdaBase>(); | 
						|
				parentVisitor.undecidedLambdas.Add(this); | 
						|
				Log.WriteLine("Added undecided implicitly-typed lambda: " + this.LambdaExpression); | 
						|
			} | 
						|
			 | 
						|
			public override IList<IParameter> Parameters { | 
						|
				get { return parameters; } | 
						|
			} | 
						|
			 | 
						|
			public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) | 
						|
			{ | 
						|
				Log.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...", | 
						|
				              this, string.Join<IType>(", ", parameterTypes), returnType); | 
						|
				Log.Indent(); | 
						|
				var hypothesis = GetHypothesis(parameterTypes); | 
						|
				Conversion c = hypothesis.IsValid(returnType, conversions); | 
						|
				Log.Unindent(); | 
						|
				Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c.IsValid ? "valid" : "invalid", returnType); | 
						|
				return c; | 
						|
			} | 
						|
			 | 
						|
			public override IType GetInferredReturnType(IType[] parameterTypes) | 
						|
			{ | 
						|
				return GetHypothesis(parameterTypes).inferredReturnType; | 
						|
			} | 
						|
			 | 
						|
			LambdaTypeHypothesis GetHypothesis(IType[] parameterTypes) | 
						|
			{ | 
						|
				if (parameterTypes.Length != parameters.Count) | 
						|
					throw new ArgumentException("Incorrect parameter type count"); | 
						|
				foreach (var h in hypotheses) { | 
						|
					bool ok = true; | 
						|
					for (int i = 0; i < parameterTypes.Length; i++) { | 
						|
						if (!parameterTypes[i].Equals(h.parameterTypes[i])) { | 
						|
							ok = false; | 
						|
							break; | 
						|
						} | 
						|
					} | 
						|
					if (ok) | 
						|
						return h; | 
						|
				} | 
						|
				ResolveVisitor visitor = new ResolveVisitor(storedContext, unresolvedFile); | 
						|
				var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null); | 
						|
				hypotheses.Add(newHypothesis); | 
						|
				return newHypothesis; | 
						|
			} | 
						|
			 | 
						|
			/// <summary> | 
						|
			/// Get any hypothesis for this lambda. | 
						|
			/// This method is used as fallback if the lambda isn't merged the normal way (AnonymousFunctionConversion) | 
						|
			/// </summary> | 
						|
			internal LambdaTypeHypothesis GetAnyHypothesis() | 
						|
			{ | 
						|
				if (winningHypothesis != null) | 
						|
					return winningHypothesis; | 
						|
				if (hypotheses.Count == 0) { | 
						|
					// make a new hypothesis with unknown parameter types | 
						|
					IType[] parameterTypes = new IType[parameters.Count]; | 
						|
					for (int i = 0; i < parameterTypes.Length; i++) { | 
						|
						parameterTypes[i] = SpecialType.UnknownType; | 
						|
					} | 
						|
					return GetHypothesis(parameterTypes); | 
						|
				} else { | 
						|
					// We have the choice, so pick the hypothesis with the least missing parameter types | 
						|
					LambdaTypeHypothesis bestHypothesis = hypotheses[0]; | 
						|
					int bestHypothesisUnknownParameters = bestHypothesis.CountUnknownParameters(); | 
						|
					for (int i = 1; i < hypotheses.Count; i++) { | 
						|
						int c = hypotheses[i].CountUnknownParameters(); | 
						|
						if (c < bestHypothesisUnknownParameters || | 
						|
						    (c == bestHypothesisUnknownParameters && hypotheses[i].success && !bestHypothesis.success)) | 
						|
						{ | 
						|
							bestHypothesis = hypotheses[i]; | 
						|
							bestHypothesisUnknownParameters = c; | 
						|
						} | 
						|
					} | 
						|
					return bestHypothesis; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			internal override void EnforceMerge(ResolveVisitor parentVisitor) | 
						|
			{ | 
						|
				GetAnyHypothesis().MergeInto(parentVisitor, SpecialType.UnknownType); | 
						|
			} | 
						|
			 | 
						|
			public override bool IsImplicitlyTyped { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAnonymousMethod { | 
						|
				get { return false; } | 
						|
			} | 
						|
			 | 
						|
			public override bool HasParameterList { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAsync { | 
						|
				get { return lambda != null && lambda.IsAsync; } | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return "[ImplicitlyTypedLambda " + this.LambdaExpression + "]"; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Every possible set of parameter types gets its own 'hypothetical world'. | 
						|
		/// It uses a nested ResolveVisitor that has its own resolve cache, so that resolve results cannot leave the hypothetical world. | 
						|
		///  | 
						|
		/// Only after overload resolution is applied and the actual parameter types are known, the winning hypothesis will be merged | 
						|
		/// with the parent ResolveVisitor. | 
						|
		/// This is done when the AnonymousFunctionConversion is applied on the parent visitor. | 
						|
		/// </summary> | 
						|
		sealed class LambdaTypeHypothesis : IResolveVisitorNavigator | 
						|
		{ | 
						|
			readonly ImplicitlyTypedLambda lambda; | 
						|
			readonly IParameter[] lambdaParameters; | 
						|
			internal readonly IType[] parameterTypes; | 
						|
			readonly ResolveVisitor visitor; | 
						|
			 | 
						|
			internal readonly IType inferredReturnType; | 
						|
			IList<Expression> returnExpressions; | 
						|
			IList<ResolveResult> returnValues; | 
						|
			bool isValidAsVoidMethod; | 
						|
			bool isEndpointUnreachable; | 
						|
			internal bool success; | 
						|
			 | 
						|
			public LambdaTypeHypothesis(ImplicitlyTypedLambda lambda, IType[] parameterTypes, ResolveVisitor visitor, | 
						|
			                            ICollection<ParameterDeclaration> parameterDeclarations) | 
						|
			{ | 
						|
				Debug.Assert(parameterTypes.Length == lambda.Parameters.Count); | 
						|
				 | 
						|
				this.lambda = lambda; | 
						|
				this.parameterTypes = parameterTypes; | 
						|
				this.visitor = visitor; | 
						|
				visitor.SetNavigator(this); | 
						|
				 | 
						|
				Log.WriteLine("Analyzing " + ToString() + "..."); | 
						|
				Log.Indent(); | 
						|
				CSharpResolver oldResolver = visitor.resolver; | 
						|
				visitor.resolver = visitor.resolver.WithIsWithinLambdaExpression(true); | 
						|
				lambdaParameters = new IParameter[parameterTypes.Length]; | 
						|
				if (parameterDeclarations != null) { | 
						|
					int i = 0; | 
						|
					foreach (var pd in parameterDeclarations) { | 
						|
						lambdaParameters[i] = new DefaultParameter(parameterTypes[i], pd.Name, visitor.MakeRegion(pd)); | 
						|
						visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]); | 
						|
						i++; | 
						|
						visitor.Scan(pd); | 
						|
					} | 
						|
				} else { | 
						|
					for (int i = 0; i < parameterTypes.Length; i++) { | 
						|
						var p = lambda.Parameters[i]; | 
						|
						lambdaParameters[i] = new DefaultParameter(parameterTypes[i], p.Name, p.Region); | 
						|
						visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]); | 
						|
					} | 
						|
				} | 
						|
				 | 
						|
				success = true; | 
						|
				visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); | 
						|
				visitor.resolver = oldResolver; | 
						|
				Log.Unindent(); | 
						|
				Log.WriteLine("Finished analyzing " + ToString()); | 
						|
			} | 
						|
			 | 
						|
			ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node) | 
						|
			{ | 
						|
				return ResolveVisitorNavigationMode.Resolve; | 
						|
			} | 
						|
			 | 
						|
			void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result) | 
						|
			{ | 
						|
				if (result.IsError) | 
						|
					success = false; | 
						|
			} | 
						|
			 | 
						|
			void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType) | 
						|
			{ | 
						|
				success &= conversion.IsValid; | 
						|
			} | 
						|
			 | 
						|
			internal int CountUnknownParameters() | 
						|
			{ | 
						|
				int c = 0; | 
						|
				foreach (IType t in parameterTypes) { | 
						|
					if (t.Kind == TypeKind.Unknown) | 
						|
						c++; | 
						|
				} | 
						|
				return c; | 
						|
			} | 
						|
			 | 
						|
			public Conversion IsValid(IType returnType, CSharpConversions conversions) | 
						|
			{ | 
						|
				bool valid = success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions); | 
						|
				return new AnonymousFunctionConversion(returnType, this, valid); | 
						|
			} | 
						|
			 | 
						|
			public void MergeInto(ResolveVisitor parentVisitor, IType returnType) | 
						|
			{ | 
						|
				if (returnType == null) | 
						|
					throw new ArgumentNullException("returnType"); | 
						|
				if (parentVisitor != lambda.parentVisitor) | 
						|
					throw new InvalidOperationException("parent visitor mismatch"); | 
						|
				 | 
						|
				if (lambda.winningHypothesis == this) | 
						|
					return; | 
						|
				else if (lambda.winningHypothesis != null) | 
						|
					throw new InvalidOperationException("Trying to merge conflicting hypotheses"); | 
						|
				 | 
						|
				lambda.winningHypothesis = this; | 
						|
				lambda.parameters = lambdaParameters; // replace untyped parameters with typed parameters | 
						|
				if (lambda.BodyExpression is Expression && returnValues.Count == 1) { | 
						|
					lambda.bodyResult = returnValues[0]; | 
						|
				} | 
						|
				 | 
						|
				Log.WriteLine("Applying return type {0} to implicitly-typed lambda {1}", returnType, lambda.LambdaExpression); | 
						|
				if (lambda.IsAsync) | 
						|
					returnType = parentVisitor.UnpackTask(returnType); | 
						|
				if (returnType.Kind != TypeKind.Void) { | 
						|
					for (int i = 0; i < returnExpressions.Count; i++) { | 
						|
						visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType); | 
						|
					} | 
						|
				} | 
						|
				 | 
						|
				visitor.MergeUndecidedLambdas(); | 
						|
				Log.WriteLine("Merging " + ToString()); | 
						|
				foreach (var pair in visitor.resolverBeforeDict) { | 
						|
					Debug.Assert(!parentVisitor.resolverBeforeDict.ContainsKey(pair.Key)); | 
						|
					parentVisitor.resolverBeforeDict[pair.Key] = pair.Value; | 
						|
				} | 
						|
				foreach (var pair in visitor.resolverAfterDict) { | 
						|
					Debug.Assert(!parentVisitor.resolverAfterDict.ContainsKey(pair.Key)); | 
						|
					parentVisitor.resolverAfterDict[pair.Key] = pair.Value; | 
						|
				} | 
						|
				foreach (var pair in visitor.resolveResultCache) { | 
						|
					parentVisitor.StoreResult(pair.Key, pair.Value); | 
						|
				} | 
						|
				parentVisitor.ImportConversions(visitor); | 
						|
				parentVisitor.undecidedLambdas.Remove(lambda); | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				StringBuilder b = new StringBuilder(); | 
						|
				b.Append("[LambdaTypeHypothesis ("); | 
						|
				for (int i = 0; i < parameterTypes.Length; i++) { | 
						|
					if (i > 0) b.Append(", "); | 
						|
					b.Append(parameterTypes[i]); | 
						|
					b.Append(' '); | 
						|
					b.Append(lambda.Parameters[i].Name); | 
						|
				} | 
						|
				b.Append(") => "); | 
						|
				b.Append(lambda.BodyExpression.ToString()); | 
						|
				b.Append(']'); | 
						|
				return b.ToString(); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region MergeUndecidedLambdas | 
						|
		abstract class LambdaBase : LambdaResolveResult | 
						|
		{ | 
						|
			internal abstract bool IsUndecided { get; } | 
						|
			internal abstract AstNode LambdaExpression { get; } | 
						|
			internal abstract AstNode BodyExpression { get; } | 
						|
			 | 
						|
			internal abstract void EnforceMerge(ResolveVisitor parentVisitor); | 
						|
			 | 
						|
			public override ResolveResult ShallowClone() | 
						|
			{ | 
						|
				if (IsUndecided) | 
						|
					throw new NotSupportedException(); | 
						|
				return base.ShallowClone(); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		void MergeUndecidedLambdas() | 
						|
		{ | 
						|
			if (undecidedLambdas == null || undecidedLambdas.Count == 0) | 
						|
				return; | 
						|
			Log.WriteLine("MergeUndecidedLambdas()..."); | 
						|
			Log.Indent(); | 
						|
			while (undecidedLambdas.Count > 0) { | 
						|
				LambdaBase lambda = undecidedLambdas[0]; | 
						|
				ResolveParentForConversion(lambda.LambdaExpression); | 
						|
				if (lambda.IsUndecided) { | 
						|
					// Lambda wasn't merged by resolving its parent -> enforce merging | 
						|
					Log.WriteLine("Lambda wasn't merged by conversion - enforce merging"); | 
						|
					lambda.EnforceMerge(this); | 
						|
				} | 
						|
			} | 
						|
			Log.Unindent(); | 
						|
			Log.WriteLine("MergeUndecidedLambdas() finished."); | 
						|
		} | 
						|
		 | 
						|
		void ResolveParentForConversion(AstNode expression) | 
						|
		{ | 
						|
			AstNode parent = expression.Parent; | 
						|
			// Continue going upwards until we find a node that can be resolved and provides | 
						|
			// an expected type. | 
						|
			while (ParenthesizedExpression.ActsAsParenthesizedExpression(parent) || CSharpAstResolver.IsUnresolvableNode(parent)) { | 
						|
				parent = parent.Parent; | 
						|
			} | 
						|
			CSharpResolver storedResolver; | 
						|
			if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { | 
						|
				Log.WriteLine("Trying to resolve '" + parent + "' in order to find the conversion applied to '" + expression + "'..."); | 
						|
				Log.Indent(); | 
						|
				ResetContext(storedResolver, delegate { Resolve(parent); }); | 
						|
				Log.Unindent(); | 
						|
			} else { | 
						|
				Log.WriteLine("Could not find a suitable parent for '" + expression + "'"); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region AnalyzeLambda | 
						|
		IType GetTaskType(IType resultType) | 
						|
		{ | 
						|
			if (resultType.Kind == TypeKind.Unknown) | 
						|
				return SpecialType.UnknownType; | 
						|
			if (resultType.Kind == TypeKind.Void) | 
						|
				return resolver.Compilation.FindType(KnownTypeCode.Task); | 
						|
			 | 
						|
			ITypeDefinition def = resolver.Compilation.FindType(KnownTypeCode.TaskOfT).GetDefinition(); | 
						|
			if (def != null) | 
						|
				return new ParameterizedType(def, new[] { resultType }); | 
						|
			else | 
						|
				return SpecialType.UnknownType; | 
						|
		} | 
						|
		 | 
						|
		void AnalyzeLambda(AstNode body, bool isAsync, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues) | 
						|
		{ | 
						|
			isEndpointUnreachable = false; | 
						|
			Expression expr = body as Expression; | 
						|
			if (expr != null) { | 
						|
				isValidAsVoidMethod = ExpressionPermittedAsStatement(expr); | 
						|
				returnExpressions = new [] { expr }; | 
						|
				returnValues = new[] { Resolve(expr) }; | 
						|
				inferredReturnType = returnValues[0].Type; | 
						|
			} else { | 
						|
				Scan(body); | 
						|
				 | 
						|
				AnalyzeLambdaVisitor alv = new AnalyzeLambdaVisitor(); | 
						|
				body.AcceptVisitor(alv); | 
						|
				isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0); | 
						|
				if (alv.HasVoidReturnStatements) { | 
						|
					returnExpressions = EmptyList<Expression>.Instance; | 
						|
					returnValues = EmptyList<ResolveResult>.Instance; | 
						|
					inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Void); | 
						|
				} else { | 
						|
					returnExpressions = alv.ReturnExpressions; | 
						|
					returnValues = new ResolveResult[returnExpressions.Count]; | 
						|
					for (int i = 0; i < returnValues.Count; i++) { | 
						|
						returnValues[i] = resolveResultCache[returnExpressions[i]]; | 
						|
					} | 
						|
					TypeInference ti = new TypeInference(resolver.Compilation, resolver.conversions); | 
						|
					bool tiSuccess; | 
						|
					inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess); | 
						|
					// Failure to infer a return type does not make the lambda invalid, | 
						|
					// so we can ignore the 'tiSuccess' value | 
						|
					if (isValidAsVoidMethod && returnExpressions.Count == 0 && body is Statement) { | 
						|
						var reachabilityAnalysis = ReachabilityAnalysis.Create( | 
						|
							(Statement)body, (node, _) => resolveResultCache[node], | 
						|
							resolver.CurrentTypeResolveContext, cancellationToken); | 
						|
						isEndpointUnreachable = !reachabilityAnalysis.IsEndpointReachable((Statement)body); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			if (isAsync) | 
						|
				inferredReturnType = GetTaskType(inferredReturnType); | 
						|
			Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType); | 
						|
		} | 
						|
		 | 
						|
		static bool ExpressionPermittedAsStatement(Expression expr) | 
						|
		{ | 
						|
			UnaryOperatorExpression uoe = expr as UnaryOperatorExpression; | 
						|
			if (uoe != null) { | 
						|
				switch (uoe.Operator) { | 
						|
					case UnaryOperatorType.Increment: | 
						|
					case UnaryOperatorType.Decrement: | 
						|
					case UnaryOperatorType.PostIncrement: | 
						|
					case UnaryOperatorType.PostDecrement: | 
						|
					case UnaryOperatorType.Await: | 
						|
						return true; | 
						|
					default: | 
						|
						return false; | 
						|
				} | 
						|
			} | 
						|
			return expr is InvocationExpression | 
						|
				|| expr is ObjectCreateExpression | 
						|
				|| expr is AssignmentExpression; | 
						|
		} | 
						|
		 | 
						|
		static bool IsValidLambda(bool isValidAsVoidMethod, bool isEndpointUnreachable, bool isAsync, IList<ResolveResult> returnValues, IType returnType, CSharpConversions conversions) | 
						|
		{ | 
						|
			if (returnType.Kind == TypeKind.Void) { | 
						|
				// Lambdas that are valid statement lambdas or expression lambdas with a statement-expression | 
						|
				// can be converted to delegates with void return type. | 
						|
				// This holds for both async and regular lambdas. | 
						|
				return isValidAsVoidMethod; | 
						|
			} else if (isAsync && IsTask(returnType) && returnType.TypeParameterCount == 0) { | 
						|
				// Additionally, async lambdas with the above property can be converted to non-generic Task. | 
						|
				return isValidAsVoidMethod; | 
						|
			} else { | 
						|
				if (returnValues.Count == 0) | 
						|
					return isEndpointUnreachable; | 
						|
				if (isAsync) { | 
						|
					// async lambdas must return Task<T> | 
						|
					if (!(IsTask(returnType) && returnType.TypeParameterCount == 1)) | 
						|
						return false; | 
						|
					// unpack Task<T> for testing the implicit conversions | 
						|
					returnType = ((ParameterizedType)returnType).GetTypeArgument(0); | 
						|
				} | 
						|
				foreach (ResolveResult returnRR in returnValues) { | 
						|
					if (!conversions.ImplicitConversion(returnRR, returnType).IsValid) | 
						|
						return false; | 
						|
				} | 
						|
				return true; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the T in Task<T>. | 
						|
		/// Returns void for non-generic Task. | 
						|
		/// </summary> | 
						|
		IType UnpackTask(IType type) | 
						|
		{ | 
						|
			if (!IsTask(type)) | 
						|
				return type; | 
						|
			if (type.TypeParameterCount == 0) | 
						|
				return resolver.Compilation.FindType(KnownTypeCode.Void); | 
						|
			else | 
						|
				return ((ParameterizedType)type).GetTypeArgument(0); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets whether the specified type is Task or Task<T>. | 
						|
		/// </summary> | 
						|
		static bool IsTask(IType type) | 
						|
		{ | 
						|
			ITypeDefinition def = type.GetDefinition(); | 
						|
			if (def != null) { | 
						|
				if (def.KnownTypeCode == KnownTypeCode.Task) | 
						|
					return true; | 
						|
				if (def.KnownTypeCode == KnownTypeCode.TaskOfT) | 
						|
					return type is ParameterizedType; | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
		 | 
						|
		sealed class AnalyzeLambdaVisitor : DepthFirstAstVisitor | 
						|
		{ | 
						|
			public bool HasVoidReturnStatements; | 
						|
			public List<Expression> ReturnExpressions = new List<Expression>(); | 
						|
			 | 
						|
			public override void VisitReturnStatement(ReturnStatement returnStatement) | 
						|
			{ | 
						|
				Expression expr = returnStatement.Expression; | 
						|
				if (expr.IsNull) { | 
						|
					HasVoidReturnStatements = true; | 
						|
				} else { | 
						|
					ReturnExpressions.Add(expr); | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) | 
						|
			{ | 
						|
				// don't go into nested lambdas | 
						|
			} | 
						|
			 | 
						|
			public override void VisitLambdaExpression(LambdaExpression lambdaExpression) | 
						|
			{ | 
						|
				// don't go into nested lambdas | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		#endregion | 
						|
		 | 
						|
		#region ForEach Statement | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement) | 
						|
		{ | 
						|
			var compilation = resolver.Compilation; | 
						|
			ResolveResult expression = Resolve(foreachStatement.InExpression); | 
						|
			bool isImplicitlyTypedVariable = IsVar(foreachStatement.VariableType); | 
						|
			var memberLookup = resolver.CreateMemberLookup(); | 
						|
			 | 
						|
			IType collectionType, enumeratorType, elementType; | 
						|
			ResolveResult getEnumeratorInvocation; | 
						|
			ResolveResult currentRR = null; | 
						|
			// C# 4.0 spec: §8.8.4 The foreach statement | 
						|
			if (expression.Type.Kind == TypeKind.Array || expression.Type.Kind == TypeKind.Dynamic) { | 
						|
				collectionType = compilation.FindType(KnownTypeCode.IEnumerable); | 
						|
				enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator); | 
						|
				if (expression.Type.Kind == TypeKind.Array) { | 
						|
					elementType = ((ArrayType)expression.Type).ElementType; | 
						|
				} else { | 
						|
					elementType = isImplicitlyTypedVariable ? SpecialType.Dynamic : compilation.FindType(KnownTypeCode.Object); | 
						|
				} | 
						|
				getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression); | 
						|
				getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); | 
						|
				getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]); | 
						|
			} else { | 
						|
				var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult; | 
						|
				if (getEnumeratorMethodGroup != null) { | 
						|
					var or = getEnumeratorMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); | 
						|
					if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) { | 
						|
						collectionType = expression.Type; | 
						|
						getEnumeratorInvocation = or.CreateResolveResult(expression); | 
						|
						enumeratorType = getEnumeratorInvocation.Type; | 
						|
						currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false); | 
						|
						elementType = currentRR.Type; | 
						|
					} else { | 
						|
						CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation); | 
						|
					} | 
						|
				} else { | 
						|
					CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation); | 
						|
				} | 
						|
			} | 
						|
			IMethod moveNextMethod = null; | 
						|
			var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult; | 
						|
			if (moveNextMethodGroup != null) { | 
						|
				var or = moveNextMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); | 
						|
				moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod; | 
						|
			} | 
						|
			 | 
						|
			if (currentRR == null) | 
						|
				currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false); | 
						|
			IProperty currentProperty = null; | 
						|
			if (currentRR is MemberResolveResult) | 
						|
				currentProperty = ((MemberResolveResult)currentRR).Member as IProperty; | 
						|
			// end of foreach resolve logic | 
						|
			// back to resolve visitor: | 
						|
			 | 
						|
			resolver = resolver.PushBlock(); | 
						|
			IVariable v; | 
						|
			if (isImplicitlyTypedVariable) { | 
						|
				StoreCurrentState(foreachStatement.VariableType); | 
						|
				StoreResult(foreachStatement.VariableType, new TypeResolveResult(elementType)); | 
						|
				v = MakeVariable(elementType, foreachStatement.VariableNameToken); | 
						|
			} else { | 
						|
				IType variableType = ResolveType(foreachStatement.VariableType); | 
						|
				v = MakeVariable(variableType, foreachStatement.VariableNameToken); | 
						|
			} | 
						|
			StoreCurrentState(foreachStatement.VariableNameToken); | 
						|
			resolver = resolver.AddVariable(v); | 
						|
			 | 
						|
			StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v)); | 
						|
			 | 
						|
			Scan(foreachStatement.EmbeddedStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return new ForEachResolveResult(getEnumeratorInvocation, collectionType, enumeratorType, elementType, | 
						|
			                                v, currentProperty, moveNextMethod, voidResult.Type); | 
						|
		} | 
						|
		 | 
						|
		void CheckForEnumerableInterface(ResolveResult expression, out IType collectionType, out IType enumeratorType, out IType elementType, out ResolveResult getEnumeratorInvocation) | 
						|
		{ | 
						|
			var compilation = resolver.Compilation; | 
						|
			bool? isGeneric; | 
						|
			elementType = GetElementTypeFromIEnumerable(expression.Type, compilation, false, out isGeneric); | 
						|
			if (isGeneric == true) { | 
						|
				ITypeDefinition enumerableOfT = compilation.FindType(KnownTypeCode.IEnumerableOfT).GetDefinition(); | 
						|
				if (enumerableOfT != null) | 
						|
					collectionType = new ParameterizedType(enumerableOfT, new [] { elementType }); | 
						|
				else | 
						|
					collectionType = SpecialType.UnknownType; | 
						|
				 | 
						|
				ITypeDefinition enumeratorOfT = compilation.FindType(KnownTypeCode.IEnumeratorOfT).GetDefinition(); | 
						|
				if (enumeratorOfT != null) | 
						|
					enumeratorType = new ParameterizedType(enumeratorOfT, new [] { elementType }); | 
						|
				else | 
						|
					enumeratorType = SpecialType.UnknownType; | 
						|
			} else if (isGeneric == false) { | 
						|
				collectionType = compilation.FindType(KnownTypeCode.IEnumerable); | 
						|
				enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator); | 
						|
			} else { | 
						|
				collectionType = SpecialType.UnknownType; | 
						|
				enumeratorType = SpecialType.UnknownType; | 
						|
			} | 
						|
			getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression); | 
						|
			getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); | 
						|
			getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Local Variable Scopes (Block Statements) | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitBlockStatement(BlockStatement blockStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			ScanChildren(blockStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUsingStatement(UsingStatement usingStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			if (resolverEnabled) { | 
						|
				for (AstNode child = usingStatement.FirstChild; child != null; child = child.NextSibling) { | 
						|
					if (child.Role == UsingStatement.ResourceAcquisitionRole && child is Expression) { | 
						|
						ResolveAndProcessConversion((Expression)child, resolver.Compilation.FindType(KnownTypeCode.IDisposable)); | 
						|
					} else { | 
						|
						Scan(child); | 
						|
					} | 
						|
				} | 
						|
			} else { | 
						|
				ScanChildren(usingStatement); | 
						|
			} | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return resolverEnabled ? voidResult : null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			IType type = ResolveType(fixedStatement.Type); | 
						|
			foreach (VariableInitializer vi in fixedStatement.Variables) { | 
						|
				resolver = resolver.AddVariable(MakeVariable(type, vi.NameToken)); | 
						|
				Scan(vi); | 
						|
			} | 
						|
			Scan(fixedStatement.EmbeddedStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitSwitchStatement(SwitchStatement switchStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			ScanChildren(switchStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCatchClause(CatchClause catchClause) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			if (string.IsNullOrEmpty(catchClause.VariableName)) { | 
						|
				Scan(catchClause.Type); | 
						|
			} else { | 
						|
				//DomRegion region = MakeRegion(catchClause.VariableNameToken); | 
						|
				StoreCurrentState(catchClause.VariableNameToken); | 
						|
				IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken); | 
						|
				resolver = resolver.AddVariable(v); | 
						|
				StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v)); | 
						|
			} | 
						|
			Scan(catchClause.Body); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region VariableDeclarationStatement | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) | 
						|
		{ | 
						|
			bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0; | 
						|
			if (!isConst && IsVar(variableDeclarationStatement.Type) && variableDeclarationStatement.Variables.Count == 1) { | 
						|
				VariableInitializer vi = variableDeclarationStatement.Variables.Single(); | 
						|
				StoreCurrentState(variableDeclarationStatement.Type); | 
						|
				IType type = Resolve(vi.Initializer).Type; | 
						|
				StoreResult(variableDeclarationStatement.Type, new TypeResolveResult(type)); | 
						|
				IVariable v = MakeVariable(type, vi.NameToken); | 
						|
				resolver = resolver.AddVariable(v); | 
						|
				Scan(vi); | 
						|
			} else { | 
						|
				IType type = ResolveType(variableDeclarationStatement.Type); | 
						|
 | 
						|
				foreach (VariableInitializer vi in variableDeclarationStatement.Variables) { | 
						|
					IVariable v; | 
						|
					if (isConst) { | 
						|
						v = MakeConstant(type, vi.NameToken, Resolve(vi.Initializer).ConstantValue); | 
						|
					} else { | 
						|
						v = MakeVariable(type, vi.NameToken); | 
						|
					} | 
						|
					resolver = resolver.AddVariable(v); | 
						|
					Scan(vi); | 
						|
				} | 
						|
			} | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Condition Statements | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitForStatement(ForStatement forStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			var result = HandleConditionStatement(forStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return result; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIfElseStatement(IfElseStatement ifElseStatement) | 
						|
		{ | 
						|
			return HandleConditionStatement(ifElseStatement); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitWhileStatement(WhileStatement whileStatement) | 
						|
		{ | 
						|
			return HandleConditionStatement(whileStatement); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDoWhileStatement(DoWhileStatement doWhileStatement) | 
						|
		{ | 
						|
			return HandleConditionStatement(doWhileStatement); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult HandleConditionStatement(Statement conditionStatement) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				for (AstNode child = conditionStatement.FirstChild; child != null; child = child.NextSibling) { | 
						|
					if (child.Role == Roles.Condition) { | 
						|
						Expression condition = (Expression)child; | 
						|
						ResolveResult conditionRR = Resolve(condition); | 
						|
						ResolveResult convertedRR = resolver.ResolveCondition(conditionRR); | 
						|
						if (convertedRR != conditionRR) | 
						|
							ProcessConversionResult(condition, convertedRR as ConversionResolveResult); | 
						|
					} else { | 
						|
						Scan(child); | 
						|
					} | 
						|
				} | 
						|
				return voidResult; | 
						|
			} else { | 
						|
				ScanChildren(conditionStatement); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Return Statements | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitReturnStatement(ReturnStatement returnStatement) | 
						|
		{ | 
						|
			if (resolverEnabled && !resolver.IsWithinLambdaExpression && resolver.CurrentMember != null) { | 
						|
				IType type = resolver.CurrentMember.ReturnType; | 
						|
				if (IsTask(type)) { | 
						|
					var methodDecl = returnStatement.Ancestors.OfType<EntityDeclaration>().FirstOrDefault(); | 
						|
					if (methodDecl != null && (methodDecl.Modifiers & Modifiers.Async) == Modifiers.Async) | 
						|
						type = UnpackTask(type); | 
						|
				} | 
						|
				ResolveAndProcessConversion(returnStatement.Expression, type); | 
						|
			} else { | 
						|
				Scan(returnStatement.Expression); | 
						|
			} | 
						|
			return resolverEnabled ? voidResult : null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitYieldReturnStatement(YieldReturnStatement yieldStatement) | 
						|
		{ | 
						|
			if (resolverEnabled && resolver.CurrentMember != null) { | 
						|
				IType returnType = resolver.CurrentMember.ReturnType; | 
						|
				bool? isGeneric; | 
						|
				IType elementType = GetElementTypeFromIEnumerable(returnType, resolver.Compilation, true, out isGeneric); | 
						|
				ResolveAndProcessConversion(yieldStatement.Expression, elementType); | 
						|
			} else { | 
						|
				Scan(yieldStatement.Expression); | 
						|
			} | 
						|
			return resolverEnabled ? voidResult : null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Other statements | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitExpressionStatement(ExpressionStatement expressionStatement) | 
						|
		{ | 
						|
			ScanChildren(expressionStatement); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitLockStatement(LockStatement lockStatement) | 
						|
		{ | 
						|
			ScanChildren(lockStatement); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitEmptyStatement(EmptyStatement emptyStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitBreakStatement(BreakStatement breakStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitContinueStatement(ContinueStatement continueStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitThrowStatement(ThrowStatement throwStatement) | 
						|
		{ | 
						|
			if (resolverEnabled) { | 
						|
				ResolveAndProcessConversion(throwStatement.Expression, resolver.Compilation.FindType(KnownTypeCode.Exception)); | 
						|
				return voidResult; | 
						|
			} else { | 
						|
				Scan(throwStatement.Expression); | 
						|
				return null; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitTryCatchStatement(TryCatchStatement tryCatchStatement) | 
						|
		{ | 
						|
			ScanChildren(tryCatchStatement); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement) | 
						|
		{ | 
						|
			ScanChildren(gotoCaseStatement); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitGotoStatement(GotoStatement gotoStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitLabelStatement(LabelStatement labelStatement) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUnsafeStatement(UnsafeStatement unsafeStatement) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			ScanChildren(unsafeStatement); | 
						|
			resolver = resolver.PopBlock(); | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Local Variable Type Inference | 
						|
		static bool IsVar(AstNode returnType) | 
						|
		{ | 
						|
			SimpleType st = returnType as SimpleType; | 
						|
			return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0; | 
						|
		} | 
						|
		 | 
						|
		IVariable MakeVariable(IType type, Identifier variableName) | 
						|
		{ | 
						|
			return new SimpleVariable(MakeRegion(variableName), type, variableName.Name); | 
						|
		} | 
						|
		 | 
						|
		IVariable MakeConstant(IType type, Identifier variableName, object constantValue) | 
						|
		{ | 
						|
			return new SimpleConstant(MakeRegion(variableName), type, variableName.Name, constantValue); | 
						|
		} | 
						|
		 | 
						|
		class SimpleVariable : IVariable | 
						|
		{ | 
						|
			readonly DomRegion region; | 
						|
			readonly IType type; | 
						|
			readonly string name; | 
						|
			 | 
						|
			public SimpleVariable(DomRegion region, IType type, string name) | 
						|
			{ | 
						|
				Debug.Assert(type != null); | 
						|
				Debug.Assert(name != null); | 
						|
				this.region = region; | 
						|
				this.type = type; | 
						|
				this.name = name; | 
						|
			} | 
						|
			 | 
						|
			public string Name { | 
						|
				get { return name; } | 
						|
			} | 
						|
			 | 
						|
			public DomRegion Region { | 
						|
				get { return region; } | 
						|
			} | 
						|
			 | 
						|
			public IType Type { | 
						|
				get { return type; } | 
						|
			} | 
						|
			 | 
						|
			public virtual bool IsConst { | 
						|
				get { return false; } | 
						|
			} | 
						|
			 | 
						|
			public virtual object ConstantValue { | 
						|
				get { return null; } | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return type.ToString() + " " + name + ";"; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		sealed class SimpleConstant : SimpleVariable | 
						|
		{ | 
						|
			readonly object constantValue; | 
						|
			 | 
						|
			public SimpleConstant(DomRegion region, IType type, string name, object constantValue) | 
						|
				: base(region, type, name) | 
						|
			{ | 
						|
				this.constantValue = constantValue; | 
						|
			} | 
						|
			 | 
						|
			public override bool IsConst { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override object ConstantValue { | 
						|
				get { return constantValue; } | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return Type.ToString() + " " + Name + " = " + new PrimitiveExpression(constantValue).ToString() + ";"; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		static IType GetElementTypeFromIEnumerable(IType collectionType, ICompilation compilation, bool allowIEnumerator, out bool? isGeneric) | 
						|
		{ | 
						|
			bool foundNonGenericIEnumerable = false; | 
						|
			foreach (IType baseType in collectionType.GetAllBaseTypes()) { | 
						|
				ITypeDefinition baseTypeDef = baseType.GetDefinition(); | 
						|
				if (baseTypeDef != null) { | 
						|
					KnownTypeCode typeCode = baseTypeDef.KnownTypeCode; | 
						|
					if (typeCode == KnownTypeCode.IEnumerableOfT || (allowIEnumerator && typeCode == KnownTypeCode.IEnumeratorOfT)) { | 
						|
						ParameterizedType pt = baseType as ParameterizedType; | 
						|
						if (pt != null) { | 
						|
							isGeneric = true; | 
						|
							return pt.GetTypeArgument(0); | 
						|
						} | 
						|
					} | 
						|
					if (typeCode == KnownTypeCode.IEnumerable || (allowIEnumerator && typeCode == KnownTypeCode.IEnumerator)) | 
						|
						foundNonGenericIEnumerable = true; | 
						|
				} | 
						|
			} | 
						|
			// System.Collections.IEnumerable found in type hierarchy -> Object is element type. | 
						|
			if (foundNonGenericIEnumerable) { | 
						|
				isGeneric = false; | 
						|
				return compilation.FindType(KnownTypeCode.Object); | 
						|
			} | 
						|
			isGeneric = null; | 
						|
			return SpecialType.UnknownType; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Attributes | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAttribute(Attribute attribute) | 
						|
		{ | 
						|
			var type = ResolveType(attribute.Type); | 
						|
			 | 
						|
			// Separate arguments into ctor arguments and non-ctor arguments: | 
						|
			var constructorArguments = attribute.Arguments.Where(a => !(a is NamedExpression)); | 
						|
			var nonConstructorArguments = attribute.Arguments.OfType<NamedExpression>(); | 
						|
			 | 
						|
			// Scan the non-constructor arguments | 
						|
			resolver = resolver.PushObjectInitializer(new InitializedObjectResolveResult(type)); | 
						|
			List<ResolveResult> initializerStatements = new List<ResolveResult>(); | 
						|
			foreach (var arg in nonConstructorArguments) | 
						|
				HandleNamedExpression(arg, initializerStatements); | 
						|
			resolver = resolver.PopObjectInitializer(); | 
						|
			 | 
						|
			// Resolve the ctor arguments and find the matching ctor overload | 
						|
			string[] argumentNames; | 
						|
			ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames); | 
						|
			ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); | 
						|
			ProcessInvocationResult(null, constructorArguments, rr); | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAttributeSection(AttributeSection attributeSection) | 
						|
		{ | 
						|
			ScanChildren(attributeSection); | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Using Declaration | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUsingDeclaration(UsingDeclaration usingDeclaration) | 
						|
		{ | 
						|
			ScanChildren(usingDeclaration); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration) | 
						|
		{ | 
						|
			ScanChildren(usingDeclaration); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration) | 
						|
		{ | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Type References | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveType(PrimitiveType primitiveType) | 
						|
		{ | 
						|
			if (!resolverEnabled) | 
						|
				return null; | 
						|
			KnownTypeCode typeCode = primitiveType.KnownTypeCode; | 
						|
			if (typeCode == KnownTypeCode.None && primitiveType.Parent is Constraint && primitiveType.Role == Roles.BaseType) { | 
						|
				switch (primitiveType.Keyword) { | 
						|
					case "class": | 
						|
					case "struct": | 
						|
					case "new": | 
						|
						return voidResult; | 
						|
				} | 
						|
			} | 
						|
			IType type = resolver.Compilation.FindType(typeCode); | 
						|
			return new TypeResolveResult(type); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitSimpleType(SimpleType simpleType) | 
						|
		{ | 
						|
			if (!resolverEnabled) { | 
						|
				ScanChildren(simpleType); | 
						|
				return null; | 
						|
			} | 
						|
			 | 
						|
			// Figure out the correct lookup mode: | 
						|
			NameLookupMode lookupMode = GetNameLookupMode(simpleType); | 
						|
			 | 
						|
			var typeArguments = ResolveTypeArguments(simpleType.TypeArguments); | 
						|
			Identifier identifier = simpleType.IdentifierToken; | 
						|
			if (string.IsNullOrEmpty(identifier.Name)) | 
						|
				return new TypeResolveResult(SpecialType.UnboundTypeArgument); | 
						|
			ResolveResult rr = resolver.LookupSimpleNameOrTypeName(identifier.Name, typeArguments, lookupMode); | 
						|
			if (simpleType.Parent is Attribute && !identifier.IsVerbatim) { | 
						|
				var withSuffix = resolver.LookupSimpleNameOrTypeName(identifier.Name + "Attribute", typeArguments, lookupMode); | 
						|
				if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation)) | 
						|
					return withSuffix; | 
						|
			} | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		NameLookupMode GetNameLookupMode(AstType type) | 
						|
		{ | 
						|
			AstType outermostType = type; | 
						|
			while (outermostType.Parent is AstType) | 
						|
				outermostType = (AstType)outermostType.Parent; | 
						|
			NameLookupMode lookupMode = NameLookupMode.Type; | 
						|
			if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) { | 
						|
				lookupMode = NameLookupMode.TypeInUsingDeclaration; | 
						|
			} else if (outermostType.Parent is TypeDeclaration && outermostType.Role == Roles.BaseType) { | 
						|
				lookupMode = NameLookupMode.BaseTypeReference; | 
						|
			} | 
						|
			return lookupMode; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType) | 
						|
		{ | 
						|
			ResolveResult target; | 
						|
			if (memberType.IsDoubleColon && memberType.Target is SimpleType) { | 
						|
				SimpleType t = (SimpleType)memberType.Target; | 
						|
				StoreCurrentState(t); | 
						|
				target = resolver.ResolveAlias(t.Identifier); | 
						|
				StoreResult(t, target); | 
						|
			} else { | 
						|
				if (!resolverEnabled) { | 
						|
					ScanChildren(memberType); | 
						|
					return null; | 
						|
				} | 
						|
				target = Resolve(memberType.Target); | 
						|
			} | 
						|
			 | 
						|
			NameLookupMode lookupMode = GetNameLookupMode(memberType); | 
						|
			var typeArguments = ResolveTypeArguments(memberType.TypeArguments); | 
						|
			Identifier identifier = memberType.MemberNameToken; | 
						|
			ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode); | 
						|
			if (memberType.Parent is Attribute && !identifier.IsVerbatim) { | 
						|
				var withSuffix = resolver.ResolveMemberAccess(target, identifier.Name + "Attribute", typeArguments, lookupMode); | 
						|
				if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation)) | 
						|
					return withSuffix; | 
						|
			} | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitComposedType(ComposedType composedType) | 
						|
		{ | 
						|
			if (!resolverEnabled) { | 
						|
				ScanChildren(composedType); | 
						|
				return null; | 
						|
			} | 
						|
			IType t = ResolveType(composedType.BaseType); | 
						|
			if (composedType.HasNullableSpecifier) { | 
						|
				t = NullableType.Create(resolver.Compilation, t); | 
						|
			} | 
						|
			for (int i = 0; i < composedType.PointerRank; i++) { | 
						|
				t = new PointerType(t); | 
						|
			} | 
						|
			foreach (var a in composedType.ArraySpecifiers.Reverse()) { | 
						|
				t = new ArrayType(resolver.Compilation, t, a.Dimensions); | 
						|
			} | 
						|
			return new TypeResolveResult(t); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Query Expressions | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryExpression(QueryExpression queryExpression) | 
						|
		{ | 
						|
			resolver = resolver.PushBlock(); | 
						|
			var oldQueryResult = currentQueryResult; | 
						|
			var oldCancellationToken = cancellationToken; | 
						|
			try { | 
						|
				// Because currentQueryResult isn't part of the stored state, | 
						|
				// query expressions must be resolved in a single operation. | 
						|
				// This means we can't allow cancellation within the query expression. | 
						|
				cancellationToken = CancellationToken.None; | 
						|
				currentQueryResult = null; | 
						|
				foreach (var clause in queryExpression.Clauses) { | 
						|
					currentQueryResult = Resolve(clause); | 
						|
				} | 
						|
				return WrapResult(currentQueryResult); | 
						|
			} finally { | 
						|
				currentQueryResult = oldQueryResult; | 
						|
				cancellationToken = oldCancellationToken; | 
						|
				resolver = resolver.PopBlock(); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		IType GetTypeForQueryVariable(IType type) | 
						|
		{ | 
						|
			// This assumes queries are only used on IEnumerable. | 
						|
			// We might want to look at the signature of a LINQ method (e.g. Select) instead. | 
						|
			bool? isGeneric; | 
						|
			return GetElementTypeFromIEnumerable(type, resolver.Compilation, false, out isGeneric); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult MakeTransparentIdentifierResolveResult() | 
						|
		{ | 
						|
			return new ResolveResult(new AnonymousType(resolver.Compilation, EmptyList<IUnresolvedProperty>.Instance)); | 
						|
		} | 
						|
		 | 
						|
		sealed class QueryExpressionLambdaConversion : Conversion | 
						|
		{ | 
						|
			internal readonly IType[] ParameterTypes; | 
						|
			 | 
						|
			public QueryExpressionLambdaConversion(IType[] parameterTypes) | 
						|
			{ | 
						|
				this.ParameterTypes = parameterTypes; | 
						|
			} | 
						|
			 | 
						|
			public override bool IsImplicit { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAnonymousFunctionConversion { | 
						|
				get { return true; } | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		sealed class QueryExpressionLambda : LambdaResolveResult | 
						|
		{ | 
						|
			readonly IParameter[] parameters; | 
						|
			readonly ResolveResult bodyExpression; | 
						|
			 | 
						|
			internal IType[] inferredParameterTypes; | 
						|
			 | 
						|
			public QueryExpressionLambda(int parameterCount, ResolveResult bodyExpression) | 
						|
			{ | 
						|
				this.parameters = new IParameter[parameterCount]; | 
						|
				for (int i = 0; i < parameterCount; i++) { | 
						|
					parameters[i] = new DefaultParameter(SpecialType.UnknownType, "x" + i); | 
						|
				} | 
						|
				this.bodyExpression = bodyExpression; | 
						|
			} | 
						|
			 | 
						|
			public override IList<IParameter> Parameters { | 
						|
				get { return parameters; } | 
						|
			} | 
						|
			 | 
						|
			public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) | 
						|
			{ | 
						|
				if (parameterTypes.Length == parameters.Length) { | 
						|
					this.inferredParameterTypes = parameterTypes; | 
						|
					return new QueryExpressionLambdaConversion(parameterTypes); | 
						|
				} else { | 
						|
					return Conversion.None; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAsync { | 
						|
				get { return false; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsImplicitlyTyped { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override bool IsAnonymousMethod { | 
						|
				get { return false; } | 
						|
			} | 
						|
			 | 
						|
			public override bool HasParameterList { | 
						|
				get { return true; } | 
						|
			} | 
						|
			 | 
						|
			public override ResolveResult Body { | 
						|
				get { return bodyExpression; } | 
						|
			} | 
						|
			 | 
						|
			public override IType GetInferredReturnType(IType[] parameterTypes) | 
						|
			{ | 
						|
				return bodyExpression.Type; | 
						|
			} | 
						|
			 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return string.Format("[QueryExpressionLambda ({0}) => {1}]", string.Join(",", parameters.Select(p => p.Name)), bodyExpression); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		QueryClause GetPreviousQueryClause(QueryClause clause) | 
						|
		{ | 
						|
			for (AstNode node = clause.PrevSibling; node != null; node = node.PrevSibling) { | 
						|
				if (node.Role == QueryExpression.ClauseRole) | 
						|
					return (QueryClause)node; | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		QueryClause GetNextQueryClause(QueryClause clause) | 
						|
		{ | 
						|
			for (AstNode node = clause.NextSibling; node != null; node = node.NextSibling) { | 
						|
				if (node.Role == QueryExpression.ClauseRole) | 
						|
					return (QueryClause)node; | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryFromClause(QueryFromClause queryFromClause) | 
						|
		{ | 
						|
			ResolveResult result = errorResult; | 
						|
			ResolveResult expr = Resolve(queryFromClause.Expression); | 
						|
			IVariable v; | 
						|
			if (queryFromClause.Type.IsNull) { | 
						|
				v = MakeVariable(GetTypeForQueryVariable(expr.Type), queryFromClause.IdentifierToken); | 
						|
				result = expr; | 
						|
			} else { | 
						|
				v = MakeVariable(ResolveType(queryFromClause.Type), queryFromClause.IdentifierToken); | 
						|
				 | 
						|
				// resolve the .Cast<>() call | 
						|
				ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { v.Type }, NameLookupMode.InvocationTarget); | 
						|
				result = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]); | 
						|
			} | 
						|
			 | 
						|
			StoreCurrentState(queryFromClause.IdentifierToken); | 
						|
			resolver = resolver.AddVariable(v); | 
						|
			StoreResult(queryFromClause.IdentifierToken, new LocalResolveResult(v)); | 
						|
			 | 
						|
			if (currentQueryResult != null) { | 
						|
				// this is a second 'from': resolve the .SelectMany() call | 
						|
				QuerySelectClause selectClause = GetNextQueryClause(queryFromClause) as QuerySelectClause; | 
						|
				ResolveResult selectResult; | 
						|
				if (selectClause != null) { | 
						|
					// from ... from ... select - the SelectMany call also performs the Select operation | 
						|
					selectResult = Resolve(selectClause.Expression); | 
						|
				} else { | 
						|
					// from .. from ... ... - introduce a transparent identifier | 
						|
					selectResult = MakeTransparentIdentifierResolveResult(); | 
						|
				} | 
						|
				ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "SelectMany", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); | 
						|
				ResolveResult[] arguments = { | 
						|
					new QueryExpressionLambda(1, result), | 
						|
					new QueryExpressionLambda(2, selectResult) | 
						|
				}; | 
						|
				result = resolver.ResolveInvocation(methodGroup, arguments); | 
						|
			} | 
						|
			if (result == expr) | 
						|
				return WrapResult(result); | 
						|
			else | 
						|
				return result; | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Wraps the result in an identity conversion. | 
						|
		/// This is necessary so that '$from x in variable$ select x*2' does not resolve | 
						|
		/// to the LocalResolveResult for the variable, which would confuse find references. | 
						|
		/// </summary> | 
						|
		ResolveResult WrapResult(ResolveResult result) | 
						|
		{ | 
						|
			return new ConversionResolveResult(result.Type, result, Conversion.IdentityConversion, resolver.CheckForOverflow); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause) | 
						|
		{ | 
						|
			ResolveResult rr = Resolve(queryContinuationClause.PrecedingQuery); | 
						|
			IType variableType = GetTypeForQueryVariable(rr.Type); | 
						|
			StoreCurrentState(queryContinuationClause.IdentifierToken); | 
						|
			IVariable v = MakeVariable(variableType, queryContinuationClause.IdentifierToken); | 
						|
			resolver = resolver.AddVariable(v); | 
						|
			StoreResult(queryContinuationClause.IdentifierToken, new LocalResolveResult(v)); | 
						|
			return WrapResult(rr); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryLetClause(QueryLetClause queryLetClause) | 
						|
		{ | 
						|
			ResolveResult expr = Resolve(queryLetClause.Expression); | 
						|
			StoreCurrentState(queryLetClause.IdentifierToken); | 
						|
			IVariable v = MakeVariable(expr.Type, queryLetClause.IdentifierToken); | 
						|
			resolver = resolver.AddVariable(v); | 
						|
			StoreResult(queryLetClause.IdentifierToken, new LocalResolveResult(v)); | 
						|
			if (currentQueryResult != null) { | 
						|
				// resolve the .Select() call | 
						|
				ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); | 
						|
				ResolveResult[] arguments = { new QueryExpressionLambda(1, MakeTransparentIdentifierResolveResult()) }; | 
						|
				return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
			} else { | 
						|
				return errorResult; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryJoinClause(QueryJoinClause queryJoinClause) | 
						|
		{ | 
						|
			// join v in expr on onExpr equals equalsExpr [into g] | 
						|
			ResolveResult inResult = null; | 
						|
			ResolveResult expr = Resolve(queryJoinClause.InExpression); | 
						|
			IType variableType; | 
						|
			if (queryJoinClause.Type.IsNull) { | 
						|
				variableType = GetTypeForQueryVariable(expr.Type); | 
						|
				inResult = expr; | 
						|
			} else { | 
						|
				variableType = ResolveType(queryJoinClause.Type); | 
						|
				 | 
						|
				// resolve the .Cast<>() call | 
						|
				ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { variableType }, NameLookupMode.InvocationTarget); | 
						|
				inResult = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]); | 
						|
			} | 
						|
			 | 
						|
			// resolve the 'On' expression in a context that contains only the previously existing range variables: | 
						|
			// (before adding any variable) | 
						|
			ResolveResult onResult = Resolve(queryJoinClause.OnExpression); | 
						|
			 | 
						|
			// scan the 'Equals' expression in a context that contains only the variable 'v' | 
						|
			CSharpResolver resolverOutsideQuery = resolver; | 
						|
			resolverOutsideQuery = resolverOutsideQuery.PopBlock(); // pop all variables from the current query expression | 
						|
			IVariable v = MakeVariable(variableType, queryJoinClause.JoinIdentifierToken); | 
						|
			resolverOutsideQuery = resolverOutsideQuery.AddVariable(v); | 
						|
			ResolveResult equalsResult = errorResult; | 
						|
			ResetContext(resolverOutsideQuery, delegate { | 
						|
			             	equalsResult = Resolve(queryJoinClause.EqualsExpression); | 
						|
			             }); | 
						|
			StoreCurrentState(queryJoinClause.JoinIdentifierToken); | 
						|
			StoreResult(queryJoinClause.JoinIdentifierToken, new LocalResolveResult(v)); | 
						|
			 | 
						|
			if (queryJoinClause.IsGroupJoin) { | 
						|
				return ResolveGroupJoin(queryJoinClause, inResult, onResult, equalsResult); | 
						|
			} else { | 
						|
				resolver = resolver.AddVariable(v); | 
						|
				if (currentQueryResult != null) { | 
						|
					QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause; | 
						|
					ResolveResult selectResult; | 
						|
					if (selectClause != null) { | 
						|
						// from ... join ... select - the Join call also performs the Select operation | 
						|
						selectResult = Resolve(selectClause.Expression); | 
						|
					} else { | 
						|
						// from .. join ... ... - introduce a transparent identifier | 
						|
						selectResult = MakeTransparentIdentifierResolveResult(); | 
						|
					} | 
						|
					 | 
						|
					var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Join", EmptyList<IType>.Instance); | 
						|
					ResolveResult[] arguments = { | 
						|
						inResult, | 
						|
						new QueryExpressionLambda(1, onResult), | 
						|
						new QueryExpressionLambda(1, equalsResult), | 
						|
						new QueryExpressionLambda(2, selectResult) | 
						|
					}; | 
						|
					return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
				} else { | 
						|
					return errorResult; | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult ResolveGroupJoin(QueryJoinClause queryJoinClause, | 
						|
		                               ResolveResult inResult, ResolveResult onResult, ResolveResult equalsResult) | 
						|
		{ | 
						|
			Debug.Assert(queryJoinClause.IsGroupJoin); | 
						|
			 | 
						|
			DomRegion intoIdentifierRegion = MakeRegion(queryJoinClause.IntoIdentifierToken); | 
						|
			 | 
						|
			// We need to declare the group variable, but it's a bit tricky to determine its type: | 
						|
			// We'll have to resolve the GroupJoin invocation and take a look at the inferred types | 
						|
			// for the lambda given as last parameter. | 
						|
			var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupJoin", EmptyList<IType>.Instance); | 
						|
			QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause; | 
						|
			LambdaResolveResult groupJoinLambda; | 
						|
			if (selectClause != null) { | 
						|
				// from ... join ... into g select - the GroupJoin call also performs the Select operation | 
						|
				IParameter[] selectLambdaParameters = { | 
						|
					new DefaultParameter(SpecialType.UnknownType, "<>transparentIdentifier"), | 
						|
					new DefaultParameter(SpecialType.UnknownType, queryJoinClause.IntoIdentifier, region: intoIdentifierRegion) | 
						|
				}; | 
						|
				groupJoinLambda = new ImplicitlyTypedLambda(selectClause, selectLambdaParameters, this); | 
						|
			} else { | 
						|
				// from .. join ... ... - introduce a transparent identifier | 
						|
				groupJoinLambda = new QueryExpressionLambda(2, MakeTransparentIdentifierResolveResult()); | 
						|
			} | 
						|
			 | 
						|
			ResolveResult[] arguments = { | 
						|
				inResult, | 
						|
				new QueryExpressionLambda(1, onResult), | 
						|
				new QueryExpressionLambda(1, equalsResult), | 
						|
				groupJoinLambda | 
						|
			}; | 
						|
			ResolveResult rr = resolver.ResolveInvocation(methodGroup, arguments); | 
						|
			InvocationResolveResult invocationRR = rr as InvocationResolveResult; | 
						|
			 | 
						|
			IVariable groupVariable; | 
						|
			if (groupJoinLambda is ImplicitlyTypedLambda) { | 
						|
				var implicitlyTypedLambda = (ImplicitlyTypedLambda)groupJoinLambda; | 
						|
				 | 
						|
				if (invocationRR != null && invocationRR.Arguments.Count > 0) { | 
						|
					ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult; | 
						|
					if (crr != null) | 
						|
						ProcessConversion(null, crr.Input, crr.Conversion, crr.Type); | 
						|
				} | 
						|
				 | 
						|
				implicitlyTypedLambda.EnforceMerge(this); | 
						|
				if (implicitlyTypedLambda.Parameters.Count == 2) { | 
						|
					StoreCurrentState(queryJoinClause.IntoIdentifierToken); | 
						|
					groupVariable = implicitlyTypedLambda.Parameters[1]; | 
						|
				} else { | 
						|
					groupVariable = null; | 
						|
				} | 
						|
			} else { | 
						|
				Debug.Assert(groupJoinLambda is QueryExpressionLambda); | 
						|
				 | 
						|
				// Add the variable if the query expression continues after the group join | 
						|
				// (there's no need to do this if there's only a select clause remaining, as | 
						|
				// we already handled that in the ImplicitlyTypedLambda). | 
						|
				 | 
						|
				// Get the inferred type of the group variable: | 
						|
				IType[] inferredParameterTypes = null; | 
						|
				if (invocationRR != null && invocationRR.Arguments.Count > 0) { | 
						|
					ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult; | 
						|
					if (crr != null && crr.Conversion is QueryExpressionLambdaConversion) { | 
						|
						inferredParameterTypes = ((QueryExpressionLambdaConversion)crr.Conversion).ParameterTypes; | 
						|
					} | 
						|
				} | 
						|
				if (inferredParameterTypes == null) | 
						|
					inferredParameterTypes = ((QueryExpressionLambda)groupJoinLambda).inferredParameterTypes; | 
						|
				 | 
						|
				IType groupParameterType; | 
						|
				if (inferredParameterTypes != null && inferredParameterTypes.Length == 2) | 
						|
					groupParameterType = inferredParameterTypes[1]; | 
						|
				else | 
						|
					groupParameterType = SpecialType.UnknownType; | 
						|
				 | 
						|
				StoreCurrentState(queryJoinClause.IntoIdentifierToken); | 
						|
				groupVariable = MakeVariable(groupParameterType, queryJoinClause.IntoIdentifierToken); | 
						|
				resolver = resolver.AddVariable(groupVariable); | 
						|
			} | 
						|
			 | 
						|
			if (groupVariable != null) { | 
						|
				StoreResult(queryJoinClause.IntoIdentifierToken, new LocalResolveResult(groupVariable)); | 
						|
			} | 
						|
			 | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryWhereClause(QueryWhereClause queryWhereClause) | 
						|
		{ | 
						|
			ResolveResult condition = Resolve(queryWhereClause.Condition); | 
						|
			IType boolType = resolver.Compilation.FindType(KnownTypeCode.Boolean); | 
						|
			Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType); | 
						|
			ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType); | 
						|
			if (currentQueryResult != null) { | 
						|
				if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) { | 
						|
					condition = new ConversionResolveResult(boolType, condition, conversionToBool, resolver.CheckForOverflow); | 
						|
				} | 
						|
				 | 
						|
				var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Where", EmptyList<IType>.Instance); | 
						|
				ResolveResult[] arguments = { new QueryExpressionLambda(1, condition) }; | 
						|
				return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
			} else { | 
						|
				return errorResult; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQuerySelectClause(QuerySelectClause querySelectClause) | 
						|
		{ | 
						|
			if (currentQueryResult == null) { | 
						|
				ScanChildren(querySelectClause); | 
						|
				return errorResult; | 
						|
			} | 
						|
			QueryClause previousQueryClause = GetPreviousQueryClause(querySelectClause); | 
						|
			// If the 'select' follows on a 'SelectMany', 'Join' or 'GroupJoin' clause, then the 'select' portion | 
						|
			// was already done as part of the previous clause. | 
						|
			if (((previousQueryClause is QueryFromClause && GetPreviousQueryClause(previousQueryClause) != null)) | 
						|
			    || previousQueryClause is QueryJoinClause) | 
						|
			{ | 
						|
				// GroupJoin already scans the following select clause in a different context, | 
						|
				// so we must not scan it again. | 
						|
				if (!(previousQueryClause is QueryJoinClause && ((QueryJoinClause)previousQueryClause).IsGroupJoin)) | 
						|
					Scan(querySelectClause.Expression); | 
						|
				return WrapResult(currentQueryResult); | 
						|
			} | 
						|
			 | 
						|
			QueryExpression query = querySelectClause.Parent as QueryExpression; | 
						|
			string rangeVariable = GetSingleRangeVariable(query); | 
						|
			if (rangeVariable != null) { | 
						|
				IdentifierExpression ident = ParenthesizedExpression.UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression; | 
						|
				if (ident != null && ident.Identifier == rangeVariable && !ident.TypeArguments.Any()) { | 
						|
					// selecting the single identifier that is the range variable | 
						|
					if (query.Clauses.Count > 2) { | 
						|
						// only if the query is not degenerate: | 
						|
						// the Select call will be optimized away, so directly return the previous result | 
						|
						Scan(querySelectClause.Expression); | 
						|
						return WrapResult(currentQueryResult); | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			ResolveResult expr = Resolve(querySelectClause.Expression); | 
						|
			var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance); | 
						|
			ResolveResult[] arguments = { new QueryExpressionLambda(1, expr) }; | 
						|
			return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Gets the name of the range variable in the specified query. | 
						|
		/// If the query has multiple range variables, this method returns null. | 
						|
		/// </summary> | 
						|
		string GetSingleRangeVariable(QueryExpression query) | 
						|
		{ | 
						|
			if (query == null) | 
						|
				return null; | 
						|
			foreach (QueryClause clause in query.Clauses.Skip(1)) { | 
						|
				if (clause is QueryFromClause || clause is QueryJoinClause || clause is QueryLetClause) { | 
						|
					// query has more than 1 range variable | 
						|
					return null; | 
						|
				} | 
						|
			} | 
						|
			QueryFromClause fromClause = query.Clauses.FirstOrDefault() as QueryFromClause; | 
						|
			if (fromClause != null) | 
						|
				return fromClause.Identifier; | 
						|
			QueryContinuationClause continuationClause = query.Clauses.FirstOrDefault() as QueryContinuationClause; | 
						|
			if (continuationClause != null) | 
						|
				return continuationClause.Identifier; | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryGroupClause(QueryGroupClause queryGroupClause) | 
						|
		{ | 
						|
			if (currentQueryResult == null) { | 
						|
				ScanChildren(queryGroupClause); | 
						|
				return errorResult; | 
						|
			} | 
						|
			 | 
						|
			// ... group projection by key | 
						|
			ResolveResult projection = Resolve(queryGroupClause.Projection); | 
						|
			ResolveResult key = Resolve(queryGroupClause.Key); | 
						|
			 | 
						|
			var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupBy", EmptyList<IType>.Instance); | 
						|
			ResolveResult[] arguments = { | 
						|
				new QueryExpressionLambda(1, key), | 
						|
				new QueryExpressionLambda(1, projection) | 
						|
			}; | 
						|
			return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrderClause(QueryOrderClause queryOrderClause) | 
						|
		{ | 
						|
			foreach (QueryOrdering ordering in queryOrderClause.Orderings) { | 
						|
				currentQueryResult = Resolve(ordering); | 
						|
			} | 
						|
			return WrapResult(currentQueryResult); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrdering(QueryOrdering queryOrdering) | 
						|
		{ | 
						|
			if (currentQueryResult == null) { | 
						|
				ScanChildren(queryOrdering); | 
						|
				return errorResult; | 
						|
			} | 
						|
			// ... orderby sortKey [descending] | 
						|
			ResolveResult sortKey = Resolve(queryOrdering.Expression); | 
						|
			 | 
						|
			QueryOrderClause parentClause = queryOrdering.Parent as QueryOrderClause; | 
						|
			bool isFirst = (parentClause == null || parentClause.Orderings.FirstOrDefault() == queryOrdering); | 
						|
			string methodName = isFirst ? "OrderBy" : "ThenBy"; | 
						|
			if (queryOrdering.Direction == QueryOrderingDirection.Descending) | 
						|
				methodName += "Descending"; | 
						|
			 | 
						|
			var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, methodName, EmptyList<IType>.Instance); | 
						|
			ResolveResult[] arguments = { | 
						|
				new QueryExpressionLambda(1, sortKey), | 
						|
			}; | 
						|
			return resolver.ResolveInvocation(methodGroup, arguments); | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Constructor Initializer | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitConstructorInitializer(ConstructorInitializer constructorInitializer) | 
						|
		{ | 
						|
			ResolveResult target; | 
						|
			if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base) { | 
						|
				target = resolver.ResolveBaseReference(); | 
						|
			} else { | 
						|
				target = resolver.ResolveThisReference(); | 
						|
			} | 
						|
			string[] argumentNames; | 
						|
			ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames); | 
						|
			ResolveResult rr = resolver.ResolveObjectCreation(target.Type, arguments, argumentNames, allowProtectedAccess: true); | 
						|
			ProcessInvocationResult(null, constructorInitializer.Arguments, rr); | 
						|
			return rr; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Other Nodes | 
						|
		// Token nodes | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitIdentifier(Identifier identifier) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitComment (Comment comment) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitNewLine (NewLineNode comment) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitWhitespace(WhitespaceNode whitespaceNode) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitText(TextNode textNode) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitArraySpecifier(ArraySpecifier arraySpecifier) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitPatternPlaceholder(AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern) | 
						|
		{ | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		// Nodes where we just need to visit the children: | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitAccessor(Accessor accessor) | 
						|
		{ | 
						|
			ScanChildren(accessor); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitSwitchSection(SwitchSection switchSection) | 
						|
		{ | 
						|
			ScanChildren(switchSection); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitCaseLabel(CaseLabel caseLabel) | 
						|
		{ | 
						|
			ScanChildren(caseLabel); | 
						|
			return voidResult; | 
						|
		} | 
						|
		 | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitConstraint(Constraint constraint) | 
						|
		{ | 
						|
			ScanChildren(constraint); | 
						|
			return voidResult; | 
						|
		} | 
						|
		#endregion | 
						|
		 | 
						|
		#region Documentation Reference | 
						|
		ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference) | 
						|
		{ | 
						|
			// Resolve child nodes: | 
						|
			ITypeDefinition declaringTypeDef; | 
						|
			if (documentationReference.DeclaringType.IsNull) | 
						|
				declaringTypeDef = resolver.CurrentTypeDefinition; | 
						|
			else | 
						|
				declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition(); | 
						|
			IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray(); | 
						|
			IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType); | 
						|
			IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray(); | 
						|
			 | 
						|
			if (documentationReference.EntityType == EntityType.TypeDefinition) { | 
						|
				if (declaringTypeDef != null) | 
						|
					return new TypeResolveResult(declaringTypeDef); | 
						|
				else | 
						|
					return errorResult; | 
						|
			} | 
						|
			 | 
						|
			if (documentationReference.EntityType == EntityType.None) { | 
						|
				// might be a type, member or ctor | 
						|
				string memberName = documentationReference.MemberName; | 
						|
				ResolveResult rr; | 
						|
				if (documentationReference.DeclaringType.IsNull) { | 
						|
					rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression); | 
						|
				} else { | 
						|
					var target = Resolve(documentationReference.DeclaringType); | 
						|
					rr = resolver.ResolveMemberAccess(target, memberName, typeArguments); | 
						|
				} | 
						|
				// reduce to definition: | 
						|
				if (rr.IsError) { | 
						|
					return rr; | 
						|
				} else if (rr is TypeResolveResult) { | 
						|
					var typeDef = rr.Type.GetDefinition(); | 
						|
					if (typeDef == null) | 
						|
						return errorResult; | 
						|
					if (documentationReference.HasParameterList) { | 
						|
						var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions); | 
						|
						return FindByParameters(ctors, parameters); | 
						|
					} else { | 
						|
						return new TypeResolveResult(typeDef); | 
						|
					} | 
						|
				} else if (rr is MemberResolveResult) { | 
						|
					var mrr = (MemberResolveResult)rr; | 
						|
					return new MemberResolveResult(null, mrr.Member.MemberDefinition); | 
						|
				} else if (rr is MethodGroupResolveResult) { | 
						|
					var mgrr = (MethodGroupResolveResult)rr; | 
						|
					var methods = mgrr.MethodsGroupedByDeclaringType.Reverse() | 
						|
						.SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition)); | 
						|
					return FindByParameters(methods, parameters); | 
						|
				} | 
						|
				return rr; | 
						|
			} | 
						|
			 | 
						|
			// Indexer or operator | 
						|
			if (declaringTypeDef == null) | 
						|
				return errorResult; | 
						|
			if (documentationReference.EntityType == EntityType.Indexer) { | 
						|
				var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation); | 
						|
				return FindByParameters(indexers, parameters); | 
						|
			} else if (documentationReference.EntityType == EntityType.Operator) { | 
						|
				var opType = documentationReference.OperatorType; | 
						|
				string memberName = OperatorDeclaration.GetName(opType); | 
						|
				var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName); | 
						|
				if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) { | 
						|
					// conversion operator | 
						|
					foreach (var method in methods) { | 
						|
						if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) { | 
						|
							if (method.ReturnType.Equals(conversionOperatorReturnType)) | 
						|
								return new MemberResolveResult(null, method); | 
						|
						} | 
						|
					} | 
						|
					return new MemberResolveResult(null, methods.FirstOrDefault()); | 
						|
				} else { | 
						|
					// not a conversion operator | 
						|
					return FindByParameters(methods, parameters); | 
						|
				} | 
						|
			} else { | 
						|
				throw new NotSupportedException(); // unknown entity type | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		IParameter ResolveXmlDocParameter(ParameterDeclaration p) | 
						|
		{ | 
						|
			var lrr = Resolve(p) as LocalResolveResult; | 
						|
			if (lrr != null && lrr.IsParameter) | 
						|
				return (IParameter)lrr.Variable; | 
						|
			else | 
						|
				return new DefaultParameter(SpecialType.UnknownType, string.Empty); | 
						|
		} | 
						|
		 | 
						|
		ResolveResult FindByParameters(IEnumerable<IParameterizedMember> methods, IList<IParameter> parameters) | 
						|
		{ | 
						|
			foreach (var method in methods) { | 
						|
				if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) | 
						|
					return new MemberResolveResult(null, method); | 
						|
			} | 
						|
			return new MemberResolveResult(null, methods.FirstOrDefault()); | 
						|
		} | 
						|
		#endregion | 
						|
	} | 
						|
}
 | 
						|
 |