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-2011 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
14 using System
.Collections
.Generic
;
15 using Mono
.CompilerServices
.SymbolWriter
;
16 using System
.Diagnostics
;
19 using IKVM
.Reflection
;
20 using IKVM
.Reflection
.Emit
;
22 using System
.Reflection
;
23 using System
.Reflection
.Emit
;
26 namespace Mono
.CSharp
{
28 public abstract class CompilerGeneratedContainer
: ClassOrStruct
30 protected CompilerGeneratedContainer (TypeContainer parent
, MemberName name
, Modifiers mod
)
31 : this (parent
, name
, mod
, MemberKind
.Class
)
35 protected CompilerGeneratedContainer (TypeContainer parent
, MemberName name
, Modifiers mod
, MemberKind kind
)
36 : base (parent
, name
, null, kind
)
38 Debug
.Assert ((mod
& Modifiers
.AccessibilityMask
) != 0);
40 ModFlags
= mod
| Modifiers
.COMPILER_GENERATED
| Modifiers
.SEALED
;
41 spec
= new TypeSpec (Kind
, null, this, null, ModFlags
);
44 protected void CheckMembersDefined ()
46 if (HasMembersDefined
)
47 throw new InternalErrorException ("Helper class already defined!");
50 protected override bool DoDefineMembers ()
52 if (Kind
== MemberKind
.Class
&& !IsStatic
&& !PartialContainer
.HasInstanceConstructor
) {
53 DefineDefaultConstructor (false);
56 return base.DoDefineMembers ();
59 protected static MemberName
MakeMemberName (MemberBase host
, string name
, int unique_id
, TypeParameters tparams
, Location loc
)
61 string host_name
= host
== null ? null : host
is InterfaceMemberBase
? ((InterfaceMemberBase
)host
).GetFullName (host
.MemberName
) : host
.MemberName
.Name
;
62 string tname
= MakeName (host_name
, "c", name
, unique_id
);
63 TypeParameters args
= null;
64 if (tparams
!= null) {
65 args
= new TypeParameters (tparams
.Count
);
67 // Type parameters will be filled later when we have TypeContainer
68 // instance, for now we need only correct arity to create valid name
69 for (int i
= 0; i
< tparams
.Count
; ++i
)
70 args
.Add ((TypeParameter
) null);
73 return new MemberName (tname
, args
, loc
);
76 public static string MakeName (string host
, string typePrefix
, string name
, int id
)
78 return "<" + host
+ ">" + typePrefix
+ "__" + name
+ id
.ToString ("X");
81 protected override TypeSpec
[] ResolveBaseTypes (out FullNamedExpression base_class
)
83 base_type
= Compiler
.BuiltinTypes
.Object
;
90 public class HoistedStoreyClass
: CompilerGeneratedContainer
92 public sealed class HoistedField
: Field
94 public HoistedField (HoistedStoreyClass parent
, FullNamedExpression type
, Modifiers mod
, string name
,
95 Attributes attrs
, Location loc
)
96 : base (parent
, type
, mod
, new MemberName (name
, loc
), attrs
)
100 protected override bool ResolveMemberType ()
102 if (!base.ResolveMemberType ())
105 HoistedStoreyClass parent
= ((HoistedStoreyClass
) Parent
).GetGenericStorey ();
106 if (parent
!= null && parent
.Mutator
!= null)
107 member_type
= parent
.Mutator
.Mutate (MemberType
);
113 protected TypeParameterMutator mutator
;
115 public HoistedStoreyClass (TypeDefinition parent
, MemberName name
, TypeParameters tparams
, Modifiers mods
, MemberKind kind
)
116 : base (parent
, name
, mods
| Modifiers
.PRIVATE
, kind
)
119 if (tparams
!= null) {
120 var type_params
= name
.TypeParameters
;
121 var src
= new TypeParameterSpec
[tparams
.Count
];
122 var dst
= new TypeParameterSpec
[tparams
.Count
];
124 for (int i
= 0; i
< tparams
.Count
; ++i
) {
125 type_params
[i
] = tparams
[i
].CreateHoistedCopy (spec
);
127 src
[i
] = tparams
[i
].Type
;
128 dst
[i
] = type_params
[i
].Type
;
131 // A copy is not enough, inflate any type parameter constraints
132 // using a new type parameters
133 var inflator
= new TypeParameterInflator (this, null, src
, dst
);
134 for (int i
= 0; i
< tparams
.Count
; ++i
) {
135 src
[i
].InflateConstraints (inflator
, dst
[i
]);
138 mutator
= new TypeParameterMutator (tparams
, type_params
);
144 public TypeParameterMutator Mutator
{
155 public HoistedStoreyClass
GetGenericStorey ()
157 TypeContainer storey
= this;
158 while (storey
!= null && storey
.CurrentTypeParameters
== null)
159 storey
= storey
.Parent
;
161 return storey
as HoistedStoreyClass
;
167 // Anonymous method storey is created when an anonymous method uses
168 // variable or parameter from outer scope. They are then hoisted to
169 // anonymous method storey (captured)
171 public class AnonymousMethodStorey
: HoistedStoreyClass
173 struct StoreyFieldPair
175 public readonly AnonymousMethodStorey Storey
;
176 public readonly Field Field
;
178 public StoreyFieldPair (AnonymousMethodStorey storey
, Field field
)
180 this.Storey
= storey
;
186 // Needed to delay hoisted _this_ initialization. When an anonymous
187 // method is used inside ctor and _this_ is hoisted, base ctor has to
188 // be called first, otherwise _this_ will be initialized with
189 // uninitialized value.
191 sealed class ThisInitializer
: Statement
193 readonly HoistedThis hoisted_this
;
194 readonly AnonymousMethodStorey parent
;
196 public ThisInitializer (HoistedThis hoisted_this
, AnonymousMethodStorey parent
)
198 this.hoisted_this
= hoisted_this
;
199 this.parent
= parent
;
202 protected override void DoEmit (EmitContext ec
)
207 source
= new CompilerGeneratedThis (ec
.CurrentType
, loc
);
209 source
= new FieldExpr (parent
.HoistedThis
.Field
, Location
.Null
) {
210 InstanceExpression
= new CompilerGeneratedThis (ec
.CurrentType
, Location
.Null
)
214 hoisted_this
.EmitAssign (ec
, source
, false, false);
217 protected override bool DoFlowAnalysis (FlowAnalysisContext fc
)
222 protected override void CloneTo (CloneContext clonectx
, Statement target
)
229 public readonly int ID
;
231 public readonly ExplicitBlock OriginalSourceBlock
;
233 // A list of StoreyFieldPair with local field keeping parent storey instance
234 List
<StoreyFieldPair
> used_parent_storeys
;
235 List
<ExplicitBlock
> children_references
;
237 // A list of hoisted parameters
238 protected List
<HoistedParameter
> hoisted_params
;
239 List
<HoistedParameter
> hoisted_local_params
;
240 protected List
<HoistedVariable
> hoisted_locals
;
243 protected HoistedThis hoisted_this
;
245 // Local variable which holds this storey instance
246 public Expression Instance
;
248 bool initialize_hoisted_this
;
249 AnonymousMethodStorey hoisted_this_parent
;
251 public AnonymousMethodStorey (ExplicitBlock block
, TypeDefinition parent
, MemberBase host
, TypeParameters tparams
, string name
, MemberKind kind
)
252 : base (parent
, MakeMemberName (host
, name
, parent
.PartialContainer
.CounterAnonymousContainers
, tparams
, block
.StartLocation
),
255 OriginalSourceBlock
= block
;
256 ID
= parent
.PartialContainer
.CounterAnonymousContainers
++;
259 public void AddCapturedThisField (EmitContext ec
, AnonymousMethodStorey parent
)
261 TypeExpr type_expr
= new TypeExpression (ec
.CurrentType
, Location
);
262 Field f
= AddCompilerGeneratedField ("$this", type_expr
);
263 hoisted_this
= new HoistedThis (this, f
);
265 initialize_hoisted_this
= true;
266 hoisted_this_parent
= parent
;
269 public Field
AddCapturedVariable (string name
, TypeSpec type
)
271 CheckMembersDefined ();
273 FullNamedExpression field_type
= new TypeExpression (type
, Location
);
274 if (!spec
.IsGenericOrParentIsGeneric
)
275 return AddCompilerGeneratedField (name
, field_type
);
277 const Modifiers mod
= Modifiers
.INTERNAL
| Modifiers
.COMPILER_GENERATED
;
278 Field f
= new HoistedField (this, field_type
, mod
, name
, null, Location
);
283 protected Field
AddCompilerGeneratedField (string name
, FullNamedExpression type
)
285 return AddCompilerGeneratedField (name
, type
, false);
288 protected Field
AddCompilerGeneratedField (string name
, FullNamedExpression type
, bool privateAccess
)
290 Modifiers mod
= Modifiers
.COMPILER_GENERATED
| (privateAccess
? Modifiers
.PRIVATE
: Modifiers
.INTERNAL
);
291 Field f
= new Field (this, type
, mod
, new MemberName (name
, Location
), null);
297 // Creates a link between hoisted variable block and the anonymous method storey
299 // An anonymous method can reference variables from any outer block, but they are
300 // hoisted in their own ExplicitBlock. When more than one block is referenced we
301 // need to create another link between those variable storeys
303 public void AddReferenceFromChildrenBlock (ExplicitBlock block
)
305 if (children_references
== null)
306 children_references
= new List
<ExplicitBlock
> ();
308 if (!children_references
.Contains (block
))
309 children_references
.Add (block
);
312 public void AddParentStoreyReference (EmitContext ec
, AnonymousMethodStorey storey
)
314 CheckMembersDefined ();
316 if (used_parent_storeys
== null)
317 used_parent_storeys
= new List
<StoreyFieldPair
> ();
318 else if (used_parent_storeys
.Exists (i
=> i
.Storey
== storey
))
321 TypeExpr type_expr
= storey
.CreateStoreyTypeExpression (ec
);
322 Field f
= AddCompilerGeneratedField ("<>f__ref$" + storey
.ID
, type_expr
);
323 used_parent_storeys
.Add (new StoreyFieldPair (storey
, f
));
326 public void CaptureLocalVariable (ResolveContext ec
, LocalVariable localVariable
)
328 if (this is StateMachine
) {
329 if (ec
.CurrentBlock
.ParametersBlock
!= localVariable
.Block
.ParametersBlock
)
330 ec
.CurrentBlock
.Explicit
.HasCapturedVariable
= true;
332 ec
.CurrentBlock
.Explicit
.HasCapturedVariable
= true;
335 var hoisted
= localVariable
.HoistedVariant
;
336 if (hoisted
!= null && hoisted
.Storey
!= this && hoisted
.Storey
is StateMachine
) {
338 // Variable is already hoisted but we need it in storey which can be shared
340 hoisted
.Storey
.hoisted_locals
.Remove (hoisted
);
341 hoisted
.Storey
.Members
.Remove (hoisted
.Field
);
345 if (hoisted
== null) {
346 hoisted
= new HoistedLocalVariable (this, localVariable
, GetVariableMangledName (ec
, localVariable
));
347 localVariable
.HoistedVariant
= hoisted
;
349 if (hoisted_locals
== null)
350 hoisted_locals
= new List
<HoistedVariable
> ();
352 hoisted_locals
.Add (hoisted
);
355 if (ec
.CurrentBlock
.Explicit
!= localVariable
.Block
.Explicit
&& !(hoisted
.Storey
is StateMachine
) && hoisted
.Storey
!= null)
356 hoisted
.Storey
.AddReferenceFromChildrenBlock (ec
.CurrentBlock
.Explicit
);
359 public void CaptureParameter (ResolveContext ec
, ParametersBlock
.ParameterInfo parameterInfo
, ParameterReference parameterReference
)
361 if (!(this is StateMachine
)) {
362 ec
.CurrentBlock
.Explicit
.HasCapturedVariable
= true;
365 var hoisted
= parameterInfo
.Parameter
.HoistedVariant
;
367 if (parameterInfo
.Block
.StateMachine
!= null) {
369 // Another storey in same block exists but state machine does not
370 // have parameter captured. We need to add it there as well to
371 // proxy parameter value correctly.
373 if (hoisted
== null && parameterInfo
.Block
.StateMachine
!= this) {
374 var storey
= parameterInfo
.Block
.StateMachine
;
376 hoisted
= new HoistedParameter (storey
, parameterReference
);
377 parameterInfo
.Parameter
.HoistedVariant
= hoisted
;
379 if (storey
.hoisted_params
== null)
380 storey
.hoisted_params
= new List
<HoistedParameter
> ();
382 storey
.hoisted_params
.Add (hoisted
);
386 // Lift captured parameter from value type storey to reference type one. Otherwise
387 // any side effects would be done on a copy
389 if (hoisted
!= null && hoisted
.Storey
!= this && hoisted
.Storey
is StateMachine
) {
390 if (hoisted_local_params
== null)
391 hoisted_local_params
= new List
<HoistedParameter
> ();
393 hoisted_local_params
.Add (hoisted
);
398 if (hoisted
== null) {
399 hoisted
= new HoistedParameter (this, parameterReference
);
400 parameterInfo
.Parameter
.HoistedVariant
= hoisted
;
402 if (hoisted_params
== null)
403 hoisted_params
= new List
<HoistedParameter
> ();
405 hoisted_params
.Add (hoisted
);
409 // Register link between current block and parameter storey. It will
410 // be used when setting up storey definition to deploy storey reference
411 // when parameters are used from multiple blocks
413 if (ec
.CurrentBlock
.Explicit
!= parameterInfo
.Block
) {
414 hoisted
.Storey
.AddReferenceFromChildrenBlock (ec
.CurrentBlock
.Explicit
);
418 TypeExpr
CreateStoreyTypeExpression (EmitContext ec
)
421 // Create an instance of storey type
423 TypeExpr storey_type_expr
;
424 if (CurrentTypeParameters
!= null) {
426 // Use current method type parameter (MVAR) for top level storey only. All
427 // nested storeys use class type parameter (VAR)
429 var tparams
= ec
.CurrentAnonymousMethod
!= null && ec
.CurrentAnonymousMethod
.Storey
!= null ?
430 ec
.CurrentAnonymousMethod
.Storey
.CurrentTypeParameters
:
431 ec
.CurrentTypeParameters
;
433 TypeArguments targs
= new TypeArguments ();
436 // Use type parameter name instead of resolved type parameter
437 // specification to resolve to correctly nested type parameters
439 for (int i
= 0; i
< tparams
.Count
; ++i
)
440 targs
.Add (new SimpleName (tparams
[i
].Name
, Location
)); // new TypeParameterExpr (tparams[i], Location));
442 storey_type_expr
= new GenericTypeExpr (Definition
, targs
, Location
);
444 storey_type_expr
= new TypeExpression (CurrentType
, Location
);
447 return storey_type_expr
;
450 public void SetNestedStoryParent (AnonymousMethodStorey parentStorey
)
452 Parent
= parentStorey
;
453 spec
.IsGeneric
= false;
454 spec
.DeclaringType
= parentStorey
.CurrentType
;
455 MemberName
.TypeParameters
= null;
458 protected override bool DoResolveTypeParameters ()
460 // Although any storey can have type parameters they are all clones of method type
461 // parameters therefore have to mutate MVAR references in any of cloned constraints
462 if (CurrentTypeParameters
!= null) {
463 for (int i
= 0; i
< CurrentTypeParameters
.Count
; ++i
) {
464 var spec
= CurrentTypeParameters
[i
].Type
;
465 spec
.BaseType
= mutator
.Mutate (spec
.BaseType
);
466 if (spec
.InterfacesDefined
!= null) {
467 var mutated
= new TypeSpec
[spec
.InterfacesDefined
.Length
];
468 for (int ii
= 0; ii
< mutated
.Length
; ++ii
) {
469 mutated
[ii
] = mutator
.Mutate (spec
.InterfacesDefined
[ii
]);
472 spec
.InterfacesDefined
= mutated
;
475 if (spec
.TypeArguments
!= null) {
476 spec
.TypeArguments
= mutator
.Mutate (spec
.TypeArguments
);
482 // Update parent cache as we most likely passed the point
483 // where the cache was constructed
485 Parent
.CurrentType
.MemberCache
.AddMember (this.spec
);
491 // Initializes all hoisted variables
493 public void EmitStoreyInstantiation (EmitContext ec
, ExplicitBlock block
)
495 // There can be only one instance variable for each storey type
496 if (Instance
!= null)
497 throw new InternalErrorException ();
500 // Create an instance of this storey
502 ResolveContext rc
= new ResolveContext (ec
.MemberContext
);
503 rc
.CurrentBlock
= block
;
505 var storey_type_expr
= CreateStoreyTypeExpression (ec
);
506 var source
= new New (storey_type_expr
, null, Location
).Resolve (rc
);
509 // When the current context is async (or iterator) lift local storey
510 // instantiation to the currect storey
512 if (ec
.CurrentAnonymousMethod
is StateMachineInitializer
&& (block
.HasYield
|| block
.HasAwait
)) {
514 // Unfortunately, normal capture mechanism could not be used because we are
515 // too late in the pipeline and standart assign cannot be used either due to
516 // recursive nature of GetStoreyInstanceExpression
518 var field
= ec
.CurrentAnonymousMethod
.Storey
.AddCompilerGeneratedField (
519 LocalVariable
.GetCompilerGeneratedName (block
), storey_type_expr
, true);
524 var fexpr
= new FieldExpr (field
, Location
);
525 fexpr
.InstanceExpression
= new CompilerGeneratedThis (ec
.CurrentType
, Location
);
526 fexpr
.EmitAssign (ec
, source
, false, false);
529 var local
= TemporaryVariableReference
.Create (source
.Type
, block
, Location
, writeToSymbolFile
: true);
530 if (source
.Type
.IsStruct
) {
531 local
.LocalInfo
.CreateBuilder (ec
);
533 local
.EmitAssign (ec
, source
);
539 EmitHoistedFieldsInitialization (rc
, ec
);
541 // TODO: Implement properly
542 //SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
545 void EmitHoistedFieldsInitialization (ResolveContext rc
, EmitContext ec
)
548 // Initialize all storey reference fields by using local or hoisted variables
550 if (used_parent_storeys
!= null) {
551 foreach (StoreyFieldPair sf
in used_parent_storeys
) {
553 // Get instance expression of storey field
555 Expression instace_expr
= GetStoreyInstanceExpression (ec
);
556 var fs
= sf
.Field
.Spec
;
557 if (TypeManager
.IsGenericType (instace_expr
.Type
))
558 fs
= MemberCache
.GetMember (instace_expr
.Type
, fs
);
560 FieldExpr f_set_expr
= new FieldExpr (fs
, Location
);
561 f_set_expr
.InstanceExpression
= instace_expr
;
563 // TODO: CompilerAssign expression
564 SimpleAssign a
= new SimpleAssign (f_set_expr
, sf
.Storey
.GetStoreyInstanceExpression (ec
));
565 if (a
.Resolve (rc
) != null)
566 a
.EmitStatement (ec
);
571 // Initialize hoisted `this' only once, everywhere else will be
572 // referenced indirectly
574 if (initialize_hoisted_this
) {
575 rc
.CurrentBlock
.AddScopeStatement (new ThisInitializer (hoisted_this
, hoisted_this_parent
));
579 // Setting currect anonymous method to null blocks any further variable hoisting
581 AnonymousExpression ae
= ec
.CurrentAnonymousMethod
;
582 ec
.CurrentAnonymousMethod
= null;
584 if (hoisted_params
!= null) {
585 EmitHoistedParameters (ec
, hoisted_params
);
588 ec
.CurrentAnonymousMethod
= ae
;
591 protected virtual void EmitHoistedParameters (EmitContext ec
, List
<HoistedParameter
> hoisted
)
593 foreach (HoistedParameter hp
in hoisted
) {
598 // Parameters could be proxied via local fields for value type storey
600 if (hoisted_local_params
!= null) {
601 var local_param
= hoisted_local_params
.Find (l
=> l
.Parameter
.Parameter
== hp
.Parameter
.Parameter
);
602 var source
= new FieldExpr (local_param
.Field
, Location
);
603 source
.InstanceExpression
= new CompilerGeneratedThis (CurrentType
, Location
);
604 hp
.EmitAssign (ec
, source
, false, false);
608 hp
.EmitHoistingAssignment (ec
);
613 // Returns a field which holds referenced storey instance
615 Field
GetReferencedStoreyField (AnonymousMethodStorey storey
)
617 if (used_parent_storeys
== null)
620 foreach (StoreyFieldPair sf
in used_parent_storeys
) {
621 if (sf
.Storey
== storey
)
629 // Creates storey instance expression regardless of currect IP
631 public Expression
GetStoreyInstanceExpression (EmitContext ec
)
633 AnonymousExpression am
= ec
.CurrentAnonymousMethod
;
636 // Access from original block -> storey
642 // Access from anonymous method implemented as a static -> storey
644 if (am
.Storey
== null)
647 Field f
= am
.Storey
.GetReferencedStoreyField (this);
649 if (am
.Storey
== this) {
651 // Access from inside of same storey (S -> S)
653 return new CompilerGeneratedThis (CurrentType
, Location
);
657 // External field access
663 // Storey was cached to local field
665 FieldExpr f_ind
= new FieldExpr (f
, Location
);
666 f_ind
.InstanceExpression
= new CompilerGeneratedThis (CurrentType
, Location
);
670 protected virtual string GetVariableMangledName (ResolveContext rc
, LocalVariable local_info
)
673 // No need to mangle anonymous method hoisted variables cause they
674 // are hoisted in their own scopes
676 return local_info
.Name
;
679 public HoistedThis HoistedThis
{
684 hoisted_this
= value;
688 public IList
<ExplicitBlock
> ReferencesFromChildrenBlock
{
689 get { return children_references; }
693 public abstract class HoistedVariable
696 // Hoisted version of variable references used in expression
697 // tree has to be delayed until we know its location. The variable
698 // doesn't know its location until all stories are calculated
700 class ExpressionTreeVariableReference
: Expression
702 readonly HoistedVariable hv
;
704 public ExpressionTreeVariableReference (HoistedVariable hv
)
709 public override bool ContainsEmitWithAwait ()
714 public override Expression
CreateExpressionTree (ResolveContext ec
)
716 return hv
.CreateExpressionTree ();
719 protected override Expression
DoResolve (ResolveContext ec
)
721 eclass
= ExprClass
.Value
;
722 type
= ec
.Module
.PredefinedTypes
.Expression
.Resolve ();
726 public override void Emit (EmitContext ec
)
728 ResolveContext rc
= new ResolveContext (ec
.MemberContext
);
729 Expression e
= hv
.GetFieldExpression (ec
).CreateExpressionTree (rc
, false);
730 // This should never fail
737 protected readonly AnonymousMethodStorey storey
;
738 protected Field field
;
739 Dictionary
<AnonymousExpression
, FieldExpr
> cached_inner_access
; // TODO: Hashtable is too heavyweight
740 FieldExpr cached_outer_access
;
742 protected HoistedVariable (AnonymousMethodStorey storey
, string name
, TypeSpec type
)
743 : this (storey
, storey
.AddCapturedVariable (name
, type
))
747 protected HoistedVariable (AnonymousMethodStorey storey
, Field field
)
749 this.storey
= storey
;
759 public AnonymousMethodStorey Storey
{
765 public void AddressOf (EmitContext ec
, AddressOp mode
)
767 GetFieldExpression (ec
).AddressOf (ec
, mode
);
770 public Expression
CreateExpressionTree ()
772 return new ExpressionTreeVariableReference (this);
775 public void Emit (EmitContext ec
)
777 GetFieldExpression (ec
).Emit (ec
);
780 public Expression
EmitToField (EmitContext ec
)
782 return GetFieldExpression (ec
);
786 // Creates field access expression for hoisted variable
788 protected virtual FieldExpr
GetFieldExpression (EmitContext ec
)
790 if (ec
.CurrentAnonymousMethod
== null || ec
.CurrentAnonymousMethod
.Storey
== null) {
791 if (cached_outer_access
!= null)
792 return cached_outer_access
;
795 // When setting top-level hoisted variable in generic storey
796 // change storey generic types to method generic types (VAR -> MVAR)
798 if (storey
.Instance
.Type
.IsGenericOrParentIsGeneric
) {
799 var fs
= MemberCache
.GetMember (storey
.Instance
.Type
, field
.Spec
);
800 cached_outer_access
= new FieldExpr (fs
, field
.Location
);
802 cached_outer_access
= new FieldExpr (field
, field
.Location
);
805 cached_outer_access
.InstanceExpression
= storey
.GetStoreyInstanceExpression (ec
);
806 return cached_outer_access
;
809 FieldExpr inner_access
;
810 if (cached_inner_access
!= null) {
811 if (!cached_inner_access
.TryGetValue (ec
.CurrentAnonymousMethod
, out inner_access
))
815 cached_inner_access
= new Dictionary
<AnonymousExpression
, FieldExpr
> (4);
818 if (inner_access
== null) {
819 if (field
.Parent
.IsGenericOrParentIsGeneric
) {
820 var fs
= MemberCache
.GetMember (field
.Parent
.CurrentType
, field
.Spec
);
821 inner_access
= new FieldExpr (fs
, field
.Location
);
823 inner_access
= new FieldExpr (field
, field
.Location
);
826 inner_access
.InstanceExpression
= storey
.GetStoreyInstanceExpression (ec
);
827 cached_inner_access
.Add (ec
.CurrentAnonymousMethod
, inner_access
);
833 public void Emit (EmitContext ec
, bool leave_copy
)
835 GetFieldExpression (ec
).Emit (ec
, leave_copy
);
838 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
840 GetFieldExpression (ec
).EmitAssign (ec
, source
, leave_copy
, false);
843 public void EmitAssignFromStack (EmitContext ec
)
845 GetFieldExpression (ec
).EmitAssignFromStack (ec
);
849 public class HoistedParameter
: HoistedVariable
851 sealed class HoistedFieldAssign
: CompilerAssign
853 public HoistedFieldAssign (Expression target
, Expression source
)
854 : base (target
, source
, target
.Location
)
858 protected override Expression
ResolveConversions (ResolveContext ec
)
861 // Implicit conversion check fails for hoisted type arguments
862 // as they are of different types (!!0 x !0)
868 readonly ParameterReference parameter
;
870 public HoistedParameter (AnonymousMethodStorey scope
, ParameterReference par
)
871 : base (scope
, par
.Name
, par
.Type
)
873 this.parameter
= par
;
876 public HoistedParameter (HoistedParameter hp
, string name
)
877 : base (hp
.storey
, name
, hp
.parameter
.Type
)
879 this.parameter
= hp
.parameter
;
884 public bool IsAssigned { get; set; }
886 public ParameterReference Parameter
{
894 public void EmitHoistingAssignment (EmitContext ec
)
897 // Remove hoisted redirection to emit assignment from original parameter
899 var temp
= parameter
.Parameter
.HoistedVariant
;
900 parameter
.Parameter
.HoistedVariant
= null;
902 var a
= new HoistedFieldAssign (GetFieldExpression (ec
), parameter
);
903 a
.EmitStatement (ec
);
905 parameter
.Parameter
.HoistedVariant
= temp
;
909 class HoistedLocalVariable
: HoistedVariable
911 public HoistedLocalVariable (AnonymousMethodStorey storey
, LocalVariable local
, string name
)
912 : base (storey
, name
, local
.Type
)
917 public class HoistedThis
: HoistedVariable
919 public HoistedThis (AnonymousMethodStorey storey
, Field field
)
920 : base (storey
, field
)
926 // Anonymous method expression as created by parser
928 public class AnonymousMethodExpression
: Expression
931 // Special conversion for nested expression tree lambdas
933 class Quote
: ShimExpression
935 public Quote (Expression expr
)
940 public override Expression
CreateExpressionTree (ResolveContext ec
)
942 var args
= new Arguments (1);
943 args
.Add (new Argument (expr
.CreateExpressionTree (ec
)));
944 return CreateExpressionFactoryCall (ec
, "Quote", args
);
947 protected override Expression
DoResolve (ResolveContext rc
)
949 expr
= expr
.Resolve (rc
);
953 eclass
= expr
.eclass
;
959 readonly Dictionary
<TypeSpec
, Expression
> compatibles
;
961 public ParametersBlock Block
;
963 public AnonymousMethodExpression (Location loc
)
966 this.compatibles
= new Dictionary
<TypeSpec
, Expression
> ();
971 public override string ExprClassName
{
973 return "anonymous method";
977 public virtual bool HasExplicitParameters
{
979 return Parameters
!= ParametersCompiled
.Undefined
;
983 public override bool IsSideEffectFree
{
989 public ParametersCompiled Parameters
{
991 return Block
.Parameters
;
995 public ReportPrinter TypeInferenceReportPrinter
{
1002 // Returns true if the body of lambda expression can be implicitly
1003 // converted to the delegate of type `delegate_type'
1005 public bool ImplicitStandardConversionExists (ResolveContext ec
, TypeSpec delegate_type
)
1007 using (ec
.With (ResolveContext
.Options
.InferReturnType
, false)) {
1008 using (ec
.Set (ResolveContext
.Options
.ProbingMode
)) {
1009 var prev
= ec
.Report
.SetPrinter (TypeInferenceReportPrinter
?? new NullReportPrinter ());
1011 var res
= Compatible (ec
, delegate_type
) != null;
1013 ec
.Report
.SetPrinter (prev
);
1020 TypeSpec
CompatibleChecks (ResolveContext ec
, TypeSpec delegate_type
)
1022 if (delegate_type
.IsDelegate
)
1023 return delegate_type
;
1025 if (delegate_type
.IsExpressionTreeType
) {
1026 delegate_type
= delegate_type
.TypeArguments
[0];
1027 if (delegate_type
.IsDelegate
)
1028 return delegate_type
;
1030 ec
.Report
.Error (835, loc
, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
1031 GetSignatureForError (), delegate_type
.GetSignatureForError ());
1035 ec
.Report
.Error (1660, loc
, "Cannot convert `{0}' to non-delegate type `{1}'",
1036 GetSignatureForError (), delegate_type
.GetSignatureForError ());
1040 protected bool VerifyExplicitParameters (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec delegate_type
, AParametersCollection parameters
)
1042 if (VerifyParameterCompatibility (ec
, tic
, delegate_type
, parameters
, ec
.IsInProbingMode
))
1045 if (!ec
.IsInProbingMode
)
1046 ec
.Report
.Error (1661, loc
,
1047 "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1048 GetSignatureForError (), delegate_type
.GetSignatureForError ());
1053 protected bool VerifyParameterCompatibility (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec delegate_type
, AParametersCollection invoke_pd
, bool ignore_errors
)
1055 if (Parameters
.Count
!= invoke_pd
.Count
) {
1059 ec
.Report
.Error (1593, loc
, "Delegate `{0}' does not take `{1}' arguments",
1060 delegate_type
.GetSignatureForError (), Parameters
.Count
.ToString ());
1064 bool has_implicit_parameters
= !HasExplicitParameters
;
1067 for (int i
= 0; i
< Parameters
.Count
; ++i
) {
1068 Parameter
.Modifier p_mod
= invoke_pd
.FixedParameters
[i
].ModFlags
;
1069 if (Parameters
.FixedParameters
[i
].ModFlags
!= p_mod
&& p_mod
!= Parameter
.Modifier
.PARAMS
) {
1073 if (p_mod
== Parameter
.Modifier
.NONE
)
1074 ec
.Report
.Error (1677, Parameters
[i
].Location
, "Parameter `{0}' should not be declared with the `{1}' keyword",
1075 (i
+ 1).ToString (), Parameter
.GetModifierSignature (Parameters
[i
].ModFlags
));
1077 ec
.Report
.Error (1676, Parameters
[i
].Location
, "Parameter `{0}' must be declared with the `{1}' keyword",
1078 (i
+1).ToString (), Parameter
.GetModifierSignature (p_mod
));
1082 if (has_implicit_parameters
)
1085 TypeSpec type
= invoke_pd
.Types
[i
];
1088 type
= tic
.InflateGenericArgument (ec
, type
);
1090 if (!TypeSpecComparer
.IsEqual (type
, Parameters
.Types
[i
])) {
1094 ec
.Report
.Error (1678, Parameters
[i
].Location
, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1096 Parameters
.Types
[i
].GetSignatureForError (),
1097 invoke_pd
.Types
[i
].GetSignatureForError ());
1106 // Infers type arguments based on explicit arguments
1108 public bool ExplicitTypeInference (TypeInferenceContext type_inference
, TypeSpec delegate_type
)
1110 if (!HasExplicitParameters
)
1113 if (!delegate_type
.IsDelegate
) {
1114 if (!delegate_type
.IsExpressionTreeType
)
1117 delegate_type
= TypeManager
.GetTypeArguments (delegate_type
) [0];
1118 if (!delegate_type
.IsDelegate
)
1122 AParametersCollection d_params
= Delegate
.GetParameters (delegate_type
);
1123 if (d_params
.Count
!= Parameters
.Count
)
1126 var ptypes
= Parameters
.Types
;
1127 var dtypes
= d_params
.Types
;
1128 for (int i
= 0; i
< Parameters
.Count
; ++i
) {
1129 if (type_inference
.ExactInference (ptypes
[i
], dtypes
[i
]) == 0) {
1131 // Continue when 0 (quick path) does not mean inference failure. Checking for
1132 // same type handles cases like int -> int
1134 if (ptypes
[i
] == dtypes
[i
])
1144 public TypeSpec
InferReturnType (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec delegate_type
)
1147 AnonymousExpression am
;
1149 if (compatibles
.TryGetValue (delegate_type
, out expr
)) {
1150 am
= expr
as AnonymousExpression
;
1151 return am
== null ? null : am
.ReturnType
;
1154 using (ec
.Set (ResolveContext
.Options
.ProbingMode
| ResolveContext
.Options
.InferReturnType
)) {
1156 if (TypeInferenceReportPrinter
!= null) {
1157 prev
= ec
.Report
.SetPrinter (TypeInferenceReportPrinter
);
1162 HashSet
<LocalVariable
> undeclaredVariables
= null;
1163 var body
= CompatibleMethodBody (ec
, tic
, null, delegate_type
, ref undeclaredVariables
);
1165 am
= body
.Compatible (ec
, body
);
1170 if (TypeInferenceReportPrinter
!= null) {
1171 ec
.Report
.SetPrinter (prev
);
1174 if (undeclaredVariables
!= null) {
1175 body
.Block
.TopBlock
.SetUndeclaredVariables (undeclaredVariables
);
1182 // compatibles.Add (delegate_type, am);
1183 return am
.ReturnType
;
1186 public override bool ContainsEmitWithAwait ()
1192 // Returns AnonymousMethod container if this anonymous method
1193 // expression can be implicitly converted to the delegate type `delegate_type'
1195 public Expression
Compatible (ResolveContext ec
, TypeSpec type
)
1198 if (compatibles
.TryGetValue (type
, out am
))
1201 if (type
== InternalType
.ErrorType
)
1204 TypeSpec delegate_type
= CompatibleChecks (ec
, type
);
1205 if (delegate_type
== null)
1209 // At this point its the first time we know the return type that is
1210 // needed for the anonymous method. We create the method here.
1213 var invoke_mb
= Delegate
.GetInvokeMethod (delegate_type
);
1214 TypeSpec return_type
= invoke_mb
.ReturnType
;
1217 // Second: the return type of the delegate must be compatible with
1218 // the anonymous type. Instead of doing a pass to examine the block
1219 // we satisfy the rule by setting the return type on the EmitContext
1220 // to be the delegate type return type.
1222 HashSet
<LocalVariable
> undeclaredVariables
= null;
1223 var body
= CompatibleMethodBody (ec
, null, return_type
, delegate_type
, ref undeclaredVariables
);
1227 bool etree_conversion
= delegate_type
!= type
;
1230 if (etree_conversion
) {
1231 if (ec
.HasSet (ResolveContext
.Options
.ExpressionTreeConversion
)) {
1233 // Nested expression tree lambda use same scope as parent
1234 // lambda, this also means no variable capturing between this
1237 am
= body
.Compatible (ec
, ec
.CurrentAnonymousMethod
);
1240 // Quote nested expression tree
1243 am
= new Quote (am
);
1245 int errors
= ec
.Report
.Errors
;
1247 if (Block
.IsAsync
) {
1248 ec
.Report
.Error (1989, loc
, "Async lambda expressions cannot be converted to expression trees");
1251 using (ec
.Set (ResolveContext
.Options
.ExpressionTreeConversion
)) {
1252 am
= body
.Compatible (ec
);
1256 // Rewrite expressions into expression tree when targeting Expression<T>
1258 if (am
!= null && errors
== ec
.Report
.Errors
)
1259 am
= CreateExpressionTree (ec
, delegate_type
);
1262 am
= body
.Compatible (ec
);
1264 if (body
.DirectMethodGroupConversion
!= null) {
1265 var errors_printer
= new SessionReportPrinter ();
1266 var old
= ec
.Report
.SetPrinter (errors_printer
);
1267 var expr
= new ImplicitDelegateCreation (delegate_type
, body
.DirectMethodGroupConversion
, loc
) {
1268 AllowSpecialMethodsInvocation
= true
1270 ec
.Report
.SetPrinter (old
);
1271 if (expr
!= null && errors_printer
.ErrorsCount
== 0)
1275 } catch (CompletionResult
) {
1277 } catch (FatalException
) {
1279 } catch (Exception e
) {
1280 throw new InternalErrorException (e
, loc
);
1283 // LocalVariable is not stateless and it's not easy to clone because it's
1284 // cached in toplevel block. Unsetting any initialized variables should
1287 if (undeclaredVariables
!= null) {
1288 body
.Block
.TopBlock
.SetUndeclaredVariables (undeclaredVariables
);
1292 if (!ec
.IsInProbingMode
&& !etree_conversion
) {
1293 compatibles
.Add (type
, am
?? EmptyExpression
.Null
);
1299 protected virtual Expression
CreateExpressionTree (ResolveContext ec
, TypeSpec delegate_type
)
1301 return CreateExpressionTree (ec
);
1304 public override Expression
CreateExpressionTree (ResolveContext ec
)
1306 ec
.Report
.Error (1946, loc
, "An anonymous method cannot be converted to an expression tree");
1310 protected virtual ParametersCompiled
ResolveParameters (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec delegate_type
)
1312 var delegate_parameters
= Delegate
.GetParameters (delegate_type
);
1314 if (Parameters
== ParametersCompiled
.Undefined
) {
1316 // We provide a set of inaccessible parameters
1318 Parameter
[] fixedpars
= new Parameter
[delegate_parameters
.Count
];
1320 for (int i
= 0; i
< delegate_parameters
.Count
; i
++) {
1321 Parameter
.Modifier i_mod
= delegate_parameters
.FixedParameters
[i
].ModFlags
;
1322 if ((i_mod
& Parameter
.Modifier
.OUT
) != 0) {
1323 if (!ec
.IsInProbingMode
) {
1324 ec
.Report
.Error (1688, loc
,
1325 "Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters",
1326 delegate_type
.GetSignatureForError ());
1331 fixedpars
[i
] = new Parameter (
1332 new TypeExpression (delegate_parameters
.Types
[i
], loc
), null,
1333 delegate_parameters
.FixedParameters
[i
].ModFlags
, null, loc
);
1336 return ParametersCompiled
.CreateFullyResolved (fixedpars
, delegate_parameters
.Types
);
1339 if (!VerifyExplicitParameters (ec
, tic
, delegate_type
, delegate_parameters
)) {
1346 protected override Expression
DoResolve (ResolveContext rc
)
1348 if (rc
.HasSet (ResolveContext
.Options
.ConstantScope
)) {
1349 rc
.Report
.Error (1706, loc
, "Anonymous methods and lambda expressions cannot be used in the current context");
1354 // Update top-level block generated duting parsing with actual top-level block
1356 if (rc
.HasAny (ResolveContext
.Options
.FieldInitializerScope
| ResolveContext
.Options
.BaseInitializer
) && rc
.CurrentMemberDefinition
.Parent
.PartialContainer
.PrimaryConstructorParameters
!= null) {
1357 var tb
= rc
.ConstructorBlock
.ParametersBlock
.TopBlock
;
1358 if (Block
.TopBlock
!= tb
) {
1360 while (b
.Parent
!= Block
.TopBlock
&& b
!= Block
.TopBlock
)
1364 tb
.IncludeBlock (Block
, Block
.TopBlock
);
1365 b
.ParametersBlock
.TopBlock
= tb
;
1369 eclass
= ExprClass
.Value
;
1372 // This hack means `The type is not accessible
1373 // anywhere', we depend on special conversion
1376 type
= InternalType
.AnonymousMethod
;
1378 if (!DoResolveParameters (rc
))
1384 protected virtual bool DoResolveParameters (ResolveContext rc
)
1386 return Parameters
.Resolve (rc
);
1389 public override void Emit (EmitContext ec
)
1391 // nothing, as we only exist to not do anything.
1394 public static void Error_AddressOfCapturedVar (ResolveContext rc
, IVariableReference
var, Location loc
)
1396 if (rc
.CurrentAnonymousMethod
is AsyncInitializer
)
1399 rc
.Report
.Error (1686, loc
,
1400 "Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method, lambda expression or query expression",
1404 public override string GetSignatureForError ()
1406 return ExprClassName
;
1409 AnonymousMethodBody
CompatibleMethodBody (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec return_type
, TypeSpec delegate_type
, ref HashSet
<LocalVariable
> undeclaredVariables
)
1411 ParametersCompiled p
= ResolveParameters (ec
, tic
, delegate_type
);
1415 ParametersBlock b
= ec
.IsInProbingMode
? (ParametersBlock
) Block
.PerformClone (ref undeclaredVariables
) : Block
;
1418 var rt
= return_type
;
1419 if (rt
!= null && rt
.Kind
!= MemberKind
.Void
&& rt
!= ec
.Module
.PredefinedTypes
.Task
.TypeSpec
&& !rt
.IsGenericTask
) {
1420 ec
.Report
.Error (4010, loc
, "Cannot convert async {0} to delegate type `{1}'",
1421 GetSignatureForError (), delegate_type
.GetSignatureForError ());
1426 b
= b
.ConvertToAsyncTask (ec
, ec
.CurrentMemberDefinition
.Parent
.PartialContainer
, p
, return_type
, delegate_type
, loc
);
1429 return CompatibleMethodFactory (return_type
?? InternalType
.ErrorType
, delegate_type
, p
, b
);
1432 protected virtual AnonymousMethodBody
CompatibleMethodFactory (TypeSpec return_type
, TypeSpec delegate_type
, ParametersCompiled p
, ParametersBlock b
)
1434 return new AnonymousMethodBody (p
, b
, return_type
, delegate_type
, loc
);
1437 protected override void CloneTo (CloneContext clonectx
, Expression t
)
1439 AnonymousMethodExpression target
= (AnonymousMethodExpression
) t
;
1441 target
.Block
= (ParametersBlock
) clonectx
.LookupBlock (Block
);
1444 public override object Accept (StructuralVisitor visitor
)
1446 return visitor
.Visit (this);
1451 // Abstract expression for any block which requires variables hoisting
1453 public abstract class AnonymousExpression
: ExpressionStatement
1455 protected class AnonymousMethodMethod
: Method
1457 public readonly AnonymousExpression AnonymousMethod
;
1458 public readonly AnonymousMethodStorey Storey
;
1460 public AnonymousMethodMethod (TypeDefinition parent
, AnonymousExpression am
, AnonymousMethodStorey storey
,
1461 TypeExpr return_type
,
1462 Modifiers mod
, MemberName name
,
1463 ParametersCompiled parameters
)
1464 : base (parent
, return_type
, mod
| Modifiers
.COMPILER_GENERATED
,
1465 name
, parameters
, null)
1467 this.AnonymousMethod
= am
;
1468 this.Storey
= storey
;
1470 Parent
.PartialContainer
.Members
.Add (this);
1471 Block
= new ToplevelBlock (am
.block
, parameters
);
1474 public override EmitContext
CreateEmitContext (ILGenerator ig
, SourceMethodBuilder sourceMethod
)
1476 EmitContext ec
= new EmitContext (this, ig
, ReturnType
, sourceMethod
);
1477 ec
.CurrentAnonymousMethod
= AnonymousMethod
;
1481 protected override void DefineTypeParameters ()
1483 // Type parameters were cloned
1486 protected override bool ResolveMemberType ()
1488 if (!base.ResolveMemberType ())
1491 if (Storey
!= null && Storey
.Mutator
!= null) {
1492 if (!parameters
.IsEmpty
) {
1493 var mutated
= Storey
.Mutator
.Mutate (parameters
.Types
);
1494 if (mutated
!= parameters
.Types
)
1495 parameters
= ParametersCompiled
.CreateFullyResolved ((Parameter
[]) parameters
.FixedParameters
, mutated
);
1498 member_type
= Storey
.Mutator
.Mutate (member_type
);
1504 public override void Emit ()
1506 if (MethodBuilder
== null) {
1514 protected readonly ParametersBlock block
;
1516 public TypeSpec ReturnType
;
1518 protected AnonymousExpression (ParametersBlock block
, TypeSpec return_type
, Location loc
)
1520 this.ReturnType
= return_type
;
1525 public abstract string ContainerType { get; }
1526 public abstract bool IsIterator { get; }
1527 public abstract AnonymousMethodStorey Storey { get; }
1530 // The block that makes up the body for the anonymous method
1532 public ParametersBlock Block
{
1538 public AnonymousExpression
Compatible (ResolveContext ec
)
1540 return Compatible (ec
, this);
1543 public AnonymousExpression
Compatible (ResolveContext ec
, AnonymousExpression ae
)
1548 // TODO: Implement clone
1549 BlockContext aec
= new BlockContext (ec
, block
, ReturnType
);
1550 aec
.CurrentAnonymousMethod
= ae
;
1552 var am
= this as AnonymousMethodBody
;
1554 if (ec
.HasSet (ResolveContext
.Options
.InferReturnType
) && am
!= null) {
1555 am
.ReturnTypeInference
= new TypeInferenceContext ();
1558 var bc
= ec
as BlockContext
;
1561 aec
.AssignmentInfoOffset
= bc
.AssignmentInfoOffset
;
1562 aec
.EnclosingLoop
= bc
.EnclosingLoop
;
1563 aec
.EnclosingLoopOrSwitch
= bc
.EnclosingLoopOrSwitch
;
1564 aec
.Switch
= bc
.Switch
;
1567 var errors
= ec
.Report
.Errors
;
1569 bool res
= Block
.Resolve (aec
);
1571 if (res
&& errors
== ec
.Report
.Errors
) {
1572 MarkReachable (new Reachability ());
1574 if (!CheckReachableExit (ec
.Report
)) {
1579 bc
.AssignmentInfoOffset
= aec
.AssignmentInfoOffset
;
1582 if (am
!= null && am
.ReturnTypeInference
!= null) {
1583 am
.ReturnTypeInference
.FixAllTypes (ec
);
1584 ReturnType
= am
.ReturnTypeInference
.InferredTypeArguments
[0];
1585 am
.ReturnTypeInference
= null;
1588 // If e is synchronous the inferred return type is T
1589 // If e is asynchronous and the body of F is either an expression classified as nothing
1590 // or a statement block where no return statements have expressions, the inferred return type is Task
1591 // If e is async and has an inferred result type T, the inferred return type is Task<T>
1593 if (block
.IsAsync
&& ReturnType
!= null) {
1594 ReturnType
= ReturnType
.Kind
== MemberKind
.Void
?
1595 ec
.Module
.PredefinedTypes
.Task
.TypeSpec
:
1596 ec
.Module
.PredefinedTypes
.TaskGeneric
.TypeSpec
.MakeGenericType (ec
, new [] { ReturnType }
);
1600 if (res
&& errors
!= ec
.Report
.Errors
)
1603 if (block
.IsAsync
&& block
.Original
.ParametersBlock
.HasCapturedThis
&& ec
.CurrentAnonymousMethod
!= null && ec
.CurrentAnonymousMethod
.block
.IsAsync
) {
1605 // We'll do ldftn to load the fabricated m_X method but
1606 // because we are inside struct the method can be hoisted
1607 // anywhere in the parent scope
1609 ec
.CurrentBlock
.ParametersBlock
.HasReferenceToStoreyForInstanceLambdas
= true;
1612 return res
? this : null;
1615 public override bool ContainsEmitWithAwait ()
1620 bool CheckReachableExit (Report report
)
1622 if (block
.HasReachableClosingBrace
&& ReturnType
.Kind
!= MemberKind
.Void
) {
1623 // FIXME: Flow-analysis on MoveNext generated code
1625 report
.Error (1643, StartLocation
,
1626 "Not all code paths return a value in anonymous method of type `{0}'", GetSignatureForError ());
1635 public override void FlowAnalysis (FlowAnalysisContext fc
)
1637 // We are reachable, mark block body reachable too
1638 MarkReachable (new Reachability ());
1640 CheckReachableExit (fc
.Report
);
1642 var das
= fc
.BranchDefiniteAssignment ();
1643 var prev_pb
= fc
.ParametersBlock
;
1644 fc
.ParametersBlock
= Block
;
1645 var da_ontrue
= fc
.DefiniteAssignmentOnTrue
;
1646 var da_onfalse
= fc
.DefiniteAssignmentOnFalse
;
1647 var prev_tf
= fc
.TryFinally
;
1649 fc
.DefiniteAssignmentOnTrue
= fc
.DefiniteAssignmentOnFalse
= null;
1650 fc
.TryFinally
= null;
1651 block
.FlowAnalysis (fc
);
1653 fc
.ParametersBlock
= prev_pb
;
1654 fc
.DefiniteAssignment
= das
;
1655 fc
.DefiniteAssignmentOnTrue
= da_ontrue
;
1656 fc
.DefiniteAssignmentOnFalse
= da_onfalse
;
1657 fc
.TryFinally
= prev_tf
;
1660 public override Reachability
MarkReachable (Reachability rc
)
1662 block
.MarkReachable (rc
);
1666 public void SetHasThisAccess ()
1668 ExplicitBlock b
= block
;
1670 if (b
.HasCapturedThis
)
1673 b
.HasCapturedThis
= true;
1674 b
= b
.Parent
== null ? null : b
.Parent
.Explicit
;
1675 } while (b
!= null);
1679 public class AnonymousMethodBody
: AnonymousExpression
1681 protected readonly ParametersCompiled parameters
;
1682 AnonymousMethodStorey storey
;
1684 AnonymousMethodMethod method
;
1687 TypeInferenceContext return_inference
;
1689 public AnonymousMethodBody (ParametersCompiled parameters
,
1690 ParametersBlock block
, TypeSpec return_type
, TypeSpec delegate_type
,
1692 : base (block
, return_type
, loc
)
1694 this.type
= delegate_type
;
1695 this.parameters
= parameters
;
1700 public override string ContainerType
{
1701 get { return "anonymous method"; }
1705 // Method-group instance for lambdas which can be replaced with
1706 // simple method group call
1708 public MethodGroupExpr DirectMethodGroupConversion
{
1712 public override bool IsIterator
{
1718 public ParametersCompiled Parameters
{
1724 public TypeInferenceContext ReturnTypeInference
{
1726 return return_inference
;
1729 return_inference
= value;
1733 public override AnonymousMethodStorey Storey
{
1741 public override Expression
CreateExpressionTree (ResolveContext ec
)
1743 ec
.Report
.Error (1945, loc
, "An expression tree cannot contain an anonymous method expression");
1747 bool Define (ResolveContext ec
)
1749 if (!Block
.Resolved
&& Compatible (ec
) == null)
1752 if (block_name
== null) {
1753 MemberCore mc
= (MemberCore
) ec
.MemberContext
;
1754 block_name
= mc
.MemberName
.Basename
;
1761 // Creates a host for the anonymous method
1763 AnonymousMethodMethod
DoCreateMethodHost (EmitContext ec
)
1766 // Anonymous method body can be converted to
1768 // 1, an instance method in current scope when only `this' is hoisted
1769 // 2, a static method in current scope when neither `this' nor any variable is hoisted
1770 // 3, an instance method in compiler generated storey when any hoisted variable exists
1773 Modifiers modifiers
;
1774 TypeDefinition parent
= null;
1775 TypeParameters hoisted_tparams
= null;
1776 ParametersCompiled method_parameters
= parameters
;
1778 var src_block
= Block
.Original
.Explicit
;
1779 if (src_block
.HasCapturedVariable
|| src_block
.HasCapturedThis
) {
1780 parent
= storey
= FindBestMethodStorey ();
1782 if (storey
== null) {
1783 var top_block
= src_block
.ParametersBlock
.TopBlock
;
1784 var sm
= top_block
.StateMachine
;
1786 if (src_block
.HasCapturedThis
) {
1788 // Remove hoisted 'this' request when simple instance method is
1789 // enough. No hoisted variables only 'this' and don't need to
1790 // propagate this to value type state machine.
1792 StateMachine sm_parent
;
1793 var pb
= src_block
.ParametersBlock
;
1795 sm_parent
= pb
.StateMachine
;
1796 pb
= pb
.Parent
== null ? null : pb
.Parent
.ParametersBlock
;
1797 } while (sm_parent
== null && pb
!= null);
1799 if (sm_parent
== null) {
1800 top_block
.RemoveThisReferenceFromChildrenBlock (src_block
);
1801 } else if (sm_parent
.Kind
== MemberKind
.Struct
) {
1803 // Special case where parent class is used to emit instance method
1804 // because currect storey is of value type (async host) and we cannot
1805 // use ldftn on non-boxed instances either to share mutated state
1807 parent
= sm_parent
.Parent
.PartialContainer
;
1808 hoisted_tparams
= sm_parent
.OriginalTypeParameters
;
1809 } else if (sm
is IteratorStorey
) {
1811 // For iterators we can host everything in one class
1813 parent
= storey
= sm
;
1816 } else if (src_block
.ParametersBlock
.HasReferenceToStoreyForInstanceLambdas
) {
1817 src_block
.ParametersBlock
.StateMachine
.AddParentStoreyReference (ec
, storey
);
1820 modifiers
= storey
!= null ? Modifiers
.INTERNAL
: Modifiers
.PRIVATE
;
1822 if (ec
.CurrentAnonymousMethod
!= null)
1823 parent
= storey
= ec
.CurrentAnonymousMethod
.Storey
;
1825 modifiers
= Modifiers
.STATIC
| Modifiers
.PRIVATE
;
1828 // Convert generated method to closed delegate method where unused
1829 // this argument is generated during compilation which speeds up dispatch
1832 // Unused as it breaks compatibility
1834 // method_parameters = ParametersCompiled.Prefix (method_parameters,
1835 // new Parameter (null, null, 0, null, loc), ec.Module.Compiler.BuiltinTypes.Object);
1838 if (storey
== null && hoisted_tparams
== null)
1839 hoisted_tparams
= ec
.CurrentTypeParameters
;
1842 parent
= ec
.CurrentTypeDefinition
.Parent
.PartialContainer
;
1844 string name
= CompilerGeneratedContainer
.MakeName (parent
!= storey
? block_name
: null,
1845 "m", null, parent
.PartialContainer
.CounterAnonymousMethods
++);
1847 MemberName member_name
;
1848 if (hoisted_tparams
!= null) {
1849 var type_params
= new TypeParameters (hoisted_tparams
.Count
);
1850 for (int i
= 0; i
< hoisted_tparams
.Count
; ++i
) {
1851 type_params
.Add (hoisted_tparams
[i
].CreateHoistedCopy (null));
1854 member_name
= new MemberName (name
, type_params
, Location
);
1856 member_name
= new MemberName (name
, Location
);
1859 return new AnonymousMethodMethod (parent
,
1860 this, storey
, new TypeExpression (ReturnType
, Location
), modifiers
,
1861 member_name
, method_parameters
);
1864 protected override Expression
DoResolve (ResolveContext ec
)
1869 eclass
= ExprClass
.Value
;
1873 public override void Emit (EmitContext ec
)
1876 // Use same anonymous method implementation for scenarios where same
1877 // code is used from multiple blocks, e.g. field initializers
1879 if (method
== null) {
1881 // Delay an anonymous method definition to avoid emitting unused code
1882 // for unreachable blocks or expression trees
1884 method
= DoCreateMethodHost (ec
);
1886 method
.PrepareEmit ();
1889 bool is_static
= (method
.ModFlags
& Modifiers
.STATIC
) != 0;
1890 if (is_static
&& am_cache
== null && !ec
.IsStaticConstructor
) {
1892 // Creates a field cache to store delegate instance if it's not generic
1894 if (!method
.MemberName
.IsGeneric
) {
1895 var parent
= method
.Parent
.PartialContainer
;
1896 int id
= parent
.AnonymousMethodsCounter
++;
1897 var cache_type
= storey
!= null && storey
.Mutator
!= null ? storey
.Mutator
.Mutate (type
) : type
;
1899 am_cache
= new Field (parent
, new TypeExpression (cache_type
, loc
),
1900 Modifiers
.STATIC
| Modifiers
.PRIVATE
| Modifiers
.COMPILER_GENERATED
,
1901 new MemberName (CompilerGeneratedContainer
.MakeName (null, "f", "am$cache", id
), loc
), null);
1903 parent
.AddField (am_cache
);
1905 // TODO: Implement caching of generated generic static methods
1909 // Some extra class is needed to capture variable generic type
1910 // arguments. Maybe we could re-use anonymous types, with a unique
1911 // anonymous method id, but they are quite heavy.
1913 // Consider : "() => typeof(T);"
1915 // We need something like
1916 // static class Wrap<Tn, Tm, DelegateType> {
1917 // public static DelegateType cache;
1920 // We then specialize local variable to capture all generic parameters
1921 // and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
1926 Label l_initialized
= ec
.DefineLabel ();
1928 if (am_cache
!= null) {
1929 ec
.Emit (OpCodes
.Ldsfld
, am_cache
.Spec
);
1930 ec
.Emit (OpCodes
.Brtrue_S
, l_initialized
);
1934 // Load method delegate implementation
1939 } else if (storey
!= null) {
1940 Expression e
= storey
.GetStoreyInstanceExpression (ec
).Resolve (new ResolveContext (ec
.MemberContext
));
1948 // Special case for value type storey where this is not lifted but
1949 // droped off to parent class
1951 if (ec
.CurrentAnonymousMethod
!= null && ec
.AsyncTaskStorey
!= null)
1952 ec
.Emit (OpCodes
.Ldfld
, ec
.AsyncTaskStorey
.HoistedThis
.Field
.Spec
);
1955 var delegate_method
= method
.Spec
;
1956 if (storey
!= null && storey
.MemberName
.IsGeneric
) {
1958 // Mutate anonymous method instance type if we are in nested
1959 // hoisted generic anonymous method storey
1961 if (ec
.IsAnonymousStoreyMutateRequired
) {
1962 ec
.Emit (OpCodes
.Ldftn
, delegate_method
);
1964 TypeSpec t
= storey
.Instance
.Type
;
1965 ec
.Emit (OpCodes
.Ldftn
, TypeBuilder
.GetMethod (t
.GetMetaInfo (), (MethodInfo
) delegate_method
.GetMetaInfo ()));
1968 if (delegate_method
.IsGeneric
) {
1969 TypeParameterSpec
[] tparams
;
1970 var sm
= ec
.CurrentAnonymousMethod
== null ? null : ec
.CurrentAnonymousMethod
.Storey
as StateMachine
;
1971 if (sm
!= null && sm
.OriginalTypeParameters
!= null) {
1972 tparams
= sm
.CurrentTypeParameters
.Types
;
1974 tparams
= method
.TypeParameters
;
1977 delegate_method
= delegate_method
.MakeGenericMethod (ec
.MemberContext
, tparams
);
1980 ec
.Emit (OpCodes
.Ldftn
, delegate_method
);
1983 var constructor_method
= Delegate
.GetConstructor (type
);
1984 ec
.Emit (OpCodes
.Newobj
, constructor_method
);
1986 if (am_cache
!= null) {
1987 ec
.Emit (OpCodes
.Stsfld
, am_cache
.Spec
);
1988 ec
.MarkLabel (l_initialized
);
1989 ec
.Emit (OpCodes
.Ldsfld
, am_cache
.Spec
);
1993 public override void EmitStatement (EmitContext ec
)
1995 throw new NotImplementedException ();
1999 // Look for the best storey for this anonymous method
2001 AnonymousMethodStorey
FindBestMethodStorey ()
2004 // Use the nearest parent block which has a storey
2006 for (Block b
= Block
.Parent
; b
!= null; b
= b
.Parent
) {
2007 AnonymousMethodStorey s
= b
.Explicit
.AnonymousMethodStorey
;
2015 public override string GetSignatureForError ()
2017 return type
.GetSignatureForError ();
2022 // Anonymous type container
2024 public class AnonymousTypeClass
: CompilerGeneratedContainer
2026 public const string ClassNamePrefix
= "<>__AnonType";
2027 public const string SignatureForError
= "anonymous type";
2029 readonly IList
<AnonymousTypeParameter
> parameters
;
2031 private AnonymousTypeClass (ModuleContainer parent
, MemberName name
, IList
<AnonymousTypeParameter
> parameters
, Location loc
)
2032 : base (parent
, name
, parent
.Evaluator
!= null ? Modifiers
.PUBLIC
: Modifiers
.INTERNAL
)
2034 this.parameters
= parameters
;
2037 public static AnonymousTypeClass
Create (TypeContainer parent
, IList
<AnonymousTypeParameter
> parameters
, Location loc
)
2039 string name
= ClassNamePrefix
+ parent
.Module
.CounterAnonymousTypes
++;
2041 ParametersCompiled all_parameters
;
2042 TypeParameters tparams
= null;
2043 SimpleName
[] t_args
;
2045 if (parameters
.Count
== 0) {
2046 all_parameters
= ParametersCompiled
.EmptyReadOnlyParameters
;
2049 t_args
= new SimpleName
[parameters
.Count
];
2050 tparams
= new TypeParameters ();
2051 Parameter
[] ctor_params
= new Parameter
[parameters
.Count
];
2052 for (int i
= 0; i
< parameters
.Count
; ++i
) {
2053 AnonymousTypeParameter p
= parameters
[i
];
2054 for (int ii
= 0; ii
< i
; ++ii
) {
2055 if (parameters
[ii
].Name
== p
.Name
) {
2056 parent
.Compiler
.Report
.Error (833, parameters
[ii
].Location
,
2057 "`{0}': An anonymous type cannot have multiple properties with the same name",
2060 p
= new AnonymousTypeParameter (null, "$" + i
.ToString (), p
.Location
);
2066 t_args
[i
] = new SimpleName ("<" + p
.Name
+ ">__T", p
.Location
);
2067 tparams
.Add (new TypeParameter (i
, new MemberName (t_args
[i
].Name
, p
.Location
), null, null, Variance
.None
));
2068 ctor_params
[i
] = new Parameter (t_args
[i
], p
.Name
, Parameter
.Modifier
.NONE
, null, p
.Location
);
2071 all_parameters
= new ParametersCompiled (ctor_params
);
2075 // Create generic anonymous type host with generic arguments
2076 // named upon properties names
2078 AnonymousTypeClass a_type
= new AnonymousTypeClass (parent
.Module
, new MemberName (name
, tparams
, loc
), parameters
, loc
);
2080 Constructor c
= new Constructor (a_type
, name
, Modifiers
.PUBLIC
| Modifiers
.DEBUGGER_HIDDEN
,
2081 null, all_parameters
, loc
);
2082 c
.Block
= new ToplevelBlock (parent
.Module
.Compiler
, c
.ParameterInfo
, loc
);
2085 // Create fields and constructor body with field initialization
2088 for (int i
= 0; i
< parameters
.Count
; ++i
) {
2089 AnonymousTypeParameter p
= parameters
[i
];
2091 Field f
= new Field (a_type
, t_args
[i
], Modifiers
.PRIVATE
| Modifiers
.READONLY
| Modifiers
.DEBUGGER_HIDDEN
,
2092 new MemberName ("<" + p
.Name
+ ">", p
.Location
), null);
2094 if (!a_type
.AddField (f
)) {
2099 c
.Block
.AddStatement (new StatementExpression (
2100 new SimpleAssign (new MemberAccess (new This (p
.Location
), f
.Name
),
2101 c
.Block
.GetParameterReference (i
, p
.Location
))));
2103 ToplevelBlock get_block
= new ToplevelBlock (parent
.Module
.Compiler
, p
.Location
);
2104 get_block
.AddStatement (new Return (
2105 new MemberAccess (new This (p
.Location
), f
.Name
), p
.Location
));
2107 Property prop
= new Property (a_type
, t_args
[i
], Modifiers
.PUBLIC
,
2108 new MemberName (p
.Name
, p
.Location
), null);
2109 prop
.Get
= new Property
.GetMethod (prop
, 0, null, p
.Location
);
2110 prop
.Get
.Block
= get_block
;
2111 a_type
.AddMember (prop
);
2117 a_type
.AddConstructor (c
);
2121 protected override bool DoDefineMembers ()
2123 if (!base.DoDefineMembers ())
2126 Location loc
= Location
;
2128 var equals_parameters
= ParametersCompiled
.CreateFullyResolved (
2129 new Parameter (new TypeExpression (Compiler
.BuiltinTypes
.Object
, loc
), "obj", 0, null, loc
), Compiler
.BuiltinTypes
.Object
);
2131 Method equals
= new Method (this, new TypeExpression (Compiler
.BuiltinTypes
.Bool
, loc
),
2132 Modifiers
.PUBLIC
| Modifiers
.OVERRIDE
| Modifiers
.DEBUGGER_HIDDEN
, new MemberName ("Equals", loc
),
2133 equals_parameters
, null);
2135 equals_parameters
[0].Resolve (equals
, 0);
2137 Method tostring
= new Method (this, new TypeExpression (Compiler
.BuiltinTypes
.String
, loc
),
2138 Modifiers
.PUBLIC
| Modifiers
.OVERRIDE
| Modifiers
.DEBUGGER_HIDDEN
, new MemberName ("ToString", loc
),
2139 ParametersCompiled
.EmptyReadOnlyParameters
, null);
2141 ToplevelBlock equals_block
= new ToplevelBlock (Compiler
, equals
.ParameterInfo
, loc
);
2143 TypeExpr current_type
;
2144 if (CurrentTypeParameters
!= null) {
2145 var targs
= new TypeArguments ();
2146 for (int i
= 0; i
< CurrentTypeParameters
.Count
; ++i
) {
2147 targs
.Add (new TypeParameterExpr (CurrentTypeParameters
[i
], Location
));
2150 current_type
= new GenericTypeExpr (Definition
, targs
, loc
);
2152 current_type
= new TypeExpression (Definition
, loc
);
2155 var li_other
= LocalVariable
.CreateCompilerGenerated (CurrentType
, equals_block
, loc
);
2156 equals_block
.AddStatement (new BlockVariable (new TypeExpression (li_other
.Type
, loc
), li_other
));
2157 var other_variable
= new LocalVariableReference (li_other
, loc
);
2159 MemberAccess system_collections_generic
= new MemberAccess (new MemberAccess (
2160 new QualifiedAliasMember ("global", "System", loc
), "Collections", loc
), "Generic", loc
);
2162 Expression rs_equals
= null;
2163 Expression string_concat
= new StringConstant (Compiler
.BuiltinTypes
, "{", loc
);
2164 Expression rs_hashcode
= new IntConstant (Compiler
.BuiltinTypes
, -2128831035, loc
);
2165 for (int i
= 0; i
< parameters
.Count
; ++i
) {
2166 var p
= parameters
[i
];
2167 var f
= (Field
) Members
[i
* 2];
2169 MemberAccess equality_comparer
= new MemberAccess (new MemberAccess (
2170 system_collections_generic
, "EqualityComparer",
2171 new TypeArguments (new SimpleName (CurrentTypeParameters
[i
].Name
, loc
)), loc
),
2174 Arguments arguments_equal
= new Arguments (2);
2175 arguments_equal
.Add (new Argument (new MemberAccess (new This (f
.Location
), f
.Name
)));
2176 arguments_equal
.Add (new Argument (new MemberAccess (other_variable
, f
.Name
)));
2178 Expression field_equal
= new Invocation (new MemberAccess (equality_comparer
,
2179 "Equals", loc
), arguments_equal
);
2181 Arguments arguments_hashcode
= new Arguments (1);
2182 arguments_hashcode
.Add (new Argument (new MemberAccess (new This (f
.Location
), f
.Name
)));
2183 Expression field_hashcode
= new Invocation (new MemberAccess (equality_comparer
,
2184 "GetHashCode", loc
), arguments_hashcode
);
2186 IntConstant FNV_prime
= new IntConstant (Compiler
.BuiltinTypes
, 16777619, loc
);
2187 rs_hashcode
= new Binary (Binary
.Operator
.Multiply
,
2188 new Binary (Binary
.Operator
.ExclusiveOr
, rs_hashcode
, field_hashcode
),
2191 Expression field_to_string
= new Conditional (new BooleanExpression (new Binary (Binary
.Operator
.Inequality
,
2192 new MemberAccess (new This (f
.Location
), f
.Name
), new NullLiteral (loc
))),
2193 new Invocation (new MemberAccess (
2194 new MemberAccess (new This (f
.Location
), f
.Name
), "ToString"), null),
2195 new StringConstant (Compiler
.BuiltinTypes
, string.Empty
, loc
), loc
);
2197 if (rs_equals
== null) {
2198 rs_equals
= field_equal
;
2199 string_concat
= new Binary (Binary
.Operator
.Addition
,
2201 new Binary (Binary
.Operator
.Addition
,
2202 new StringConstant (Compiler
.BuiltinTypes
, " " + p
.Name
+ " = ", loc
),
2208 // Implementation of ToString () body using string concatenation
2210 string_concat
= new Binary (Binary
.Operator
.Addition
,
2211 new Binary (Binary
.Operator
.Addition
,
2213 new StringConstant (Compiler
.BuiltinTypes
, ", " + p
.Name
+ " = ", loc
)),
2216 rs_equals
= new Binary (Binary
.Operator
.LogicalAnd
, rs_equals
, field_equal
);
2219 string_concat
= new Binary (Binary
.Operator
.Addition
,
2221 new StringConstant (Compiler
.BuiltinTypes
, " }", loc
));
2224 // Equals (object obj) override
2226 var other_variable_assign
= new TemporaryVariableReference (li_other
, loc
);
2227 equals_block
.AddStatement (new StatementExpression (
2228 new SimpleAssign (other_variable_assign
,
2229 new As (equals_block
.GetParameterReference (0, loc
),
2230 current_type
, loc
), loc
)));
2232 Expression equals_test
= new Binary (Binary
.Operator
.Inequality
, other_variable
, new NullLiteral (loc
));
2233 if (rs_equals
!= null)
2234 equals_test
= new Binary (Binary
.Operator
.LogicalAnd
, equals_test
, rs_equals
);
2235 equals_block
.AddStatement (new Return (equals_test
, loc
));
2237 equals
.Block
= equals_block
;
2239 Members
.Add (equals
);
2242 // GetHashCode () override
2244 Method hashcode
= new Method (this, new TypeExpression (Compiler
.BuiltinTypes
.Int
, loc
),
2245 Modifiers
.PUBLIC
| Modifiers
.OVERRIDE
| Modifiers
.DEBUGGER_HIDDEN
,
2246 new MemberName ("GetHashCode", loc
),
2247 ParametersCompiled
.EmptyReadOnlyParameters
, null);
2250 // Modified FNV with good avalanche behavior and uniform
2251 // distribution with larger hash sizes.
2253 // const int FNV_prime = 16777619;
2254 // int hash = (int) 2166136261;
2255 // foreach (int d in data)
2256 // hash = (hash ^ d) * FNV_prime;
2257 // hash += hash << 13;
2258 // hash ^= hash >> 7;
2259 // hash += hash << 3;
2260 // hash ^= hash >> 17;
2261 // hash += hash << 5;
2263 ToplevelBlock hashcode_top
= new ToplevelBlock (Compiler
, loc
);
2264 Block hashcode_block
= new Block (hashcode_top
, loc
, loc
);
2265 hashcode_top
.AddStatement (new Unchecked (hashcode_block
, loc
));
2267 var li_hash
= LocalVariable
.CreateCompilerGenerated (Compiler
.BuiltinTypes
.Int
, hashcode_top
, loc
);
2268 hashcode_block
.AddStatement (new BlockVariable (new TypeExpression (li_hash
.Type
, loc
), li_hash
));
2269 LocalVariableReference hash_variable_assign
= new LocalVariableReference (li_hash
, loc
);
2270 hashcode_block
.AddStatement (new StatementExpression (
2271 new SimpleAssign (hash_variable_assign
, rs_hashcode
)));
2273 var hash_variable
= new LocalVariableReference (li_hash
, loc
);
2274 hashcode_block
.AddStatement (new StatementExpression (
2275 new CompoundAssign (Binary
.Operator
.Addition
, hash_variable
,
2276 new Binary (Binary
.Operator
.LeftShift
, hash_variable
, new IntConstant (Compiler
.BuiltinTypes
, 13, loc
)))));
2277 hashcode_block
.AddStatement (new StatementExpression (
2278 new CompoundAssign (Binary
.Operator
.ExclusiveOr
, hash_variable
,
2279 new Binary (Binary
.Operator
.RightShift
, hash_variable
, new IntConstant (Compiler
.BuiltinTypes
, 7, loc
)))));
2280 hashcode_block
.AddStatement (new StatementExpression (
2281 new CompoundAssign (Binary
.Operator
.Addition
, hash_variable
,
2282 new Binary (Binary
.Operator
.LeftShift
, hash_variable
, new IntConstant (Compiler
.BuiltinTypes
, 3, loc
)))));
2283 hashcode_block
.AddStatement (new StatementExpression (
2284 new CompoundAssign (Binary
.Operator
.ExclusiveOr
, hash_variable
,
2285 new Binary (Binary
.Operator
.RightShift
, hash_variable
, new IntConstant (Compiler
.BuiltinTypes
, 17, loc
)))));
2286 hashcode_block
.AddStatement (new StatementExpression (
2287 new CompoundAssign (Binary
.Operator
.Addition
, hash_variable
,
2288 new Binary (Binary
.Operator
.LeftShift
, hash_variable
, new IntConstant (Compiler
.BuiltinTypes
, 5, loc
)))));
2290 hashcode_block
.AddStatement (new Return (hash_variable
, loc
));
2291 hashcode
.Block
= hashcode_top
;
2293 Members
.Add (hashcode
);
2296 // ToString () override
2299 ToplevelBlock tostring_block
= new ToplevelBlock (Compiler
, loc
);
2300 tostring_block
.AddStatement (new Return (string_concat
, loc
));
2301 tostring
.Block
= tostring_block
;
2303 Members
.Add (tostring
);
2308 public override string GetSignatureForError ()
2310 return SignatureForError
;
2313 public override CompilationSourceFile
GetCompilationSourceFile ()
2318 public IList
<AnonymousTypeParameter
> Parameters
{