2 // anonymous.cs: Support for anonymous methods and types
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003-2008 Novell, Inc.
13 using System.Collections.Generic;
16 using IKVM.Reflection;
17 using IKVM.Reflection.Emit;
19 using System.Reflection;
20 using System.Reflection.Emit;
23 namespace Mono.CSharp {
25 public abstract class CompilerGeneratedClass : Class
27 protected CompilerGeneratedClass (TypeContainer parent, MemberName name, Modifiers mod)
28 : base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED, null)
32 protected void CheckMembersDefined ()
34 if (HasMembersDefined)
35 throw new InternalErrorException ("Helper class already defined!");
38 protected static MemberName MakeMemberName (MemberBase host, string name, int unique_id, TypeParameter[] tparams, Location loc)
40 string host_name = host == null ? null : host.Name;
41 string tname = MakeName (host_name, "c", name, unique_id);
42 TypeArguments args = null;
43 if (tparams != null) {
44 args = new TypeArguments ();
45 foreach (TypeParameter tparam in tparams)
46 args.Add (new TypeParameterName (tparam.Name, null, loc));
49 return new MemberName (tname, args, loc);
52 public static string MakeName (string host, string typePrefix, string name, int id)
54 return "<" + host + ">" + typePrefix + "__" + name + id.ToString ("X");
58 public class HoistedStoreyClass : CompilerGeneratedClass
60 public sealed class HoistedField : Field
62 public HoistedField (HoistedStoreyClass parent, FullNamedExpression type, Modifiers mod, string name,
63 Attributes attrs, Location loc)
64 : base (parent, type, mod, new MemberName (name, loc), attrs)
68 protected override bool ResolveMemberType ()
70 if (!base.ResolveMemberType ())
73 HoistedStoreyClass parent = ((HoistedStoreyClass) Parent).GetGenericStorey ();
74 if (parent != null && parent.Mutator != null)
75 member_type = parent.Mutator.Mutate (MemberType);
81 protected TypeParameterMutator mutator;
83 public HoistedStoreyClass (TypeContainer parent, MemberName name, TypeParameter[] tparams, Modifiers mod)
84 : base (parent, name, mod | Modifiers.PRIVATE)
86 if (tparams != null) {
87 type_params = new TypeParameter[tparams.Length];
88 var src = new TypeParameterSpec[tparams.Length];
89 var dst = new TypeParameterSpec[tparams.Length];
91 for (int i = 0; i < type_params.Length; ++i) {
92 type_params[i] = tparams[i].CreateHoistedCopy (this, spec);
94 src[i] = tparams[i].Type;
95 dst[i] = type_params[i].Type;
98 // A copy is not enough, inflate any type parameter constraints
99 // using a new type parameters
100 var inflator = new TypeParameterInflator (this, null, src, dst);
101 for (int i = 0; i < type_params.Length; ++i) {
102 src[i].InflateConstraints (inflator, dst[i]);
105 mutator = new TypeParameterMutator (tparams, type_params);
111 public TypeParameterMutator Mutator {
122 public HoistedStoreyClass GetGenericStorey ()
124 DeclSpace storey = this;
125 while (storey != null && storey.CurrentTypeParameters == null)
126 storey = storey.Parent;
128 return storey as HoistedStoreyClass;
134 // Anonymous method storey is created when an anonymous method uses
135 // variable or parameter from outer scope. They are then hoisted to
136 // anonymous method storey (captured)
138 public class AnonymousMethodStorey : HoistedStoreyClass
140 struct StoreyFieldPair
142 public readonly AnonymousMethodStorey Storey;
143 public readonly Field Field;
145 public StoreyFieldPair (AnonymousMethodStorey storey, Field field)
147 this.Storey = storey;
153 // Needed to delay hoisted _this_ initialization. When an anonymous
154 // method is used inside ctor and _this_ is hoisted, base ctor has to
155 // be called first, otherwise _this_ will be initialized with
156 // uninitialized value.
158 sealed class ThisInitializer : Statement
160 readonly HoistedThis hoisted_this;
162 public ThisInitializer (HoistedThis hoisted_this)
164 this.hoisted_this = hoisted_this;
167 protected override void DoEmit (EmitContext ec)
169 hoisted_this.EmitHoistingAssignment (ec);
172 protected override void CloneTo (CloneContext clonectx, Statement target)
179 public readonly int ID;
180 static int unique_id;
182 public readonly Block OriginalSourceBlock;
184 // A list of StoreyFieldPair with local field keeping parent storey instance
185 List<StoreyFieldPair> used_parent_storeys;
186 List<ExplicitBlock> children_references;
188 // A list of hoisted parameters
189 protected List<HoistedParameter> hoisted_params;
190 protected List<HoistedVariable> hoisted_locals;
193 protected HoistedThis hoisted_this;
195 // Local variable which holds this storey instance
196 public LocalTemporary Instance;
198 public AnonymousMethodStorey (Block block, TypeContainer parent, MemberBase host, TypeParameter[] tparams, string name)
199 : base (parent, MakeMemberName (host, name, unique_id, tparams, block.StartLocation),
200 tparams, Modifiers.SEALED)
202 OriginalSourceBlock = block;
206 public void AddCapturedThisField (EmitContext ec)
208 TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location);
209 Field f = AddCompilerGeneratedField ("<>f__this", type_expr);
211 hoisted_this = new HoistedThis (this, f);
213 // Inflated type instance has to be updated manually
214 if (Instance.Type is InflatedTypeSpec) {
215 var inflator = new TypeParameterInflator (this, Instance.Type, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
216 Instance.Type.MemberCache.AddMember (f.Spec.InflateMember (inflator));
218 inflator = new TypeParameterInflator (this, f.Parent.CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
219 f.Parent.CurrentType.MemberCache.AddMember (f.Spec.InflateMember (inflator));
223 public Field AddCapturedVariable (string name, TypeSpec type)
225 CheckMembersDefined ();
227 FullNamedExpression field_type = new TypeExpression (type, Location);
229 return AddCompilerGeneratedField (name, field_type);
231 const Modifiers mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
232 Field f = new HoistedField (this, field_type, mod, name, null, Location);
237 protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
239 const Modifiers mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
240 Field f = new Field (this, type, mod, new MemberName (name, Location), null);
246 // Creates a link between hoisted variable block and the anonymous method storey
248 // An anonymous method can reference variables from any outer block, but they are
249 // hoisted in their own ExplicitBlock. When more than one block is referenced we
250 // need to create another link between those variable storeys
252 public void AddReferenceFromChildrenBlock (ExplicitBlock block)
254 if (children_references == null)
255 children_references = new List<ExplicitBlock> ();
257 if (!children_references.Contains (block))
258 children_references.Add (block);
261 public void AddParentStoreyReference (EmitContext ec, AnonymousMethodStorey storey)
263 CheckMembersDefined ();
265 if (used_parent_storeys == null)
266 used_parent_storeys = new List<StoreyFieldPair> ();
267 else if (used_parent_storeys.Exists (i => i.Storey == storey))
270 TypeExpr type_expr = storey.CreateStoreyTypeExpression (ec);
271 Field f = AddCompilerGeneratedField ("<>f__ref$" + storey.ID, type_expr);
272 used_parent_storeys.Add (new StoreyFieldPair (storey, f));
275 public void CaptureLocalVariable (ResolveContext ec, LocalVariable local_info)
277 ec.CurrentBlock.Explicit.HasCapturedVariable = true;
278 if (ec.CurrentBlock.Explicit != local_info.Block.Explicit)
279 AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
281 if (local_info.HoistedVariant != null)
284 HoistedVariable var = new HoistedLocalVariable (this, local_info, GetVariableMangledName (local_info));
285 local_info.HoistedVariant = var;
287 if (hoisted_locals == null)
288 hoisted_locals = new List<HoistedVariable> ();
290 hoisted_locals.Add (var);
293 public void CaptureParameter (ResolveContext ec, ParameterReference param_ref)
295 ec.CurrentBlock.Explicit.HasCapturedVariable = true;
296 AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
298 if (param_ref.GetHoistedVariable (ec) != null)
301 if (hoisted_params == null)
302 hoisted_params = new List<HoistedParameter> (2);
304 var expr = new HoistedParameter (this, param_ref);
305 param_ref.Parameter.HoistedVariant = expr;
306 hoisted_params.Add (expr);
309 TypeExpr CreateStoreyTypeExpression (EmitContext ec)
312 // Create an instance of storey type
314 TypeExpr storey_type_expr;
315 if (CurrentTypeParameters != null) {
317 // Use current method type parameter (MVAR) for top level storey only. All
318 // nested storeys use class type parameter (VAR)
320 TypeParameter[] tparams = ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null ?
321 ec.CurrentAnonymousMethod.Storey.TypeParameters :
322 ec.CurrentTypeParameters;
324 TypeArguments targs = new TypeArguments ();
327 // Use type parameter name instead of resolved type parameter
328 // specification to resolve to correctly nested type parameters
330 for (int i = 0; i < tparams.Length; ++i)
331 targs.Add (new SimpleName (tparams [i].Name, Location)); // new TypeParameterExpr (tparams[i], Location));
333 storey_type_expr = new GenericTypeExpr (Definition, targs, Location);
335 storey_type_expr = new TypeExpression (CurrentType, Location);
338 return storey_type_expr;
341 public void SetNestedStoryParent (AnonymousMethodStorey parentStorey)
343 Parent = parentStorey;
345 spec.IsGeneric = false;
346 spec.DeclaringType = parentStorey.CurrentType;
347 MemberName.TypeArguments = null;
350 protected override bool DoResolveTypeParameters ()
352 // Although any storey can have type parameters they are all clones of method type
353 // parameters therefore have to mutate MVAR references in any of cloned constraints
354 if (type_params != null) {
355 for (int i = 0; i < type_params.Length; ++i) {
356 var spec = type_params[i].Type;
357 spec.BaseType = mutator.Mutate (spec.BaseType);
358 if (spec.InterfacesDefined != null) {
359 var mutated = new TypeSpec[spec.InterfacesDefined.Length];
360 for (int ii = 0; ii < mutated.Length; ++ii) {
361 mutated[ii] = mutator.Mutate (spec.InterfacesDefined[ii]);
364 spec.InterfacesDefined = mutated;
367 if (spec.TypeArguments != null) {
368 spec.TypeArguments = mutator.Mutate (spec.TypeArguments);
374 // Update parent cache as we most likely passed the point
375 // where the cache was constructed
377 Parent.CurrentType.MemberCache.AddMember (this.spec);
383 // Initializes all hoisted variables
385 public void EmitStoreyInstantiation (EmitContext ec, ExplicitBlock block)
387 // There can be only one instance variable for each storey type
388 if (Instance != null)
389 throw new InternalErrorException ();
391 SymbolWriter.OpenCompilerGeneratedBlock (ec);
394 // Create an instance of a storey
396 var storey_type_expr = CreateStoreyTypeExpression (ec);
398 ResolveContext rc = new ResolveContext (ec.MemberContext);
399 rc.CurrentBlock = block;
400 Expression e = new New (storey_type_expr, null, Location).Resolve (rc);
403 Instance = new LocalTemporary (storey_type_expr.Type);
406 EmitHoistedFieldsInitialization (rc, ec);
408 SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
409 SymbolWriter.CloseCompilerGeneratedBlock (ec);
412 void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec)
415 // Initialize all storey reference fields by using local or hoisted variables
417 if (used_parent_storeys != null) {
418 foreach (StoreyFieldPair sf in used_parent_storeys) {
420 // Get instance expression of storey field
422 Expression instace_expr = GetStoreyInstanceExpression (ec);
423 var fs = sf.Field.Spec;
424 if (TypeManager.IsGenericType (instace_expr.Type))
425 fs = MemberCache.GetMember (instace_expr.Type, fs);
427 FieldExpr f_set_expr = new FieldExpr (fs, Location);
428 f_set_expr.InstanceExpression = instace_expr;
430 SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec));
431 if (a.Resolve (rc) != null)
432 a.EmitStatement (ec);
437 // Define hoisted `this' in top-level storey only
439 if (OriginalSourceBlock.Explicit.HasCapturedThis && !(Parent is AnonymousMethodStorey)) {
440 AddCapturedThisField (ec);
441 rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this));
445 // Setting currect anonymous method to null blocks any further variable hoisting
447 AnonymousExpression ae = ec.CurrentAnonymousMethod;
448 ec.CurrentAnonymousMethod = null;
450 if (hoisted_params != null) {
451 EmitHoistedParameters (ec, hoisted_params);
454 ec.CurrentAnonymousMethod = ae;
457 protected virtual void EmitHoistedParameters (EmitContext ec, IList<HoistedParameter> hoisted)
459 foreach (HoistedParameter hp in hoisted) {
460 hp.EmitHoistingAssignment (ec);
464 public override void EmitType ()
466 SymbolWriter.DefineAnonymousScope (ID);
468 if (hoisted_this != null)
469 hoisted_this.EmitSymbolInfo ();
471 if (hoisted_locals != null) {
472 foreach (HoistedVariable local in hoisted_locals)
473 local.EmitSymbolInfo ();
476 if (hoisted_params != null) {
477 foreach (HoistedParameter param in hoisted_params)
478 param.EmitSymbolInfo ();
481 if (used_parent_storeys != null) {
482 foreach (StoreyFieldPair sf in used_parent_storeys) {
483 SymbolWriter.DefineCapturedScope (ID, sf.Storey.ID, sf.Field.Name);
491 // Returns a field which holds referenced storey instance
493 Field GetReferencedStoreyField (AnonymousMethodStorey storey)
495 if (used_parent_storeys == null)
498 foreach (StoreyFieldPair sf in used_parent_storeys) {
499 if (sf.Storey == storey)
507 // Creates storey instance expression regardless of currect IP
509 public Expression GetStoreyInstanceExpression (EmitContext ec)
511 AnonymousExpression am = ec.CurrentAnonymousMethod;
514 // Access from original block -> storey
520 // Access from anonymous method implemented as a static -> storey
522 if (am.Storey == null)
525 Field f = am.Storey.GetReferencedStoreyField (this);
527 if (am.Storey == this) {
529 // Access inside of same storey (S -> S)
531 return new CompilerGeneratedThis (CurrentType, Location);
534 // External field access
540 // Storey was cached to local field
542 FieldExpr f_ind = new FieldExpr (f, Location);
543 f_ind.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
547 protected virtual string GetVariableMangledName (LocalVariable local_info)
550 // No need to mangle anonymous method hoisted variables cause they
551 // are hoisted in their own scopes
553 return local_info.Name;
556 public HoistedThis HoistedThis {
557 get { return hoisted_this; }
560 public IList<ExplicitBlock> ReferencesFromChildrenBlock {
561 get { return children_references; }
564 public static void Reset ()
570 public abstract class HoistedVariable
573 // Hoisted version of variable references used in expression
574 // tree has to be delayed until we know its location. The variable
575 // doesn't know its location until all stories are calculated
577 class ExpressionTreeVariableReference : Expression
579 readonly HoistedVariable hv;
581 public ExpressionTreeVariableReference (HoistedVariable hv)
586 public override Expression CreateExpressionTree (ResolveContext ec)
588 return hv.CreateExpressionTree ();
591 protected override Expression DoResolve (ResolveContext ec)
593 eclass = ExprClass.Value;
594 type = ec.Module.PredefinedTypes.Expression.Resolve ();
598 public override void Emit (EmitContext ec)
600 ResolveContext rc = new ResolveContext (ec.MemberContext);
601 Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (rc);
602 // This should never fail
609 protected readonly AnonymousMethodStorey storey;
610 protected Field field;
611 Dictionary<AnonymousExpression, FieldExpr> cached_inner_access; // TODO: Hashtable is too heavyweight
612 FieldExpr cached_outer_access;
614 protected HoistedVariable (AnonymousMethodStorey storey, string name, TypeSpec type)
615 : this (storey, storey.AddCapturedVariable (name, type))
619 protected HoistedVariable (AnonymousMethodStorey storey, Field field)
621 this.storey = storey;
625 public void AddressOf (EmitContext ec, AddressOp mode)
627 GetFieldExpression (ec).AddressOf (ec, mode);
630 public Expression CreateExpressionTree ()
632 return new ExpressionTreeVariableReference (this);
635 public void Emit (EmitContext ec)
637 GetFieldExpression (ec).Emit (ec);
641 // Creates field access expression for hoisted variable
643 protected virtual FieldExpr GetFieldExpression (EmitContext ec)
645 if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) {
646 if (cached_outer_access != null)
647 return cached_outer_access;
650 // When setting top-level hoisted variable in generic storey
651 // change storey generic types to method generic types (VAR -> MVAR)
653 if (storey.Instance.Type.IsGenericOrParentIsGeneric) {
654 var fs = MemberCache.GetMember (storey.Instance.Type, field.Spec);
655 cached_outer_access = new FieldExpr (fs, field.Location);
657 cached_outer_access = new FieldExpr (field, field.Location);
660 cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
661 return cached_outer_access;
664 FieldExpr inner_access;
665 if (cached_inner_access != null) {
666 if (!cached_inner_access.TryGetValue (ec.CurrentAnonymousMethod, out inner_access))
670 cached_inner_access = new Dictionary<AnonymousExpression, FieldExpr> (4);
673 if (inner_access == null) {
674 if (field.Parent.IsGeneric) {
675 var fs = MemberCache.GetMember (field.Parent.CurrentType, field.Spec);
676 inner_access = new FieldExpr (fs, field.Location);
678 inner_access = new FieldExpr (field, field.Location);
681 inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
682 cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access);
688 public abstract void EmitSymbolInfo ();
690 public void Emit (EmitContext ec, bool leave_copy)
692 GetFieldExpression (ec).Emit (ec, leave_copy);
695 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
697 GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
701 public class HoistedParameter : HoistedVariable
703 sealed class HoistedFieldAssign : Assign
705 public HoistedFieldAssign (Expression target, Expression source)
706 : base (target, source, source.Location)
710 protected override Expression ResolveConversions (ResolveContext ec)
713 // Implicit conversion check fails for hoisted type arguments
714 // as they are of different types (!!0 x !0)
720 readonly ParameterReference parameter;
722 public HoistedParameter (AnonymousMethodStorey scope, ParameterReference par)
723 : base (scope, par.Name, par.Type)
725 this.parameter = par;
728 public HoistedParameter (HoistedParameter hp, string name)
729 : base (hp.storey, name, hp.parameter.Type)
731 this.parameter = hp.parameter;
734 public void EmitHoistingAssignment (EmitContext ec)
737 // Remove hoisted redirection to emit assignment from original parameter
739 HoistedVariable temp = parameter.Parameter.HoistedVariant;
740 parameter.Parameter.HoistedVariant = null;
742 Assign a = new HoistedFieldAssign (GetFieldExpression (ec), parameter);
743 if (a.Resolve (new ResolveContext (ec.MemberContext)) != null)
744 a.EmitStatement (ec);
746 parameter.Parameter.HoistedVariant = temp;
749 public override void EmitSymbolInfo ()
751 SymbolWriter.DefineCapturedParameter (storey.ID, field.Name, field.Name);
755 get { return field; }
759 class HoistedLocalVariable : HoistedVariable
761 readonly string name;
763 public HoistedLocalVariable (AnonymousMethodStorey scope, LocalVariable local, string name)
764 : base (scope, name, local.Type)
766 this.name = local.Name;
769 public override void EmitSymbolInfo ()
771 SymbolWriter.DefineCapturedLocal (storey.ID, name, field.Name);
775 public class HoistedThis : HoistedVariable
777 public HoistedThis (AnonymousMethodStorey storey, Field field)
778 : base (storey, field)
782 public void EmitHoistingAssignment (EmitContext ec)
784 SimpleAssign a = new SimpleAssign (GetFieldExpression (ec), new CompilerGeneratedThis (ec.CurrentType, field.Location));
785 if (a.Resolve (new ResolveContext (ec.MemberContext)) != null)
786 a.EmitStatement (ec);
789 public override void EmitSymbolInfo ()
791 SymbolWriter.DefineCapturedThis (storey.ID, field.Name);
795 get { return field; }
800 // Anonymous method expression as created by parser
802 public class AnonymousMethodExpression : Expression
805 // Special conversion for nested expression tree lambdas
807 class Quote : ShimExpression
809 public Quote (Expression expr)
814 public override Expression CreateExpressionTree (ResolveContext ec)
816 var args = new Arguments (1);
817 args.Add (new Argument (expr.CreateExpressionTree (ec)));
818 return CreateExpressionFactoryCall (ec, "Quote", args);
821 protected override Expression DoResolve (ResolveContext rc)
823 expr = expr.Resolve (rc);
827 eclass = expr.eclass;
833 readonly Dictionary<TypeSpec, Expression> compatibles;
834 readonly bool is_async;
836 public ParametersBlock Block;
838 public AnonymousMethodExpression (bool isAsync, Location loc)
840 this.is_async = isAsync;
842 this.compatibles = new Dictionary<TypeSpec, Expression> ();
847 public override string ExprClassName {
849 return "anonymous method";
853 public virtual bool HasExplicitParameters {
855 return Parameters != ParametersCompiled.Undefined;
859 public bool IsAsync {
865 public ParametersCompiled Parameters {
867 return Block.Parameters;
874 // Returns true if the body of lambda expression can be implicitly
875 // converted to the delegate of type `delegate_type'
877 public bool ImplicitStandardConversionExists (ResolveContext ec, TypeSpec delegate_type)
879 using (ec.With (ResolveContext.Options.InferReturnType, false)) {
880 using (ec.Set (ResolveContext.Options.ProbingMode)) {
881 return Compatible (ec, delegate_type) != null;
886 TypeSpec CompatibleChecks (ResolveContext ec, TypeSpec delegate_type)
888 if (delegate_type.IsDelegate)
889 return delegate_type;
891 if (delegate_type.IsExpressionTreeType) {
892 delegate_type = delegate_type.TypeArguments [0];
893 if (delegate_type.IsDelegate)
894 return delegate_type;
896 ec.Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
897 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
901 ec.Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
902 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
906 protected bool VerifyExplicitParameters (ResolveContext ec, TypeSpec delegate_type, AParametersCollection parameters)
908 if (VerifyParameterCompatibility (ec, delegate_type, parameters, ec.IsInProbingMode))
911 if (!ec.IsInProbingMode)
912 ec.Report.Error (1661, loc,
913 "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
914 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
919 protected bool VerifyParameterCompatibility (ResolveContext ec, TypeSpec delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
921 if (Parameters.Count != invoke_pd.Count) {
925 ec.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
926 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
930 bool has_implicit_parameters = !HasExplicitParameters;
933 for (int i = 0; i < Parameters.Count; ++i) {
934 Parameter.Modifier p_mod = invoke_pd.FixedParameters [i].ModFlags;
935 if (Parameters.FixedParameters [i].ModFlags != p_mod && p_mod != Parameter.Modifier.PARAMS) {
939 if (p_mod == Parameter.Modifier.NONE)
940 ec.Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
941 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.FixedParameters [i].ModFlags));
943 ec.Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
944 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
948 if (has_implicit_parameters)
951 TypeSpec type = invoke_pd.Types [i];
953 // We assume that generic parameters are always inflated
954 if (TypeManager.IsGenericParameter (type))
957 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
960 if (!TypeSpecComparer.IsEqual (invoke_pd.Types [i], Parameters.Types [i])) {
964 ec.Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
966 TypeManager.CSharpName (Parameters.Types [i]),
967 TypeManager.CSharpName (invoke_pd.Types [i]));
976 // Infers type arguments based on explicit arguments
978 public bool ExplicitTypeInference (ResolveContext ec, TypeInferenceContext type_inference, TypeSpec delegate_type)
980 if (!HasExplicitParameters)
983 if (!delegate_type.IsDelegate) {
984 if (!delegate_type.IsExpressionTreeType)
987 delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
988 if (!delegate_type.IsDelegate)
992 AParametersCollection d_params = Delegate.GetParameters (delegate_type);
993 if (d_params.Count != Parameters.Count)
996 for (int i = 0; i < Parameters.Count; ++i) {
997 TypeSpec itype = d_params.Types [i];
998 if (!TypeManager.IsGenericParameter (itype)) {
999 if (!TypeManager.HasElementType (itype))
1002 if (!TypeManager.IsGenericParameter (TypeManager.GetElementType (itype)))
1005 type_inference.ExactInference (Parameters.Types [i], itype);
1010 public TypeSpec InferReturnType (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1013 AnonymousExpression am;
1015 if (compatibles.TryGetValue (delegate_type, out expr)) {
1016 am = expr as AnonymousExpression;
1017 return am == null ? null : am.ReturnType;
1020 using (ec.Set (ResolveContext.Options.ProbingMode | ResolveContext.Options.InferReturnType)) {
1021 var body = CompatibleMethodBody (ec, tic, InternalType.Arglist, delegate_type);
1024 AsyncInitializer.Create (body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, null, loc);
1027 am = body.Compatible (ec, body, is_async);
1036 // compatibles.Add (delegate_type, am);
1037 return am.ReturnType;
1041 // Returns AnonymousMethod container if this anonymous method
1042 // expression can be implicitly converted to the delegate type `delegate_type'
1044 public Expression Compatible (ResolveContext ec, TypeSpec type)
1047 if (compatibles.TryGetValue (type, out am))
1050 TypeSpec delegate_type = CompatibleChecks (ec, type);
1051 if (delegate_type == null)
1055 // At this point its the first time we know the return type that is
1056 // needed for the anonymous method. We create the method here.
1059 var invoke_mb = Delegate.GetInvokeMethod (delegate_type);
1060 TypeSpec return_type = invoke_mb.ReturnType;
1063 // Second: the return type of the delegate must be compatible with
1064 // the anonymous type. Instead of doing a pass to examine the block
1065 // we satisfy the rule by setting the return type on the EmitContext
1066 // to be the delegate type return type.
1069 var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
1073 bool etree_conversion = delegate_type != type;
1076 if (etree_conversion) {
1077 if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1079 // Nested expression tree lambda use same scope as parent
1080 // lambda, this also means no variable capturing between this
1083 am = body.Compatible (ec, ec.CurrentAnonymousMethod, is_async);
1086 // Quote nested expression tree
1089 am = new Quote (am);
1091 int errors = ec.Report.Errors;
1093 using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
1094 am = body.Compatible (ec);
1098 // Rewrite expressions into expression tree when targeting Expression<T>
1100 if (am != null && errors == ec.Report.Errors)
1101 am = CreateExpressionTree (ec, delegate_type);
1105 AsyncInitializer.Create (body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, body.ReturnType, loc);
1108 am = body.Compatible (ec);
1110 } catch (CompletionResult) {
1112 } catch (Exception e) {
1113 throw new InternalErrorException (e, loc);
1116 if (!ec.IsInProbingMode) {
1117 compatibles.Add (type, am ?? EmptyExpression.Null);
1123 protected virtual Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
1125 return CreateExpressionTree (ec);
1128 public override Expression CreateExpressionTree (ResolveContext ec)
1130 ec.Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
1134 protected virtual ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1136 var delegate_parameters = Delegate.GetParameters (delegate_type);
1138 if (Parameters == ParametersCompiled.Undefined) {
1140 // We provide a set of inaccessible parameters
1142 Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
1144 for (int i = 0; i < delegate_parameters.Count; i++) {
1145 Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags;
1146 if (i_mod == Parameter.Modifier.OUT) {
1147 if (!ec.IsInProbingMode) {
1148 ec.Report.Error (1688, loc,
1149 "Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters",
1150 delegate_type.GetSignatureForError ());
1155 fixedpars[i] = new Parameter (
1156 new TypeExpression (delegate_parameters.Types [i], loc), null,
1157 delegate_parameters.FixedParameters [i].ModFlags, null, loc);
1160 return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1163 if (!VerifyExplicitParameters (ec, delegate_type, delegate_parameters)) {
1170 protected override Expression DoResolve (ResolveContext ec)
1172 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
1173 ec.Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1178 // Set class type, set type
1181 eclass = ExprClass.Value;
1184 // This hack means `The type is not accessible
1185 // anywhere', we depend on special conversion
1188 type = InternalType.AnonymousMethod;
1190 if (!DoResolveParameters (ec))
1193 // FIXME: The emitted code isn't very careful about reachability
1194 // so, ensure we have a 'ret' at the end
1195 BlockContext bc = ec as BlockContext;
1196 if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
1197 bc.NeedReturnLabel ();
1202 protected virtual bool DoResolveParameters (ResolveContext rc)
1204 return Parameters.Resolve (rc);
1207 public override void Emit (EmitContext ec)
1209 // nothing, as we only exist to not do anything.
1212 public static void Error_AddressOfCapturedVar (ResolveContext ec, IVariableReference var, Location loc)
1214 ec.Report.Error (1686, loc,
1215 "Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method, lambda expression or query expression",
1219 public override string GetSignatureForError ()
1221 return ExprClassName;
1224 AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type)
1226 ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
1230 ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block;
1232 return CompatibleMethodFactory (return_type, delegate_type, p, b);
1235 protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b)
1237 return new AnonymousMethodBody (p, b, return_type, delegate_type, loc);
1240 protected override void CloneTo (CloneContext clonectx, Expression t)
1242 AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1244 target.Block = (ParametersBlock) clonectx.LookupBlock (Block);
1249 // Abstract expression for any block which requires variables hoisting
1251 public abstract class AnonymousExpression : ExpressionStatement
1253 protected class AnonymousMethodMethod : Method
1255 public readonly AnonymousExpression AnonymousMethod;
1256 public readonly AnonymousMethodStorey Storey;
1257 readonly string RealName;
1259 public AnonymousMethodMethod (DeclSpace parent, AnonymousExpression am, AnonymousMethodStorey storey,
1260 GenericMethod generic, TypeExpr return_type,
1261 Modifiers mod, string real_name, MemberName name,
1262 ParametersCompiled parameters)
1263 : base (parent, generic, return_type, mod | Modifiers.COMPILER_GENERATED,
1264 name, parameters, null)
1266 this.AnonymousMethod = am;
1267 this.Storey = storey;
1268 this.RealName = real_name;
1270 Parent.PartialContainer.AddMethod (this);
1271 Block = new ToplevelBlock (am.block, parameters);
1274 public override EmitContext CreateEmitContext (ILGenerator ig)
1276 EmitContext ec = new EmitContext (this, ig, ReturnType);
1277 ec.CurrentAnonymousMethod = AnonymousMethod;
1278 if (AnonymousMethod.return_label != null) {
1279 ec.HasReturnLabel = true;
1280 ec.ReturnLabel = (Label) AnonymousMethod.return_label;
1286 protected override void DefineTypeParameters ()
1288 // Type parameters were cloned
1291 protected override bool ResolveMemberType ()
1293 if (!base.ResolveMemberType ())
1296 if (Storey != null && Storey.Mutator != null) {
1297 if (!parameters.IsEmpty) {
1298 var mutated = Storey.Mutator.Mutate (parameters.Types);
1299 if (mutated != parameters.Types)
1300 parameters = ParametersCompiled.CreateFullyResolved ((Parameter[]) parameters.FixedParameters, mutated);
1303 member_type = Storey.Mutator.Mutate (member_type);
1309 public override void Emit ()
1311 if (MethodBuilder == null) {
1318 public override void EmitExtraSymbolInfo (SourceMethod source)
1320 source.SetRealMethodName (RealName);
1324 protected ParametersBlock block;
1326 public TypeSpec ReturnType;
1328 object return_label;
1330 protected AnonymousExpression (ParametersBlock block, TypeSpec return_type, Location loc)
1332 this.ReturnType = return_type;
1337 public abstract string ContainerType { get; }
1338 public abstract bool IsIterator { get; }
1339 public abstract AnonymousMethodStorey Storey { get; }
1341 public AnonymousExpression Compatible (ResolveContext ec)
1343 return Compatible (ec, this, false);
1346 public AnonymousExpression Compatible (ResolveContext ec, AnonymousExpression ae, bool isAsync)
1351 // TODO: Implement clone
1352 BlockContext aec = new BlockContext (ec, block, ReturnType);
1353 aec.CurrentAnonymousMethod = ae;
1355 ResolveContext.Options flags = 0;
1357 var am = this as AnonymousMethodBody;
1359 if (ec.HasSet (ResolveContext.Options.InferReturnType) && am != null) {
1360 am.ReturnTypeInference = new TypeInferenceContext ();
1363 if (ec.IsInProbingMode)
1364 flags |= ResolveContext.Options.ProbingMode;
1366 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
1367 flags |= ResolveContext.Options.FieldInitializerScope;
1369 if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion))
1370 flags |= ResolveContext.Options.ExpressionTreeConversion;
1374 var errors = ec.Report.Errors;
1376 bool res = Block.Resolve (ec.CurrentBranching, aec, null);
1378 if (aec.HasReturnLabel)
1379 return_label = aec.ReturnLabel;
1381 if (am != null && am.ReturnTypeInference != null) {
1382 am.ReturnTypeInference.FixAllTypes (ec);
1383 ReturnType = am.ReturnTypeInference.InferredTypeArguments [0];
1384 am.ReturnTypeInference = null;
1387 // If e is synchronous the inferred return type is T
1388 // If e is asynchronous the inferred return type is Task<T>
1390 if (isAsync && ReturnType != null) {
1391 ReturnType = ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
1395 if (res && errors != ec.Report.Errors)
1398 return res ? this : null;
1401 public void SetHasThisAccess ()
1403 ExplicitBlock b = block;
1405 if (b.HasCapturedThis)
1408 b.HasCapturedThis = true;
1409 b = b.Parent == null ? null : b.Parent.Explicit;
1410 } while (b != null);
1414 // The block that makes up the body for the anonymous method
1416 public ParametersBlock Block {
1424 public class AnonymousMethodBody : AnonymousExpression
1426 protected readonly ParametersCompiled parameters;
1427 AnonymousMethodStorey storey;
1429 AnonymousMethodMethod method;
1432 TypeInferenceContext return_inference;
1434 static int unique_id;
1436 public AnonymousMethodBody (ParametersCompiled parameters,
1437 ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
1439 : base (block, return_type, loc)
1441 this.type = delegate_type;
1442 this.parameters = parameters;
1447 public override string ContainerType {
1448 get { return "anonymous method"; }
1451 public override bool IsIterator {
1457 public ParametersCompiled Parameters {
1463 public TypeInferenceContext ReturnTypeInference {
1465 return return_inference;
1468 return_inference = value;
1472 public override AnonymousMethodStorey Storey {
1473 get { return storey; }
1478 public override Expression CreateExpressionTree (ResolveContext ec)
1480 ec.Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
1484 bool Define (ResolveContext ec)
1486 if (!Block.Resolved && Compatible (ec) == null)
1489 if (block_name == null) {
1490 MemberCore mc = (MemberCore) ec.MemberContext;
1491 block_name = mc.MemberName.Basename;
1498 // Creates a host for the anonymous method
1500 AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
1503 // Anonymous method body can be converted to
1505 // 1, an instance method in current scope when only `this' is hoisted
1506 // 2, a static method in current scope when neither `this' nor any variable is hoisted
1507 // 3, an instance method in compiler generated storey when any hoisted variable exists
1510 Modifiers modifiers;
1511 if (Block.HasCapturedVariable || Block.HasCapturedThis) {
1512 storey = FindBestMethodStorey ();
1513 modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
1515 if (ec.CurrentAnonymousMethod != null)
1516 storey = ec.CurrentAnonymousMethod.Storey;
1518 modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
1521 TypeContainer parent = storey != null ? storey : ec.CurrentTypeDefinition.Parent.PartialContainer;
1523 MemberCore mc = ec.MemberContext as MemberCore;
1524 string name = CompilerGeneratedClass.MakeName (parent != storey ? block_name : null,
1525 "m", null, unique_id++);
1527 MemberName member_name;
1528 GenericMethod generic_method;
1529 if (storey == null && mc.MemberName.TypeArguments != null) {
1530 member_name = new MemberName (name, mc.MemberName.TypeArguments.Clone (), Location);
1532 var hoisted_tparams = ec.CurrentTypeParameters;
1533 var type_params = new TypeParameter[hoisted_tparams.Length];
1534 for (int i = 0; i < type_params.Length; ++i) {
1535 type_params[i] = hoisted_tparams[i].CreateHoistedCopy (parent, null);
1538 generic_method = new GenericMethod (parent.NamespaceEntry, parent, member_name, type_params,
1539 new TypeExpression (ReturnType, Location), parameters);
1541 member_name = new MemberName (name, Location);
1542 generic_method = null;
1545 string real_name = String.Format (
1546 "{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (),
1547 parameters.GetSignatureForError ());
1549 return new AnonymousMethodMethod (parent,
1550 this, storey, generic_method, new TypeExpression (ReturnType, Location), modifiers,
1551 real_name, member_name, parameters);
1554 protected override Expression DoResolve (ResolveContext ec)
1559 eclass = ExprClass.Value;
1563 public override void Emit (EmitContext ec)
1566 // Use same anonymous method implementation for scenarios where same
1567 // code is used from multiple blocks, e.g. field initializers
1569 if (method == null) {
1571 // Delay an anonymous method definition to avoid emitting unused code
1572 // for unreachable blocks or expression trees
1574 method = DoCreateMethodHost (ec);
1578 bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
1579 if (is_static && am_cache == null) {
1581 // Creates a field cache to store delegate instance if it's not generic
1583 if (!method.MemberName.IsGeneric) {
1584 TypeContainer parent = method.Parent.PartialContainer;
1585 int id = parent.Fields == null ? 0 : parent.Fields.Count;
1586 var cache_type = storey != null && storey.Mutator != null ? storey.Mutator.Mutate (type) : type;
1588 am_cache = new Field (parent, new TypeExpression (cache_type, loc),
1589 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
1590 new MemberName (CompilerGeneratedClass.MakeName (null, "f", "am$cache", id), loc), null);
1592 parent.AddField (am_cache);
1594 // TODO: Implement caching of generated generic static methods
1598 // Some extra class is needed to capture variable generic type
1599 // arguments. Maybe we could re-use anonymous types, with a unique
1600 // anonymous method id, but they are quite heavy.
1602 // Consider : "() => typeof(T);"
1604 // We need something like
1605 // static class Wrap<Tn, Tm, DelegateType> {
1606 // public static DelegateType cache;
1609 // We then specialize local variable to capture all generic parameters
1610 // and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
1615 Label l_initialized = ec.DefineLabel ();
1617 if (am_cache != null) {
1618 ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
1619 ec.Emit (OpCodes.Brtrue_S, l_initialized);
1623 // Load method delegate implementation
1627 ec.Emit (OpCodes.Ldnull);
1628 } else if (storey != null) {
1629 Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext));
1633 ec.Emit (OpCodes.Ldarg_0);
1636 var delegate_method = method.Spec;
1637 if (storey != null && storey.MemberName.IsGeneric) {
1638 TypeSpec t = storey.Instance.Type;
1641 // Mutate anonymous method instance type if we are in nested
1642 // hoisted generic anonymous method storey
1644 if (ec.CurrentAnonymousMethod != null &&
1645 ec.CurrentAnonymousMethod.Storey != null &&
1646 ec.CurrentAnonymousMethod.Storey.Mutator != null) {
1647 t = storey.Mutator.Mutate (t);
1650 ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
1652 if (delegate_method.IsGeneric)
1653 delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);
1655 ec.Emit (OpCodes.Ldftn, delegate_method);
1658 var constructor_method = Delegate.GetConstructor (type);
1659 ec.Emit (OpCodes.Newobj, constructor_method);
1661 if (am_cache != null) {
1662 ec.Emit (OpCodes.Stsfld, am_cache.Spec);
1663 ec.MarkLabel (l_initialized);
1664 ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
1668 public override void EmitStatement (EmitContext ec)
1670 throw new NotImplementedException ();
1674 // Look for the best storey for this anonymous method
1676 AnonymousMethodStorey FindBestMethodStorey ()
1679 // Use the nearest parent block which has a storey
1681 for (Block b = Block.Parent; b != null; b = b.Parent) {
1682 AnonymousMethodStorey s = b.Explicit.AnonymousMethodStorey;
1690 public override string GetSignatureForError ()
1692 return TypeManager.CSharpName (type);
1695 public static void Reset ()
1702 // Anonymous type container
1704 public class AnonymousTypeClass : CompilerGeneratedClass
1706 static int types_counter;
1707 public const string ClassNamePrefix = "<>__AnonType";
1708 public const string SignatureForError = "anonymous type";
1710 readonly IList<AnonymousTypeParameter> parameters;
1712 private AnonymousTypeClass (TypeContainer parent, MemberName name, IList<AnonymousTypeParameter> parameters, Location loc)
1713 : base (parent, name, (parent.Module.Evaluator != null ? Modifiers.PUBLIC : 0) | Modifiers.SEALED)
1715 this.parameters = parameters;
1718 public static AnonymousTypeClass Create (TypeContainer parent, IList<AnonymousTypeParameter> parameters, Location loc)
1720 string name = ClassNamePrefix + types_counter++;
1722 ParametersCompiled all_parameters;
1723 TypeParameterName[] t_params;
1724 SimpleName[] t_args;
1726 if (parameters.Count == 0) {
1727 all_parameters = ParametersCompiled.EmptyReadOnlyParameters;
1728 t_params = new TypeParameterName[0];
1731 t_args = new SimpleName[parameters.Count];
1732 t_params = new TypeParameterName[parameters.Count];
1733 Parameter[] ctor_params = new Parameter[parameters.Count];
1734 for (int i = 0; i < parameters.Count; ++i) {
1735 AnonymousTypeParameter p = parameters[i];
1736 for (int ii = 0; ii < i; ++ii) {
1737 if (parameters[ii].Name == p.Name) {
1738 parent.Compiler.Report.Error (833, parameters[ii].Location,
1739 "`{0}': An anonymous type cannot have multiple properties with the same name",
1742 p = new AnonymousTypeParameter (null, "$" + i.ToString (), p.Location);
1748 t_args[i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1749 t_params[i] = new TypeParameterName (t_args[i].Name, null, p.Location);
1750 ctor_params[i] = new Parameter (t_args[i], p.Name, Parameter.Modifier.NONE, null, p.Location);
1753 all_parameters = new ParametersCompiled (ctor_params);
1757 // Create generic anonymous type host with generic arguments
1758 // named upon properties names
1760 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
1761 new MemberName (name, new TypeArguments (t_params), loc), parameters, loc);
1763 if (parameters.Count > 0)
1764 a_type.SetParameterInfo (null);
1766 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
1767 null, all_parameters, null, loc);
1768 c.Block = new ToplevelBlock (parent.Module.Compiler, c.ParameterInfo, loc);
1771 // Create fields and contructor body with field initialization
1774 for (int i = 0; i < parameters.Count; ++i) {
1775 AnonymousTypeParameter p = parameters [i];
1777 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
1778 new MemberName ("<" + p.Name + ">", p.Location), null);
1780 if (!a_type.AddField (f)) {
1785 c.Block.AddStatement (new StatementExpression (
1786 new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
1787 c.Block.GetParameterReference (i, p.Location))));
1789 ToplevelBlock get_block = new ToplevelBlock (parent.Module.Compiler, p.Location);
1790 get_block.AddStatement (new Return (
1791 new MemberAccess (new This (p.Location), f.Name), p.Location));
1793 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC,
1794 new MemberName (p.Name, p.Location), null);
1795 prop.Get = new Property.GetMethod (prop, 0, null, p.Location);
1796 prop.Get.Block = get_block;
1797 a_type.AddProperty (prop);
1803 a_type.AddConstructor (c);
1807 public static void Reset ()
1812 protected override bool AddToContainer (MemberCore symbol, string name)
1814 MemberCore mc = GetDefinition (name);
1817 defined_names.Add (name, symbol);
1821 // A conflict between anonymous type members will be reported
1822 if (symbol is TypeParameter) {
1823 Report.SymbolRelatedToPreviousError (symbol);
1827 // Ignore other conflicts
1831 protected override bool DoDefineMembers ()
1833 if (!base.DoDefineMembers ())
1836 Location loc = Location;
1838 var equals_parameters = ParametersCompiled.CreateFullyResolved (
1839 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc), Compiler.BuiltinTypes.Object);
1841 Method equals = new Method (this, null, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
1842 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("Equals", loc),
1843 equals_parameters, null);
1845 equals_parameters[0].Resolve (equals, 0);
1847 Method tostring = new Method (this, null, new TypeExpression (Compiler.BuiltinTypes.String, loc),
1848 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc),
1849 Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
1851 ToplevelBlock equals_block = new ToplevelBlock (Compiler, equals.ParameterInfo, loc);
1853 TypeExpr current_type;
1854 if (type_params != null) {
1855 var targs = new TypeArguments ();
1856 foreach (var type_param in type_params)
1857 targs.Add (new TypeParameterExpr (type_param, type_param.Location));
1859 current_type = new GenericTypeExpr (Definition, targs, loc);
1861 current_type = new TypeExpression (Definition, loc);
1864 var li_other = LocalVariable.CreateCompilerGenerated (CurrentType, equals_block, loc);
1865 equals_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_other.Type, loc), li_other));
1866 var other_variable = new LocalVariableReference (li_other, loc);
1868 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1869 new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc);
1871 Expression rs_equals = null;
1872 Expression string_concat = new StringConstant (Compiler.BuiltinTypes, "{", loc);
1873 Expression rs_hashcode = new IntConstant (Compiler.BuiltinTypes, -2128831035, loc);
1874 for (int i = 0; i < parameters.Count; ++i) {
1875 var p = parameters [i];
1878 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
1879 system_collections_generic, "EqualityComparer",
1880 new TypeArguments (new SimpleName (CurrentTypeParameters [i].Name, loc)), loc),
1883 Arguments arguments_equal = new Arguments (2);
1884 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1885 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
1887 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
1888 "Equals", loc), arguments_equal);
1890 Arguments arguments_hashcode = new Arguments (1);
1891 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1892 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
1893 "GetHashCode", loc), arguments_hashcode);
1895 IntConstant FNV_prime = new IntConstant (Compiler.BuiltinTypes, 16777619, loc);
1896 rs_hashcode = new Binary (Binary.Operator.Multiply,
1897 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode, loc),
1900 Expression field_to_string = new Conditional (new BooleanExpression (new Binary (Binary.Operator.Inequality,
1901 new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc), loc)),
1902 new Invocation (new MemberAccess (
1903 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
1904 new StringConstant (Compiler.BuiltinTypes, string.Empty, loc), loc);
1906 if (rs_equals == null) {
1907 rs_equals = field_equal;
1908 string_concat = new Binary (Binary.Operator.Addition,
1910 new Binary (Binary.Operator.Addition,
1911 new StringConstant (Compiler.BuiltinTypes, " " + p.Name + " = ", loc),
1919 // Implementation of ToString () body using string concatenation
1921 string_concat = new Binary (Binary.Operator.Addition,
1922 new Binary (Binary.Operator.Addition,
1924 new StringConstant (Compiler.BuiltinTypes, ", " + p.Name + " = ", loc),
1929 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal, loc);
1932 string_concat = new Binary (Binary.Operator.Addition,
1934 new StringConstant (Compiler.BuiltinTypes, " }", loc),
1938 // Equals (object obj) override
1940 var other_variable_assign = new TemporaryVariableReference (li_other, loc);
1941 equals_block.AddStatement (new StatementExpression (
1942 new SimpleAssign (other_variable_assign,
1943 new As (equals_block.GetParameterReference (0, loc),
1944 current_type, loc), loc)));
1946 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc), loc);
1947 if (rs_equals != null)
1948 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals, loc);
1949 equals_block.AddStatement (new Return (equals_test, loc));
1951 equals.Block = equals_block;
1956 // GetHashCode () override
1958 Method hashcode = new Method (this, null, new TypeExpression (Compiler.BuiltinTypes.Int, loc),
1959 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
1960 new MemberName ("GetHashCode", loc),
1961 Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
1964 // Modified FNV with good avalanche behavior and uniform
1965 // distribution with larger hash sizes.
1967 // const int FNV_prime = 16777619;
1968 // int hash = (int) 2166136261;
1969 // foreach (int d in data)
1970 // hash = (hash ^ d) * FNV_prime;
1971 // hash += hash << 13;
1972 // hash ^= hash >> 7;
1973 // hash += hash << 3;
1974 // hash ^= hash >> 17;
1975 // hash += hash << 5;
1977 ToplevelBlock hashcode_top = new ToplevelBlock (Compiler, loc);
1978 Block hashcode_block = new Block (hashcode_top, loc, loc);
1979 hashcode_top.AddStatement (new Unchecked (hashcode_block, loc));
1981 var li_hash = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Int, hashcode_top, loc);
1982 hashcode_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_hash.Type, loc), li_hash));
1983 LocalVariableReference hash_variable_assign = new LocalVariableReference (li_hash, loc);
1984 hashcode_block.AddStatement (new StatementExpression (
1985 new SimpleAssign (hash_variable_assign, rs_hashcode)));
1987 var hash_variable = new LocalVariableReference (li_hash, loc);
1988 hashcode_block.AddStatement (new StatementExpression (
1989 new CompoundAssign (Binary.Operator.Addition, hash_variable,
1990 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 13, loc), loc), loc)));
1991 hashcode_block.AddStatement (new StatementExpression (
1992 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
1993 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 7, loc), loc), loc)));
1994 hashcode_block.AddStatement (new StatementExpression (
1995 new CompoundAssign (Binary.Operator.Addition, hash_variable,
1996 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 3, loc), loc), loc)));
1997 hashcode_block.AddStatement (new StatementExpression (
1998 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
1999 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 17, loc), loc), loc)));
2000 hashcode_block.AddStatement (new StatementExpression (
2001 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2002 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 5, loc), loc), loc)));
2004 hashcode_block.AddStatement (new Return (hash_variable, loc));
2005 hashcode.Block = hashcode_top;
2007 AddMethod (hashcode);
2010 // ToString () override
2013 ToplevelBlock tostring_block = new ToplevelBlock (Compiler, loc);
2014 tostring_block.AddStatement (new Return (string_concat, loc));
2015 tostring.Block = tostring_block;
2017 AddMethod (tostring);
2022 public override string GetSignatureForError ()
2024 return SignatureForError;
2027 public IList<AnonymousTypeParameter> Parameters {