PageRenderTime 105ms CodeModel.GetById 17ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 1ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/anonymous.cs

http://github.com/icsharpcode/ILSpy
C# | 2292 lines | 1547 code | 408 blank | 337 comment | 384 complexity | 78a3ad6fc1ff25d143b9274abfc8b331 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1//
   2// anonymous.cs: Support for anonymous methods and types
   3//
   4// Author:
   5//   Miguel de Icaza (miguel@ximain.com)
   6//   Marek Safar (marek.safar@gmail.com)
   7//
   8// Dual licensed under the terms of the MIT X11 or GNU GPL
   9// Copyright 2003-2011 Novell, Inc.
  10// Copyright 2011 Xamarin Inc
  11//
  12
  13using System;
  14using System.Collections.Generic;
  15using Mono.CompilerServices.SymbolWriter;
  16using System.Diagnostics;
  17
  18#if STATIC
  19using IKVM.Reflection;
  20using IKVM.Reflection.Emit;
  21using System.Diagnostics;
  22#else
  23using System.Reflection;
  24using System.Reflection.Emit;
  25#endif
  26
  27namespace Mono.CSharp {
  28
  29	public abstract class CompilerGeneratedContainer : ClassOrStruct
  30	{
  31		protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod)
  32			: this (parent, name, mod, MemberKind.Class)
  33		{
  34		}
  35
  36		protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod, MemberKind kind)
  37			: base (parent, name, null, kind)
  38		{
  39			Debug.Assert ((mod & Modifiers.AccessibilityMask) != 0);
  40
  41			ModFlags = mod | Modifiers.COMPILER_GENERATED | Modifiers.SEALED;
  42			spec = new TypeSpec (Kind, null, this, null, ModFlags);
  43		}
  44
  45		protected void CheckMembersDefined ()
  46		{
  47			if (HasMembersDefined)
  48				throw new InternalErrorException ("Helper class already defined!");
  49		}
  50
  51		protected override bool DoDefineMembers ()
  52		{
  53			if (Kind == MemberKind.Class && !IsStatic && !PartialContainer.HasInstanceConstructor) {
  54				DefineDefaultConstructor (false);
  55			}
  56
  57			return base.DoDefineMembers ();
  58		}
  59
  60		protected static MemberName MakeMemberName (MemberBase host, string name, int unique_id, TypeParameters tparams, Location loc)
  61		{
  62			string host_name = host == null ? null : host is InterfaceMemberBase ? ((InterfaceMemberBase)host).GetFullName (host.MemberName) : host.MemberName.Name;
  63			string tname = MakeName (host_name, "c", name, unique_id);
  64			TypeParameters args = null;
  65			if (tparams != null) {
  66				args = new TypeParameters (tparams.Count);
  67
  68				// Type parameters will be filled later when we have TypeContainer
  69				// instance, for now we need only correct arity to create valid name
  70				for (int i = 0; i < tparams.Count; ++i)
  71					args.Add ((TypeParameter) null);
  72			}
  73
  74			return new MemberName (tname, args, loc);
  75		}
  76
  77		public static string MakeName (string host, string typePrefix, string name, int id)
  78		{
  79			return "<" + host + ">" + typePrefix + "__" + name + id.ToString ("X");
  80		}
  81
  82		protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
  83		{
  84			base_type = Compiler.BuiltinTypes.Object;
  85
  86			base_class = null;
  87			return null;
  88		}
  89	}
  90
  91	public class HoistedStoreyClass : CompilerGeneratedContainer
  92	{
  93		public sealed class HoistedField : Field
  94		{
  95			public HoistedField (HoistedStoreyClass parent, FullNamedExpression type, Modifiers mod, string name,
  96				  Attributes attrs, Location loc)
  97				: base (parent, type, mod, new MemberName (name, loc), attrs)
  98			{
  99			}
 100
 101			protected override bool ResolveMemberType ()
 102			{
 103				if (!base.ResolveMemberType ())
 104					return false;
 105
 106				HoistedStoreyClass parent = ((HoistedStoreyClass) Parent).GetGenericStorey ();
 107				if (parent != null && parent.Mutator != null)
 108					member_type = parent.Mutator.Mutate (MemberType);
 109
 110				return true;
 111			}
 112		}
 113
 114		protected TypeParameterMutator mutator;
 115
 116		public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mods, MemberKind kind)
 117			: base (parent, name, mods | Modifiers.PRIVATE, kind)
 118		{
 119
 120			if (tparams != null) {
 121				var type_params = name.TypeParameters;
 122				var src = new TypeParameterSpec[tparams.Count];
 123				var dst = new TypeParameterSpec[tparams.Count];
 124
 125				for (int i = 0; i < tparams.Count; ++i) {
 126					type_params[i] = tparams[i].CreateHoistedCopy (spec);
 127
 128					src[i] = tparams[i].Type;
 129					dst[i] = type_params[i].Type;
 130				}
 131
 132				// A copy is not enough, inflate any type parameter constraints
 133				// using a new type parameters
 134				var inflator = new TypeParameterInflator (this, null, src, dst);
 135				for (int i = 0; i < tparams.Count; ++i) {
 136					src[i].InflateConstraints (inflator, dst[i]);
 137				}
 138
 139				mutator = new TypeParameterMutator (tparams, type_params);
 140			}
 141		}
 142
 143		#region Properties
 144
 145		public TypeParameterMutator Mutator {
 146			get {
 147				return mutator;
 148			}
 149			set {
 150				mutator = value;
 151			}
 152		}
 153
 154		#endregion
 155
 156		public HoistedStoreyClass GetGenericStorey ()
 157		{
 158			TypeContainer storey = this;
 159			while (storey != null && storey.CurrentTypeParameters == null)
 160				storey = storey.Parent;
 161
 162			return storey as HoistedStoreyClass;
 163		}
 164	}
 165
 166
 167	//
 168	// Anonymous method storey is created when an anonymous method uses
 169	// variable or parameter from outer scope. They are then hoisted to
 170	// anonymous method storey (captured)
 171	//
 172	public class AnonymousMethodStorey : HoistedStoreyClass
 173	{
 174		struct StoreyFieldPair
 175		{
 176			public readonly AnonymousMethodStorey Storey;
 177			public readonly Field Field;
 178
 179			public StoreyFieldPair (AnonymousMethodStorey storey, Field field)
 180			{
 181				this.Storey = storey;
 182				this.Field = field;
 183			}
 184		}
 185
 186		//
 187		// Needed to delay hoisted _this_ initialization. When an anonymous
 188		// method is used inside ctor and _this_ is hoisted, base ctor has to
 189		// be called first, otherwise _this_ will be initialized with 
 190		// uninitialized value.
 191		//
 192		sealed class ThisInitializer : Statement
 193		{
 194			readonly HoistedThis hoisted_this;
 195			readonly AnonymousMethodStorey parent;
 196
 197			public ThisInitializer (HoistedThis hoisted_this, AnonymousMethodStorey parent)
 198			{
 199				this.hoisted_this = hoisted_this;
 200				this.parent = parent;
 201			}
 202
 203			protected override void DoEmit (EmitContext ec)
 204			{
 205				Expression source;
 206
 207				if (parent == null)
 208					source = new CompilerGeneratedThis (ec.CurrentType, loc);
 209				else {
 210					source = new FieldExpr (parent.HoistedThis.Field, Location.Null) {
 211						InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location.Null)
 212					};
 213				}
 214
 215				hoisted_this.EmitAssign (ec, source, false, false);
 216			}
 217
 218			protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
 219			{
 220				return false;
 221			}
 222
 223			protected override void CloneTo (CloneContext clonectx, Statement target)
 224			{
 225				// Nothing to clone
 226			}
 227		}
 228
 229		// Unique storey ID
 230		public readonly int ID;
 231
 232		public readonly ExplicitBlock OriginalSourceBlock;
 233
 234		// A list of StoreyFieldPair with local field keeping parent storey instance
 235		List<StoreyFieldPair> used_parent_storeys;
 236		List<ExplicitBlock> children_references;
 237
 238		// A list of hoisted parameters
 239		protected List<HoistedParameter> hoisted_params;
 240		List<HoistedParameter> hoisted_local_params;
 241		protected List<HoistedVariable> hoisted_locals;
 242
 243		// Hoisted this
 244		protected HoistedThis hoisted_this;
 245
 246		// Local variable which holds this storey instance
 247		public Expression Instance;
 248
 249		bool initialize_hoisted_this;
 250		AnonymousMethodStorey hoisted_this_parent;
 251
 252		public AnonymousMethodStorey (ExplicitBlock block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name, MemberKind kind)
 253			: base (parent, MakeMemberName (host, name, parent.PartialContainer.CounterAnonymousContainers, tparams, block.StartLocation),
 254				tparams, 0, kind)
 255		{
 256			OriginalSourceBlock = block;
 257			ID = parent.PartialContainer.CounterAnonymousContainers++;
 258		}
 259
 260		public void AddCapturedThisField (EmitContext ec, AnonymousMethodStorey parent)
 261		{
 262			TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location);
 263			Field f = AddCompilerGeneratedField ("$this", type_expr);
 264			hoisted_this = new HoistedThis (this, f);
 265
 266			initialize_hoisted_this = true;
 267			hoisted_this_parent = parent;
 268		}
 269
 270		public Field AddCapturedVariable (string name, TypeSpec type)
 271		{
 272			CheckMembersDefined ();
 273
 274			FullNamedExpression field_type = new TypeExpression (type, Location);
 275			if (!spec.IsGenericOrParentIsGeneric)
 276				return AddCompilerGeneratedField (name, field_type);
 277
 278			const Modifiers mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
 279			Field f = new HoistedField (this, field_type, mod, name, null, Location);
 280			AddField (f);
 281			return f;
 282		}
 283
 284		protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
 285		{
 286			return AddCompilerGeneratedField (name, type, false);
 287		}
 288
 289		protected Field AddCompilerGeneratedField (string name, FullNamedExpression type, bool privateAccess)
 290		{
 291			Modifiers mod = Modifiers.COMPILER_GENERATED | (privateAccess ? Modifiers.PRIVATE : Modifiers.INTERNAL);
 292			Field f = new Field (this, type, mod, new MemberName (name, Location), null);
 293			AddField (f);
 294			return f;
 295		}
 296
 297		//
 298		// Creates a link between hoisted variable block and the anonymous method storey
 299		//
 300		// An anonymous method can reference variables from any outer block, but they are
 301		// hoisted in their own ExplicitBlock. When more than one block is referenced we
 302		// need to create another link between those variable storeys
 303		//
 304		public void AddReferenceFromChildrenBlock (ExplicitBlock block)
 305		{
 306			if (children_references == null)
 307				children_references = new List<ExplicitBlock> ();
 308
 309			if (!children_references.Contains (block))
 310				children_references.Add (block);
 311		}
 312
 313		public void AddParentStoreyReference (EmitContext ec, AnonymousMethodStorey storey)
 314		{
 315			CheckMembersDefined ();
 316
 317			if (used_parent_storeys == null)
 318				used_parent_storeys = new List<StoreyFieldPair> ();
 319			else if (used_parent_storeys.Exists (i => i.Storey == storey))
 320				return;
 321
 322			TypeExpr type_expr = storey.CreateStoreyTypeExpression (ec);
 323			Field f = AddCompilerGeneratedField ("<>f__ref$" + storey.ID, type_expr);
 324			used_parent_storeys.Add (new StoreyFieldPair (storey, f));
 325		}
 326
 327		public void CaptureLocalVariable (ResolveContext ec, LocalVariable localVariable)
 328		{
 329			if (this is StateMachine) {
 330				if (ec.CurrentBlock.ParametersBlock != localVariable.Block.ParametersBlock)
 331					ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 332			} else {
 333				ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 334			}
 335
 336			var hoisted = localVariable.HoistedVariant;
 337			if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) {
 338				//
 339				// Variable is already hoisted but we need it in storey which can be shared
 340				//
 341				hoisted.Storey.hoisted_locals.Remove (hoisted);
 342				hoisted.Storey.Members.Remove (hoisted.Field);
 343				hoisted = null;
 344			}
 345
 346			if (hoisted == null) {
 347				hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (localVariable));
 348				localVariable.HoistedVariant = hoisted;
 349
 350				if (hoisted_locals == null)
 351					hoisted_locals = new List<HoistedVariable> ();
 352
 353				hoisted_locals.Add (hoisted);
 354			}
 355
 356			if (ec.CurrentBlock.Explicit != localVariable.Block.Explicit && !(hoisted.Storey is StateMachine))
 357				hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
 358		}
 359
 360		public void CaptureParameter (ResolveContext ec, ParametersBlock.ParameterInfo parameterInfo, ParameterReference parameterReference)
 361		{
 362			if (!(this is StateMachine)) {
 363				ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 364			}
 365
 366			var hoisted = parameterInfo.Parameter.HoistedVariant;
 367
 368			if (parameterInfo.Block.StateMachine != null) {
 369				//
 370				// Another storey in same block exists but state machine does not
 371				// have parameter captured. We need to add it there as well to
 372				// proxy parameter value correctly.
 373				//
 374				if (hoisted == null && parameterInfo.Block.StateMachine != this) {
 375					var storey = parameterInfo.Block.StateMachine;
 376
 377					hoisted = new HoistedParameter (storey, parameterReference);
 378					parameterInfo.Parameter.HoistedVariant = hoisted;
 379
 380					if (storey.hoisted_params == null)
 381						storey.hoisted_params = new List<HoistedParameter> ();
 382
 383					storey.hoisted_params.Add (hoisted);
 384				}
 385
 386				//
 387				// Lift captured parameter from value type storey to reference type one. Otherwise
 388				// any side effects would be done on a copy
 389				//
 390				if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) {
 391					if (hoisted_local_params == null)
 392						hoisted_local_params = new List<HoistedParameter> ();
 393
 394					hoisted_local_params.Add (hoisted);
 395					hoisted = null;
 396				}
 397			}
 398
 399			if (hoisted == null) {
 400				hoisted = new HoistedParameter (this, parameterReference);
 401				parameterInfo.Parameter.HoistedVariant = hoisted;
 402
 403				if (hoisted_params == null)
 404					hoisted_params = new List<HoistedParameter> ();
 405
 406				hoisted_params.Add (hoisted);
 407			}
 408
 409			//
 410			// Register link between current block and parameter storey. It will
 411			// be used when setting up storey definition to deploy storey reference
 412			// when parameters are used from multiple blocks
 413			//
 414			if (ec.CurrentBlock.Explicit != parameterInfo.Block) {
 415				hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
 416			}
 417		}
 418
 419		TypeExpr CreateStoreyTypeExpression (EmitContext ec)
 420		{
 421			//
 422			// Create an instance of storey type
 423			//
 424			TypeExpr storey_type_expr;
 425			if (CurrentTypeParameters != null) {
 426				//
 427				// Use current method type parameter (MVAR) for top level storey only. All
 428				// nested storeys use class type parameter (VAR)
 429				//
 430				var tparams = ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null ?
 431					ec.CurrentAnonymousMethod.Storey.CurrentTypeParameters :
 432					ec.CurrentTypeParameters;
 433
 434				TypeArguments targs = new TypeArguments ();
 435
 436				//
 437				// Use type parameter name instead of resolved type parameter
 438				// specification to resolve to correctly nested type parameters
 439				//
 440				for (int i = 0; i < tparams.Count; ++i)
 441					targs.Add (new SimpleName (tparams [i].Name, Location)); //  new TypeParameterExpr (tparams[i], Location));
 442
 443				storey_type_expr = new GenericTypeExpr (Definition, targs, Location);
 444			} else {
 445				storey_type_expr = new TypeExpression (CurrentType, Location);
 446			}
 447
 448			return storey_type_expr;
 449		}
 450
 451		public void SetNestedStoryParent (AnonymousMethodStorey parentStorey)
 452		{
 453			Parent = parentStorey;
 454			spec.IsGeneric = false;
 455			spec.DeclaringType = parentStorey.CurrentType;
 456			MemberName.TypeParameters = null;
 457		}
 458
 459		protected override bool DoResolveTypeParameters ()
 460		{
 461			// Although any storey can have type parameters they are all clones of method type
 462			// parameters therefore have to mutate MVAR references in any of cloned constraints
 463			if (CurrentTypeParameters != null) {
 464				for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
 465					var spec = CurrentTypeParameters[i].Type;
 466					spec.BaseType = mutator.Mutate (spec.BaseType);
 467					if (spec.InterfacesDefined != null) {
 468						var mutated = new TypeSpec[spec.InterfacesDefined.Length];
 469						for (int ii = 0; ii < mutated.Length; ++ii) {
 470							mutated[ii] = mutator.Mutate (spec.InterfacesDefined[ii]);
 471						}
 472
 473						spec.InterfacesDefined = mutated;
 474					}
 475
 476					if (spec.TypeArguments != null) {
 477						spec.TypeArguments = mutator.Mutate (spec.TypeArguments);
 478					}
 479				}
 480			}
 481
 482			//
 483			// Update parent cache as we most likely passed the point
 484			// where the cache was constructed
 485			//
 486			Parent.CurrentType.MemberCache.AddMember (this.spec);
 487
 488			return true;
 489		}
 490
 491		//
 492		// Initializes all hoisted variables
 493		//
 494		public void EmitStoreyInstantiation (EmitContext ec, ExplicitBlock block)
 495		{
 496			// There can be only one instance variable for each storey type
 497			if (Instance != null)
 498				throw new InternalErrorException ();
 499
 500			//
 501			// Create an instance of this storey
 502			//
 503			ResolveContext rc = new ResolveContext (ec.MemberContext);
 504			rc.CurrentBlock = block;
 505
 506			var storey_type_expr = CreateStoreyTypeExpression (ec);
 507			var source = new New (storey_type_expr, null, Location).Resolve (rc);
 508
 509			//
 510			// When the current context is async (or iterator) lift local storey
 511			// instantiation to the currect storey
 512			//
 513			if (ec.CurrentAnonymousMethod is StateMachineInitializer && (block.HasYield || block.HasAwait)) {
 514				//
 515				// Unfortunately, normal capture mechanism could not be used because we are
 516				// too late in the pipeline and standart assign cannot be used either due to
 517				// recursive nature of GetStoreyInstanceExpression
 518				//
 519				var field = ec.CurrentAnonymousMethod.Storey.AddCompilerGeneratedField (
 520					LocalVariable.GetCompilerGeneratedName (block), storey_type_expr, true);
 521
 522				field.Define ();
 523				field.Emit ();
 524
 525				var fexpr = new FieldExpr (field, Location);
 526				fexpr.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location);
 527				fexpr.EmitAssign (ec, source, false, false);
 528				Instance = fexpr;
 529			} else {
 530				var local = TemporaryVariableReference.Create (source.Type, block, Location);
 531				if (source.Type.IsStruct) {
 532					local.LocalInfo.CreateBuilder (ec);
 533				} else {
 534					local.EmitAssign (ec, source);
 535				}
 536
 537				Instance = local;
 538			}
 539
 540			EmitHoistedFieldsInitialization (rc, ec);
 541
 542			// TODO: Implement properly
 543			//SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
 544		}
 545
 546		void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec)
 547		{
 548			//
 549			// Initialize all storey reference fields by using local or hoisted variables
 550			//
 551			if (used_parent_storeys != null) {
 552				foreach (StoreyFieldPair sf in used_parent_storeys) {
 553					//
 554					// Get instance expression of storey field
 555					//
 556					Expression instace_expr = GetStoreyInstanceExpression (ec);
 557					var fs = sf.Field.Spec;
 558					if (TypeManager.IsGenericType (instace_expr.Type))
 559						fs = MemberCache.GetMember (instace_expr.Type, fs);
 560
 561					FieldExpr f_set_expr = new FieldExpr (fs, Location);
 562					f_set_expr.InstanceExpression = instace_expr;
 563
 564					// TODO: CompilerAssign expression
 565					SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec));
 566					if (a.Resolve (rc) != null)
 567						a.EmitStatement (ec);
 568				}
 569			}
 570
 571			//
 572			// Initialize hoisted `this' only once, everywhere else will be
 573			// referenced indirectly
 574			//
 575			if (initialize_hoisted_this) {
 576				rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this, hoisted_this_parent));
 577			}
 578
 579			//
 580			// Setting currect anonymous method to null blocks any further variable hoisting
 581			//
 582			AnonymousExpression ae = ec.CurrentAnonymousMethod;
 583			ec.CurrentAnonymousMethod = null;
 584
 585			if (hoisted_params != null) {
 586				EmitHoistedParameters (ec, hoisted_params);
 587			}
 588
 589			ec.CurrentAnonymousMethod = ae;
 590		}
 591
 592		protected virtual void EmitHoistedParameters (EmitContext ec, List<HoistedParameter> hoisted)
 593		{
 594			foreach (HoistedParameter hp in hoisted) {
 595				if (hp == null)
 596					continue;
 597
 598				//
 599				// Parameters could be proxied via local fields for value type storey
 600				//
 601				if (hoisted_local_params != null) {
 602					var local_param = hoisted_local_params.Find (l => l.Parameter.Parameter == hp.Parameter.Parameter);
 603					var source = new FieldExpr (local_param.Field, Location);
 604					source.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
 605					hp.EmitAssign (ec, source, false, false);
 606					continue;
 607				}
 608
 609				hp.EmitHoistingAssignment (ec);
 610			}
 611		}
 612
 613		//
 614		// Returns a field which holds referenced storey instance
 615		//
 616		Field GetReferencedStoreyField (AnonymousMethodStorey storey)
 617		{
 618			if (used_parent_storeys == null)
 619				return null;
 620
 621			foreach (StoreyFieldPair sf in used_parent_storeys) {
 622				if (sf.Storey == storey)
 623					return sf.Field;
 624			}
 625
 626			return null;
 627		}
 628
 629		//
 630		// Creates storey instance expression regardless of currect IP
 631		//
 632		public Expression GetStoreyInstanceExpression (EmitContext ec)
 633		{
 634			AnonymousExpression am = ec.CurrentAnonymousMethod;
 635
 636			//
 637			// Access from original block -> storey
 638			//
 639			if (am == null)
 640				return Instance;
 641
 642			//
 643			// Access from anonymous method implemented as a static -> storey
 644			//
 645			if (am.Storey == null)
 646				return Instance;
 647
 648			Field f = am.Storey.GetReferencedStoreyField (this);
 649			if (f == null) {
 650				if (am.Storey == this) {
 651					//
 652					// Access from inside of same storey (S -> S)
 653					//
 654					return new CompilerGeneratedThis (CurrentType, Location);
 655				}
 656
 657				//
 658				// External field access
 659				//
 660				return Instance;
 661			}
 662
 663			//
 664			// Storey was cached to local field
 665			//
 666			FieldExpr f_ind = new FieldExpr (f, Location);
 667			f_ind.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
 668			return f_ind;
 669		}
 670
 671		protected virtual string GetVariableMangledName (LocalVariable local_info)
 672		{
 673			//
 674			// No need to mangle anonymous method hoisted variables cause they
 675			// are hoisted in their own scopes
 676			//
 677			return local_info.Name;
 678		}
 679
 680		public HoistedThis HoistedThis {
 681			get {
 682				return hoisted_this;
 683			}
 684			set {
 685				hoisted_this = value;
 686			}
 687		}
 688
 689		public IList<ExplicitBlock> ReferencesFromChildrenBlock {
 690			get { return children_references; }
 691		}
 692	}
 693
 694	public abstract class HoistedVariable
 695	{
 696		//
 697		// Hoisted version of variable references used in expression
 698		// tree has to be delayed until we know its location. The variable
 699		// doesn't know its location until all stories are calculated
 700		//
 701		class ExpressionTreeVariableReference : Expression
 702		{
 703			readonly HoistedVariable hv;
 704
 705			public ExpressionTreeVariableReference (HoistedVariable hv)
 706			{
 707				this.hv = hv;
 708			}
 709
 710			public override bool ContainsEmitWithAwait ()
 711			{
 712				return false;
 713			}
 714
 715			public override Expression CreateExpressionTree (ResolveContext ec)
 716			{
 717				return hv.CreateExpressionTree ();
 718			}
 719
 720			protected override Expression DoResolve (ResolveContext ec)
 721			{
 722				eclass = ExprClass.Value;
 723				type = ec.Module.PredefinedTypes.Expression.Resolve ();
 724				return this;
 725			}
 726
 727			public override void Emit (EmitContext ec)
 728			{
 729				ResolveContext rc = new ResolveContext (ec.MemberContext);
 730				Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (rc, false);
 731				// This should never fail
 732				e = e.Resolve (rc);
 733				if (e != null)
 734					e.Emit (ec);
 735			}
 736		}
 737	
 738		protected readonly AnonymousMethodStorey storey;
 739		protected Field field;
 740		Dictionary<AnonymousExpression, FieldExpr> cached_inner_access; // TODO: Hashtable is too heavyweight
 741		FieldExpr cached_outer_access;
 742
 743		protected HoistedVariable (AnonymousMethodStorey storey, string name, TypeSpec type)
 744			: this (storey, storey.AddCapturedVariable (name, type))
 745		{
 746		}
 747
 748		protected HoistedVariable (AnonymousMethodStorey storey, Field field)
 749		{
 750			this.storey = storey;
 751			this.field = field;
 752		}
 753
 754		public Field Field {
 755			get {
 756				return field;
 757			}
 758		}
 759
 760		public AnonymousMethodStorey Storey {
 761			get {
 762				return storey;
 763			}
 764		}
 765
 766		public void AddressOf (EmitContext ec, AddressOp mode)
 767		{
 768			GetFieldExpression (ec).AddressOf (ec, mode);
 769		}
 770
 771		public Expression CreateExpressionTree ()
 772		{
 773			return new ExpressionTreeVariableReference (this);
 774		}
 775
 776		public void Emit (EmitContext ec)
 777		{
 778			GetFieldExpression (ec).Emit (ec);
 779		}
 780
 781		public Expression EmitToField (EmitContext ec)
 782		{
 783			return GetFieldExpression (ec);
 784		}
 785
 786		//
 787		// Creates field access expression for hoisted variable
 788		//
 789		protected virtual FieldExpr GetFieldExpression (EmitContext ec)
 790		{
 791			if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) {
 792				if (cached_outer_access != null)
 793					return cached_outer_access;
 794
 795				//
 796				// When setting top-level hoisted variable in generic storey
 797				// change storey generic types to method generic types (VAR -> MVAR)
 798				//
 799				if (storey.Instance.Type.IsGenericOrParentIsGeneric) {
 800					var fs = MemberCache.GetMember (storey.Instance.Type, field.Spec);
 801					cached_outer_access = new FieldExpr (fs, field.Location);
 802				} else {
 803					cached_outer_access = new FieldExpr (field, field.Location);
 804				}
 805
 806				cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
 807				return cached_outer_access;
 808			}
 809
 810			FieldExpr inner_access;
 811			if (cached_inner_access != null) {
 812				if (!cached_inner_access.TryGetValue (ec.CurrentAnonymousMethod, out inner_access))
 813					inner_access = null;
 814			} else {
 815				inner_access = null;
 816				cached_inner_access = new Dictionary<AnonymousExpression, FieldExpr> (4);
 817			}
 818
 819			if (inner_access == null) {
 820				if (field.Parent.IsGenericOrParentIsGeneric) {
 821					var fs = MemberCache.GetMember (field.Parent.CurrentType, field.Spec);
 822					inner_access = new FieldExpr (fs, field.Location);
 823				} else {
 824					inner_access = new FieldExpr (field, field.Location);
 825				}
 826
 827				inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
 828				cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access);
 829			}
 830
 831			return inner_access;
 832		}
 833
 834		public void Emit (EmitContext ec, bool leave_copy)
 835		{
 836			GetFieldExpression (ec).Emit (ec, leave_copy);
 837		}
 838
 839		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
 840		{
 841			GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
 842		}
 843	}
 844
 845	public class HoistedParameter : HoistedVariable
 846	{
 847		sealed class HoistedFieldAssign : CompilerAssign
 848		{
 849			public HoistedFieldAssign (Expression target, Expression source)
 850				: base (target, source, target.Location)
 851			{
 852			}
 853
 854			protected override Expression ResolveConversions (ResolveContext ec)
 855			{
 856				//
 857				// Implicit conversion check fails for hoisted type arguments
 858				// as they are of different types (!!0 x !0)
 859				//
 860				return this;
 861			}
 862		}
 863
 864		readonly ParameterReference parameter;
 865
 866		public HoistedParameter (AnonymousMethodStorey scope, ParameterReference par)
 867			: base (scope, par.Name, par.Type)
 868		{
 869			this.parameter = par;
 870		}
 871
 872		public HoistedParameter (HoistedParameter hp, string name)
 873			: base (hp.storey, name, hp.parameter.Type)
 874		{
 875			this.parameter = hp.parameter;
 876		}
 877
 878		#region Properties
 879
 880		public bool IsAssigned { get; set; }
 881
 882		public ParameterReference Parameter {
 883			get {
 884				return parameter;
 885			}
 886		}
 887
 888		#endregion
 889
 890		public void EmitHoistingAssignment (EmitContext ec)
 891		{
 892			//
 893			// Remove hoisted redirection to emit assignment from original parameter
 894			//
 895			var temp = parameter.Parameter.HoistedVariant;
 896			parameter.Parameter.HoistedVariant = null;
 897
 898			var a = new HoistedFieldAssign (GetFieldExpression (ec), parameter);
 899			a.EmitStatement (ec);
 900
 901			parameter.Parameter.HoistedVariant = temp;
 902		}
 903	}
 904
 905	class HoistedLocalVariable : HoistedVariable
 906	{
 907		public HoistedLocalVariable (AnonymousMethodStorey storey, LocalVariable local, string name)
 908			: base (storey, name, local.Type)
 909		{
 910		}
 911	}
 912
 913	public class HoistedThis : HoistedVariable
 914	{
 915		public HoistedThis (AnonymousMethodStorey storey, Field field)
 916			: base (storey, field)
 917		{
 918		}
 919	}
 920
 921	//
 922	// Anonymous method expression as created by parser
 923	//
 924	public class AnonymousMethodExpression : Expression
 925	{
 926		//
 927		// Special conversion for nested expression tree lambdas
 928		//
 929		class Quote : ShimExpression
 930		{
 931			public Quote (Expression expr)
 932				: base (expr)
 933			{
 934			}
 935
 936			public override Expression CreateExpressionTree (ResolveContext ec)
 937			{
 938				var args = new Arguments (1);
 939				args.Add (new Argument (expr.CreateExpressionTree (ec)));
 940				return CreateExpressionFactoryCall (ec, "Quote", args);
 941			}
 942
 943			protected override Expression DoResolve (ResolveContext rc)
 944			{
 945				expr = expr.Resolve (rc);
 946				if (expr == null)
 947					return null;
 948
 949				eclass = expr.eclass;
 950				type = expr.Type;
 951				return this;
 952			}
 953		}
 954
 955		readonly Dictionary<TypeSpec, Expression> compatibles;
 956
 957		public ParametersBlock Block;
 958
 959		public AnonymousMethodExpression (Location loc)
 960		{
 961			this.loc = loc;
 962			this.compatibles = new Dictionary<TypeSpec, Expression> ();
 963		}
 964
 965		#region Properties
 966
 967		public override string ExprClassName {
 968			get {
 969				return "anonymous method";
 970			}
 971		}
 972
 973		public virtual bool HasExplicitParameters {
 974			get {
 975				return Parameters != ParametersCompiled.Undefined;
 976			}
 977		}
 978
 979		public override bool IsSideEffectFree {
 980			get {
 981				return true;
 982			}
 983		}
 984
 985		public ParametersCompiled Parameters {
 986			get {
 987				return Block.Parameters;
 988			}
 989		}
 990
 991		public bool IsAsync {
 992			get;
 993			internal set;
 994		}
 995
 996		public ReportPrinter TypeInferenceReportPrinter {
 997			get; set;
 998		}
 999
1000		#endregion
1001
1002		//
1003		// Returns true if the body of lambda expression can be implicitly
1004		// converted to the delegate of type `delegate_type'
1005		//
1006		public bool ImplicitStandardConversionExists (ResolveContext ec, TypeSpec delegate_type)
1007		{
1008			using (ec.With (ResolveContext.Options.InferReturnType, false)) {
1009				using (ec.Set (ResolveContext.Options.ProbingMode)) {
1010					var prev = ec.Report.SetPrinter (TypeInferenceReportPrinter ?? new NullReportPrinter ());
1011
1012					var res = Compatible (ec, delegate_type) != null;
1013
1014					ec.Report.SetPrinter (prev);
1015
1016					return res;
1017				}
1018			}
1019		}
1020
1021		TypeSpec CompatibleChecks (ResolveContext ec, TypeSpec delegate_type)
1022		{
1023			if (delegate_type.IsDelegate)
1024				return delegate_type;
1025
1026			if (delegate_type.IsExpressionTreeType) {
1027				delegate_type = delegate_type.TypeArguments [0];
1028				if (delegate_type.IsDelegate)
1029					return delegate_type;
1030
1031				ec.Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
1032					GetSignatureForError (), delegate_type.GetSignatureForError ());
1033				return null;
1034			}
1035
1036			ec.Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
1037				      GetSignatureForError (), delegate_type.GetSignatureForError ());
1038			return null;
1039		}
1040
1041		protected bool VerifyExplicitParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type, AParametersCollection parameters)
1042		{
1043			if (VerifyParameterCompatibility (ec, tic, delegate_type, parameters, ec.IsInProbingMode))
1044				return true;
1045
1046			if (!ec.IsInProbingMode)
1047				ec.Report.Error (1661, loc,
1048					"Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1049					GetSignatureForError (), delegate_type.GetSignatureForError ());
1050
1051			return false;
1052		}
1053
1054		protected bool VerifyParameterCompatibility (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
1055		{
1056			if (Parameters.Count != invoke_pd.Count) {
1057				if (ignore_errors)
1058					return false;
1059				
1060				ec.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1061					      delegate_type.GetSignatureForError (), Parameters.Count.ToString ());
1062				return false;
1063			}
1064
1065			bool has_implicit_parameters = !HasExplicitParameters;
1066			bool error = false;
1067
1068			for (int i = 0; i < Parameters.Count; ++i) {
1069				Parameter.Modifier p_mod = invoke_pd.FixedParameters [i].ModFlags;
1070				if (Parameters.FixedParameters [i].ModFlags != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1071					if (ignore_errors)
1072						return false;
1073					
1074					if (p_mod == Parameter.Modifier.NONE)
1075						ec.Report.Error (1677, Parameters[i].Location, "Parameter `{0}' should not be declared with the `{1}' keyword",
1076							      (i + 1).ToString (), Parameter.GetModifierSignature (Parameters [i].ModFlags));
1077					else
1078						ec.Report.Error (1676, Parameters[i].Location, "Parameter `{0}' must be declared with the `{1}' keyword",
1079							      (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1080					error = true;
1081				}
1082
1083				if (has_implicit_parameters)
1084					continue;
1085
1086				TypeSpec type = invoke_pd.Types [i];
1087
1088				if (tic != null)
1089					type = tic.InflateGenericArgument (ec, type);
1090				
1091				if (!TypeSpecComparer.IsEqual (type, Parameters.Types [i])) {
1092					if (ignore_errors)
1093						return false;
1094					
1095					ec.Report.Error (1678, Parameters [i].Location, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1096						      (i+1).ToString (),
1097						      Parameters.Types [i].GetSignatureForError (),
1098						      invoke_pd.Types [i].GetSignatureForError ());
1099					error = true;
1100				}
1101			}
1102
1103			return !error;
1104		}
1105
1106		//
1107		// Infers type arguments based on explicit arguments
1108		//
1109		public bool ExplicitTypeInference (TypeInferenceContext type_inference, TypeSpec delegate_type)
1110		{
1111			if (!HasExplicitParameters)
1112				return false;
1113
1114			if (!delegate_type.IsDelegate) {
1115				if (!delegate_type.IsExpressionTreeType)
1116					return false;
1117
1118				delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
1119				if (!delegate_type.IsDelegate)
1120					return false;
1121			}
1122			
1123			AParametersCollection d_params = Delegate.GetParameters (delegate_type);
1124			if (d_params.Count != Parameters.Count)
1125				return false;
1126
1127			var ptypes = Parameters.Types;
1128			var dtypes = d_params.Types;
1129			for (int i = 0; i < Parameters.Count; ++i) {
1130				if (type_inference.ExactInference (ptypes[i], dtypes[i]) == 0) {
1131					//
1132					// Continue when 0 (quick path) does not mean inference failure. Checking for
1133					// same type handles cases like int -> int
1134					//
1135					if (ptypes[i] == dtypes[i])
1136						continue;
1137
1138					return false;
1139				}
1140			}
1141
1142			return true;
1143		}
1144
1145		public TypeSpec InferReturnType (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1146		{
1147			Expression expr;
1148			AnonymousExpression am;
1149
1150			if (compatibles.TryGetValue (delegate_type, out expr)) {
1151				am = expr as AnonymousExpression;
1152				return am == null ? null : am.ReturnType;
1153			}
1154
1155			using (ec.Set (ResolveContext.Options.ProbingMode | ResolveContext.Options.InferReturnType)) {
1156				ReportPrinter prev;
1157				if (TypeInferenceReportPrinter != null) {
1158					prev = ec.Report.SetPrinter (TypeInferenceReportPrinter);
1159				} else {
1160					prev = null;
1161				}
1162
1163				var body = CompatibleMethodBody (ec, tic, null, delegate_type);
1164				if (body != null) {
1165					am = body.Compatible (ec, body);
1166				} else {
1167					am = null;
1168				}
1169
1170				if (TypeInferenceReportPrinter != null) {
1171					ec.Report.SetPrinter (prev);
1172				}
1173			}
1174
1175			if (am == null)
1176				return null;
1177
1178//			compatibles.Add (delegate_type, am);
1179			return am.ReturnType;
1180		}
1181
1182		public override bool ContainsEmitWithAwait ()
1183		{
1184			return false;
1185		}
1186
1187		//
1188		// Returns AnonymousMethod container if this anonymous method
1189		// expression can be implicitly converted to the delegate type `delegate_type'
1190		//
1191		public Expression Compatible (ResolveContext ec, TypeSpec type)
1192		{
1193			Expression am;
1194			if (compatibles.TryGetValue (type, out am))
1195				return am;
1196
1197			TypeSpec delegate_type = CompatibleChecks (ec, type);
1198			if (delegate_type == null)
1199				return null;
1200
1201			//
1202			// At this point its the first time we know the return type that is 
1203			// needed for the anonymous method.  We create the method here.
1204			//
1205
1206			var invoke_mb = Delegate.GetInvokeMethod (delegate_type);
1207			TypeSpec return_type = invoke_mb.ReturnType;
1208
1209			//
1210			// Second: the return type of the delegate must be compatible with 
1211			// the anonymous type.   Instead of doing a pass to examine the block
1212			// we satisfy the rule by setting the return type on the EmitContext
1213			// to be the delegate type return type.
1214			//
1215
1216			var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
1217			if (body == null)
1218				return null;
1219
1220			bool etree_conversion = delegate_type != type;
1221
1222			try {
1223				if (etree_conversion) {
1224					if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1225						//
1226						// Nested expression tree lambda use same scope as parent
1227						// lambda, this also means no variable capturing between this
1228						// and parent scope
1229						//
1230						am = body.Compatible (ec, ec.CurrentAnonymousMethod);
1231
1232						//
1233						// Quote nested expression tree
1234						//
1235						if (am != null)
1236							am = new Quote (am);
1237					} else {
1238						int errors = ec.Report.Errors;
1239
1240						if (Block.IsAsync) {
1241							ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees");
1242						}
1243
1244						using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
1245							am = body.Compatible (ec);
1246						}
1247
1248						//
1249						// Rewrite expressions into expression tree when targeting Expression<T>
1250						//
1251						if (am != null && errors == ec.Report.Errors)
1252							am = CreateExpressionTree (ec, delegate_type);
1253					}
1254				} else {
1255					am = body.Compatible (ec);
1256
1257					if (body.DirectMethodGroupConversion != null) {
1258						var errors_printer = new SessionReportPrinter ();
1259						var old = ec.Report.SetPrinter (errors_printer);
1260						var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) {
1261							AllowSpecialMethodsInvocation = true
1262						}.Resolve (ec);
1263						ec.Report.SetPrinter (old);
1264						if (expr != null && errors_printer.ErrorsCount == 0)
1265							am = expr;
1266					}
1267				}
1268			} catch (CompletionResult) {
1269				throw;
1270			} catch (FatalException) {
1271				throw;
1272			} catch (Exception e) {
1273				throw new InternalErrorException (e, loc);
1274			}
1275
1276			if (!ec.IsInProbingMode && !etree_conversion) {
1277				compatibles.Add (type, am ?? EmptyExpression.Null);
1278			}
1279
1280			return am;
1281		}
1282
1283		protected virtual Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
1284		{
1285			return CreateExpressionTree (ec);
1286		}
1287
1288		public override Expression CreateExpressionTree (ResolveContext ec)
1289		{
1290			ec.Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
1291			return null;
1292		}
1293
1294		protected virtual ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1295		{
1296			var delegate_parameters = Delegate.GetParameters (delegate_type);
1297
1298			if (Parameters == ParametersCompiled.Undefined) {
1299				//
1300				// We provide a set of inaccessible parameters
1301				//
1302				Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
1303
1304				for (int i = 0; i < delegate_parameters.Count; i++) {
1305					Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags;
1306					if ((i_mod & Parameter.Modifier.OUT) != 0) {
1307						if (!ec.IsInProbingMode) {
1308							ec.Report.Error (1688, loc,
1309								"Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters",
1310								delegate_type.GetSignatureForError ());
1311						}
1312
1313						return null;
1314					}
1315					fixedpars[i] = new Parameter (
1316						new TypeExpression (delegate_parameters.Types [i], loc), null,
1317						delegate_parameters.FixedParameters [i].ModFlags, null, loc);
1318				}
1319
1320				return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1321			}
1322
1323			if (!VerifyExplicitParameters (ec, tic, delegate_type, delegate_parameters)) {
1324				return null;
1325			}
1326
1327			return Parameters;
1328		}
1329
1330		protected override Expression DoResolve (ResolveContext rc)
1331		{
1332			if (rc.HasSet (ResolveContext.Options.ConstantScope)) {
1333				rc.Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1334				return null;
1335			}
1336
1337			//
1338			// Update top-level block generated duting parsing with actual top-level block
1339			//
1340			if (rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer) && rc.CurrentMemberDefinition.Parent.PartialContainer.PrimaryConstructorParameters != null) {
1341				var tb = rc.ConstructorBlock.ParametersBlock.TopBlock;
1342				if (Block.TopBlock != tb) {
1343					Block b = Block;
1344					while (b.Parent != Block.TopBlock && b != Block.TopBlock)
1345						b = b.Parent;
1346
1347					b.Parent = tb;
1348					tb.IncludeBlock (Block, Block.TopBlock);
1349					b.ParametersBlock.TopBlock = tb;
1350				}
1351			}
1352
1353			eclass = ExprClass.Value;
1354
1355			//
1356			// This hack means `The type is not accessible
1357			// anywhere', we depend on special conversion
1358			// rules.
1359			// 
1360			type = InternalType.AnonymousMethod;
1361
1362			if (!DoResolveParameters (rc))
1363				return null;
1364
1365			return this;
1366		}
1367
1368		protected virtual bool DoResolveParameters (ResolveContext rc)
1369		{
1370			return Parameters.Resolve (rc);
1371		}
1372
1373		public override void Emit (EmitContext ec)
1374		{
1375			// nothing, as we only exist to not do anything.
1376		}
1377
1378		public static void Error_AddressOfCapturedVar (ResolveContext rc, IVariableReference var, Location loc)
1379		{
1380			if (rc.CurrentAnonymousMethod is AsyncInitializer)
1381				return;
1382
1383			rc.Report.Error (1686, loc,
1384				"Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method, lambda expression or query expression",
1385				var.Name);
1386		}
1387
1388		public override string GetSignatureForError ()
1389		{
1390			return ExprClassName;
1391		}
1392
1393		AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type)
1394		{
1395			ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
1396			if (p == null)
1397				return null;
1398
1399			ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block;
1400
1401			if (b.IsAsync) {
1402				var rt = return_type;
1403				if (rt != null && rt.Kind != MemberKind.Void && rt != ec.Module.PredefinedTypes.Task.TypeSpec && !rt.IsGenericTask) {
1404					ec.Report.Error (4010, loc, "Cannot convert async {0} to delegate type `{1}'",
1405						GetSignatureForError (), delegate_type.GetSignatureForError ());
1406
1407					return null;
1408				}
1409
1410				b = b.ConvertToAsyncTask (ec, ec.CurrentMemberDefinition.Parent.PartialContainer, p, return_type, delegate_type, loc);
1411			}
1412
1413			return CompatibleMethodFactory (return_type ?? InternalType.ErrorType, delegate_type, p, b);
1414		}
1415
1416		protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b)
1417		{
1418			return new AnonymousMethodBody (p, b, return_type, delegate_type, loc);
1419		}
1420
1421		protected override void CloneTo (CloneContext clonectx, Expression t)
1422		{
1423			AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1424
1425			target.Block = (ParametersBlock) clonectx.LookupBlock (Block);
1426		}
1427		
1428		public override object Accept (StructuralVisitor visitor)
1429		{
1430			return visitor.Visit (this);
1431		}
1432	}
1433
1434	//
1435	// Abstract expression for any block which requires variables hoisting
1436	//
1437	public abstract class AnonymousExpression : ExpressionStatement
1438	{
1439		protected class AnonymousMethodMethod : Method
1440		{
1441			public readonly AnonymousExpression AnonymousMethod;
1442			public readonly AnonymousMethodStorey Storey;
1443
1444			public AnonymousMethodMethod (TypeDefinition parent, AnonymousExpression am, AnonymousMethodStorey storey,
1445							  TypeExpr return_type,
1446							  Modifiers mod, MemberName name,
1447							  ParametersCompiled parameters)
1448				: base (parent, return_type, mod | Modifiers.COMPILER_GENERATED,
1449						name, parameters, null)
1450			{
1451				this.AnonymousMethod = am;
1452				this.Storey = storey;
1453
1454				Parent.PartialContainer.Members.Add (this);
1455				Block = new ToplevelBlock (am.block, parameters);
1456			}
1457
1458			public override EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
1459			{
1460				EmitContext ec = new EmitContext (this, ig, ReturnType, sourceMethod);
1461				ec.CurrentAnonymousMethod = AnonymousMethod;
1462				return ec;
1463			}
1464
1465			protected override void DefineTypeParameters ()
1466			{
1467				// Type parameters were cloned
1468			}
1469
1470			protected override bool ResolveMemberType ()
1471			{
1472				if (!base.ResolveMemberType ())
1473					return false;
1474
1475				if (Storey != null && Storey.Mutator != null) {
1476					if (!parameters.IsEmpty) {
1477						var mutated = Storey.Mutator.Mutate (parameters.Types);
1478						if (mutated != parameters.Types)
1479							parameters = ParametersCompiled.CreateFullyResolved ((Parameter[]) parameters.FixedParameters, mutated);
1480					}
1481
1482					member_type = Storey.Mutator.Mutate (member_type);
1483				}
1484
1485				return true;
1486			}
1487
1488			public override void Emit ()
1489			{
1490				if (MethodBuilder == null) {
1491					Define ();
1492				}
1493
1494				base.Emit ();
1495			}
1496		}
1497
1498		protected readonly ParametersBlock block;
1499
1500		public TypeSpec ReturnType;
1501
1502		protected AnonymousExpression (ParametersBlock block, TypeSpec return_type, Location loc)
1503		{
1504			this.ReturnType = return_type;
1505			this.block = block;
1506			this.loc = loc;
1507		}
1508
1509		public abstract string ContainerType { get; }
1510		public abstract bool IsIterator { get; }
1511		public abstract AnonymousMethodStorey Storey { get; }
1512
1513		//
1514		// The block that makes up the body for the anonymous method
1515		//
1516		public ParametersBlock Block {
1517			get {
1518				return block;
1519			}
1520		}
1521
1522		public AnonymousExpression Compatible (ResolveContext ec)
1523		{
1524			return Compatible (ec, this);
1525		}
1526
1527		public AnonymousExpression Compatible (ResolveContext ec, AnonymousExpression ae)
1528		{
1529			if (block.Resolved)
1530				return this;
1531
1532			// TODO: Implement clone
1533			BlockContext aec = new BlockContext (ec, block, ReturnType);
1534			aec.CurrentAnonymousMethod = ae;
1535
1536			var am = this as AnonymousMethodBody;
1537
1538			if (ec.HasSet (ResolveContext.Options.InferReturnType) && am != null) {
1539				am.ReturnTypeInference = new TypeInferenceContext ();
1540			}
1541
1542			var bc = ec as BlockContext;
1543
1544			if (bc != null) {
1545				aec.AssignmentInfoOffset = bc.AssignmentInfoOffset;
1546				aec.EnclosingLoop = bc.EnclosingLoop;
1547				aec.EnclosingLoopOrSwitch = bc.EnclosingLoopOrSwitch;
1548				aec.Switch = bc.Switch;
1549			}
1550
1551			var errors = ec.Report.Errors;
1552
1553			bool res = Block.Resolve (aec);
1554
1555			if (res && errors == ec.Report.Errors) {
1556				MarkReachable (new Reachability ());
1557
1558				if (!CheckReachableExit (ec.Report)) {
1559					return null;
1560				}
1561
1562				if (bc != null)
1563					bc.AssignmentInfoOffset = aec.AssignmentInfoOffset;
1564			}
1565
1566			if (am != null && am.ReturnTypeInference != null) {
1567				am.ReturnTypeInference.FixAllTypes (ec);
1568				ReturnType = am.ReturnTypeInference.InferredTypeArguments [0];
1569				am.ReturnTypeInference = null;
1570
1571				//
1572				// If e is synchronous the inferred return type is T
1573				// If e is asynchronous and the body of F is either an expression classified as nothing
1574				// or a statement block where no return statements have expressions, the inferred return type is Task
1575				// If e is async and has an inferred result type T, the inferred return type is Task<T>
1576				//
1577				if (block.IsAsync && ReturnType != null) {
1578					ReturnType = ReturnType.Kind == MemberKind.Void ?
1579						ec.Module.PredefinedTypes.Task.TypeSpec :
1580						ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
1581				}
1582			}
1583
1584			if (res && errors != ec.Report.Errors)
1585				return null;
1586
1587			return res ? this : null;
1588		}
1589
1590		public override bool ContainsEmitWithAwait ()
1591		{
1592			return false;
1593		}
1594
1595		bool CheckReachableExit (Report report)
1596		{
1597			if (block.HasReachableClosingBrace && ReturnType.Kind != MemberKind.Void) {
1598				// FIXME: Flow-analysis on MoveNext generated code
1599				if (!IsIterator) {
1600					report.Error (1643, StartLocation,
1601							"Not all code paths return a value in anonymous method of type `{0}'", GetSignatureForError ());
1602
1603					return false;
1604				}
1605			}
1606
1607			return true;
1608		}
1609
1610		public override void FlowAnalysis (FlowAnalysisContext fc)
1611		{
1612			// We are reachable, mark block body reachable too
1613			MarkReachable (new Reachability ());
1614
1615			CheckReachableExit (fc.Report);
1616
1617			var das = fc.BranchDefiniteAssignment ();
1618			var prev_pb = fc.ParametersBlock;
1619			fc.ParametersBlock = Block;
1620			var da_ontrue = fc.DefiniteAssignmentOnTrue;
1621			var da_onfalse = fc.DefiniteAssignmentOnFalse;
1622
1623			fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
1624			block.FlowAnalysis (fc);
1625
1626			fc.ParametersBlock = prev_pb;
1627			fc.DefiniteAssignment = das;
1628			fc.DefiniteAssignmentOnTrue = da_ontrue;
1629			fc.DefiniteAssignmentOnFalse = da_onfalse;
1630		}
1631
1632		public override void MarkReachable (Reachability rc)
1633		{
1634			block.MarkReachable (rc);
1635		}
1636
1637		public void SetHasThisAccess ()
1638		{
1639			ExplicitBlock b = block;
1640			do {
1641				if (b.HasCapturedThis)
1642					return;
1643
1644				b.HasCapturedThis = true;
1645				b = b.Parent == null ? null : b.Parent.Explicit;
1646			} while (b != null);
1647		}
1648	}
1649
1650	public class AnonymousMethodBody : AnonymousExpression
1651	{
1652		protected readonly ParametersCompiled parameters;
1653		AnonymousMethodStorey storey;
1654
1655		AnonymousMethodMethod method;
1656		Field am_cache;
1657		string block_name;
1658		TypeInferenceContext return_inference;
1659
1660		public AnonymousMethodBody (ParametersCompiled parameters,
1661					ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
1662					Location loc)
1663			: base (block, return_type, loc)
1664		{
1665			this.type = delegate_type;
1666			this.parameters = parameters;
1667		}
1668
1669		#region Properties
1670
1671		public override string ContainerType {
1672			get { return "anonymous method"; }
1673		}
1674
1675		//
1676		// Method-group instance for lambdas which can be replaced with
1677		// simple method group call
1678		//
1679		public MethodGroupExpr DirectMethodGroupConversion {
1680			get; set;
1681		}
1682
1683		public override bool IsIterator {
1684			get {
1685				return false;
1686			}
1687		}
1688
1689		public ParametersCompiled Parameters {
1690			get {
1691				return parameters;
1692			}
1693		}
1694
1695		public TypeInferenceContext ReturnTypeInference {
1696			get {
1697				return return_inference;
1698			}
1699			set {
1700				return_inference = value;
1701			}
1702		}
1703
1704		public override AnonymousMethodStorey Storey {
1705			get {
1706				return storey;
1707			}
1708		}
1709
1710		#endregion
1711
1712		public override Expression CreateExpressionTree (ResolveContext ec)
1713		{
1714			ec.Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
1715			return null;
1716		}
1717
1718		bool Define (ResolveContext ec)
1719		{
1720			if (!Block.Resolved && Compatible (ec) == null)
1721				return false;
1722
1723			if (block_name == null) {
1724				MemberCore mc = (MemberCore) ec.MemberContext;
1725				block_name = mc.MemberName.Basename;
1726			}
1727
1728			return true;
1729		}
1730
1731		//
1732		// Creates a host for the anonymous method
1733		//
1734		AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
1735		{
1736			//
1737			// Anonymous method body can be converted to
1738			//
1739			// 1, an instance method in current scope when only `this' is hoisted
1740			// 2, a static method in current scope when neither `this' nor any variable is hoisted
1741			// 3, an instance method in compiler generated storey when any hoisted variable exists
1742			//
1743
1744			Modifiers modifiers;
1745			TypeDefinition parent = null;
1746			TypeParameters hoisted_tparams = null;
1747			ParametersCompiled method_parameters = parameters;
1748
1749			var src_block = Block.Original.Explicit;
1750			if (src_block.HasCapturedVariable || src_block.HasCapturedThis) {
1751				parent = storey = FindBestMethodStorey ();
1752
1753				if (storey == null) {
1754					var top_block = src_block.ParametersBlock.TopBlock;
1755					var sm = top_block.StateMachine;
1756
1757					if (src_block.HasCapturedThis) {
1758						//
1759						// Remove hoisted 'this' request when simple instance method is
1760						// enough. No hoisted variables only 'this' and don't need to
1761						// propagate this to value type state machine.
1762	

Large files files are truncated, but you can click here to view the full file