2 // generic.cs: Generics support
4 // Authors: Martin Baulig (martin@ximian.com)
5 // Miguel de Icaza (miguel@ximian.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
10 // (C) 2004 Novell, Inc
13 using System
.Reflection
;
14 using System
.Reflection
.Emit
;
15 using System
.Globalization
;
16 using System
.Collections
;
18 using System
.Text
.RegularExpressions
;
20 namespace Mono
.CSharp
{
22 public abstract class GenericConstraints
{
23 public abstract GenericParameterAttributes Attributes
{
27 public bool HasConstructorConstraint
{
28 get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
31 public bool HasReferenceTypeConstraint
{
32 get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
35 public bool HasValueTypeConstraint
{
36 get { return (Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; }
39 public virtual bool HasClassConstraint
{
40 get { return ClassConstraint != null; }
43 public abstract Type ClassConstraint
{
47 public abstract Type
[] InterfaceConstraints
{
51 public abstract Type EffectiveBaseClass
{
56 // Returns whether the type parameter is "known to be a reference type".
58 public virtual bool IsReferenceType
{
60 if (HasReferenceTypeConstraint
)
62 if (HasValueTypeConstraint
)
65 if (ClassConstraint
!= null) {
66 if (ClassConstraint
.IsValueType
)
69 if (ClassConstraint
!= TypeManager
.object_type
)
73 foreach (Type t
in InterfaceConstraints
) {
74 if (!t
.IsGenericParameter
)
77 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (t
);
78 if ((gc
!= null) && gc
.IsReferenceType
)
87 // Returns whether the type parameter is "known to be a value type".
89 public virtual bool IsValueType
{
91 if (HasValueTypeConstraint
)
93 if (HasReferenceTypeConstraint
)
96 if (ClassConstraint
!= null) {
97 if (!ClassConstraint
.IsValueType
)
100 if (ClassConstraint
!= TypeManager
.value_type
)
104 foreach (Type t
in InterfaceConstraints
) {
105 if (!t
.IsGenericParameter
)
108 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (t
);
109 if ((gc
!= null) && gc
.IsValueType
)
118 public enum SpecialConstraint
126 // Tracks the constraints for a type parameter
128 public class Constraints
: GenericConstraints
{
130 ArrayList constraints
;
134 // name is the identifier, constraints is an arraylist of
135 // Expressions (with types) or `true' for the constructor constraint.
137 public Constraints (string name
, ArrayList constraints
,
141 this.constraints
= constraints
;
145 public string TypeParameter
{
151 GenericParameterAttributes attrs
;
152 TypeExpr class_constraint
;
153 ArrayList iface_constraints
;
154 ArrayList type_param_constraints
;
155 int num_constraints
, first_constraint
;
156 Type class_constraint_type
;
157 Type
[] iface_constraint_types
;
158 Type effective_base_type
;
160 public bool Resolve (EmitContext ec
)
162 iface_constraints
= new ArrayList ();
163 type_param_constraints
= new ArrayList ();
165 foreach (object obj
in constraints
) {
166 if (HasConstructorConstraint
) {
167 Report
.Error (401, loc
,
168 "The new() constraint must be last.");
172 if (obj
is SpecialConstraint
) {
173 SpecialConstraint sc
= (SpecialConstraint
) obj
;
175 if (sc
== SpecialConstraint
.Constructor
) {
176 if (!HasValueTypeConstraint
) {
177 attrs
|= GenericParameterAttributes
.DefaultConstructorConstraint
;
182 451, loc
, "The new () constraint " +
183 "cannot be used with the `struct' " +
188 if ((num_constraints
> 0) || HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
189 Report
.Error (449, loc
,
190 "The `class' or `struct' " +
191 "constraint must be first");
195 if (sc
== SpecialConstraint
.ReferenceType
)
196 attrs
|= GenericParameterAttributes
.ReferenceTypeConstraint
;
198 attrs
|= GenericParameterAttributes
.NotNullableValueTypeConstraint
;
203 if (obj
is ConstructedType
) {
204 ConstructedType cexpr
= (ConstructedType
) obj
;
205 if (!cexpr
.ResolveConstructedType (ec
))
209 expr
= ((Expression
) obj
).ResolveAsTypeTerminal (ec
);
214 TypeParameterExpr texpr
= expr
as TypeParameterExpr
;
216 type_param_constraints
.Add (expr
);
217 else if (expr
.IsInterface
)
218 iface_constraints
.Add (expr
);
219 else if (class_constraint
!= null) {
220 Report
.Error (406, loc
,
221 "`{0}': the class constraint for `{1}' " +
222 "must come before any other constraints.",
225 } else if (HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
226 Report
.Error (450, loc
, "`{0}': cannot specify both " +
227 "a constraint class and the `class' " +
228 "or `struct' constraint.", expr
.Name
);
231 class_constraint
= expr
;
239 bool CheckTypeParameterConstraints (TypeParameter tparam
, Hashtable seen
)
241 seen
.Add (tparam
, true);
243 Constraints constraints
= tparam
.Constraints
;
244 if (constraints
== null)
247 if (constraints
.HasValueTypeConstraint
) {
248 Report
.Error (456, loc
, "Type parameter `{0}' has " +
249 "the `struct' constraint, so it cannot " +
250 "be used as a constraint for `{1}'",
255 if (constraints
.type_param_constraints
== null)
258 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
259 if (seen
.Contains (expr
.TypeParameter
)) {
260 Report
.Error (454, loc
, "Circular constraint " +
261 "dependency involving `{0}' and `{1}'",
262 tparam
.Name
, expr
.Name
);
266 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
273 public bool ResolveTypes (EmitContext ec
)
275 if (effective_base_type
!= null)
278 foreach (object obj
in constraints
) {
279 ConstructedType cexpr
= obj
as ConstructedType
;
283 if (!cexpr
.CheckConstraints (ec
))
287 foreach (TypeParameterExpr expr
in type_param_constraints
) {
288 Hashtable seen
= new Hashtable ();
289 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
293 ArrayList list
= new ArrayList ();
295 foreach (TypeExpr iface_constraint
in iface_constraints
) {
296 foreach (Type type
in list
) {
297 if (!type
.Equals (iface_constraint
.Type
))
300 Report
.Error (405, loc
,
301 "Duplicate constraint `{0}' for type " +
302 "parameter `{1}'.", iface_constraint
.Type
,
307 list
.Add (iface_constraint
.Type
);
310 foreach (TypeParameterExpr expr
in type_param_constraints
) {
311 foreach (Type type
in list
) {
312 if (!type
.Equals (expr
.Type
))
315 Report
.Error (405, loc
,
316 "Duplicate constraint `{0}' for type " +
317 "parameter `{1}'.", expr
.Type
, name
);
321 list
.Add (expr
.Type
);
324 iface_constraint_types
= new Type
[list
.Count
];
325 list
.CopyTo (iface_constraint_types
, 0);
327 if (class_constraint
!= null) {
328 class_constraint_type
= class_constraint
.Type
;
329 if (class_constraint_type
== null)
332 if (class_constraint_type
.IsSealed
) {
333 Report
.Error (701, loc
,
334 "`{0}' is not a valid bound. Bounds " +
335 "must be interfaces or non sealed " +
336 "classes", class_constraint_type
);
340 if ((class_constraint_type
== TypeManager
.array_type
) ||
341 (class_constraint_type
== TypeManager
.delegate_type
) ||
342 (class_constraint_type
== TypeManager
.enum_type
) ||
343 (class_constraint_type
== TypeManager
.value_type
) ||
344 (class_constraint_type
== TypeManager
.object_type
)) {
345 Report
.Error (702, loc
,
346 "Bound cannot be special class `{0}'",
347 class_constraint_type
);
352 if (class_constraint_type
!= null)
353 effective_base_type
= class_constraint_type
;
354 else if (HasValueTypeConstraint
)
355 effective_base_type
= TypeManager
.value_type
;
357 effective_base_type
= TypeManager
.object_type
;
362 public bool CheckDependencies (EmitContext ec
)
364 foreach (TypeParameterExpr expr
in type_param_constraints
) {
365 if (!CheckDependencies (expr
.TypeParameter
, ec
))
372 bool CheckDependencies (TypeParameter tparam
, EmitContext ec
)
374 Constraints constraints
= tparam
.Constraints
;
375 if (constraints
== null)
378 if (HasValueTypeConstraint
&& constraints
.HasClassConstraint
) {
379 Report
.Error (455, loc
, "Type parameter `{0}' inherits " +
380 "conflicting constraints `{1}' and `{2}'",
381 name
, constraints
.ClassConstraint
,
386 if (HasClassConstraint
&& constraints
.HasClassConstraint
) {
387 Type t1
= ClassConstraint
;
388 TypeExpr e1
= class_constraint
;
389 Type t2
= constraints
.ClassConstraint
;
390 TypeExpr e2
= constraints
.class_constraint
;
392 if (!Convert
.WideningReferenceConversionExists (ec
, e1
, t2
) &&
393 !Convert
.WideningReferenceConversionExists (ec
, e2
, t1
)) {
394 Report
.Error (455, loc
,
395 "Type parameter `{0}' inherits " +
396 "conflicting constraints `{1}' and `{2}'",
402 if (constraints
.type_param_constraints
== null)
405 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
406 if (!CheckDependencies (expr
.TypeParameter
, ec
))
413 public void Define (GenericTypeParameterBuilder type
)
415 type
.SetGenericParameterAttributes (attrs
);
418 public override GenericParameterAttributes Attributes
{
419 get { return attrs; }
422 public override bool HasClassConstraint
{
423 get { return class_constraint != null; }
426 public override Type ClassConstraint
{
427 get { return class_constraint_type; }
430 public override Type
[] InterfaceConstraints
{
431 get { return iface_constraint_types; }
434 public override Type EffectiveBaseClass
{
435 get { return effective_base_type; }
438 internal bool IsSubclassOf (Type t
)
440 if ((class_constraint_type
!= null) &&
441 class_constraint_type
.IsSubclassOf (t
))
444 if (iface_constraint_types
== null)
447 foreach (Type iface
in iface_constraint_types
) {
448 if (TypeManager
.IsSubclassOf (iface
, t
))
455 public bool CheckInterfaceMethod (EmitContext ec
, GenericConstraints gc
)
457 if (gc
.Attributes
!= attrs
)
460 if (HasClassConstraint
!= gc
.HasClassConstraint
)
462 if (HasClassConstraint
&& !TypeManager
.IsEqual (gc
.ClassConstraint
, ClassConstraint
))
465 int gc_icount
= gc
.InterfaceConstraints
!= null ?
466 gc
.InterfaceConstraints
.Length
: 0;
467 int icount
= InterfaceConstraints
!= null ?
468 InterfaceConstraints
.Length
: 0;
470 if (gc_icount
!= icount
)
473 foreach (Type iface
in gc
.InterfaceConstraints
) {
475 foreach (Type check
in InterfaceConstraints
) {
476 if (TypeManager
.IsEqual (iface
, check
)) {
491 // This type represents a generic type parameter
493 public class TypeParameter
: MemberCore
, IMemberContainer
{
495 GenericConstraints gc
;
496 Constraints constraints
;
498 GenericTypeParameterBuilder type
;
500 public TypeParameter (TypeContainer parent
, string name
,
501 Constraints constraints
, Location loc
)
502 : base (parent
, new MemberName (name
), null, loc
)
505 this.constraints
= constraints
;
509 public GenericConstraints GenericConstraints
{
511 return gc
!= null ? gc
: constraints
;
515 public Constraints Constraints
{
521 public bool HasConstructorConstraint
{
523 if (constraints
!= null)
524 return constraints
.HasConstructorConstraint
;
536 public bool Resolve (DeclSpace ds
)
538 if (constraints
!= null) {
539 if (!constraints
.Resolve (ds
.EmitContext
)) {
548 public void Define (GenericTypeParameterBuilder type
)
550 if (this.type
!= null)
551 throw new InvalidOperationException ();
554 TypeManager
.AddTypeParameter (type
, this);
557 public void DefineConstraints ()
559 if (constraints
!= null)
560 constraints
.Define (type
);
563 public bool ResolveType (EmitContext ec
)
565 if (constraints
!= null) {
566 if (!constraints
.ResolveTypes (ec
)) {
575 public bool DefineType (EmitContext ec
)
577 return DefineType (ec
, null, null, false);
580 public bool DefineType (EmitContext ec
, MethodBuilder builder
,
581 MethodInfo implementing
, bool is_override
)
583 if (!ResolveType (ec
))
586 if (implementing
!= null) {
587 if (is_override
&& (constraints
!= null)) {
589 460, loc
, "Constraints for override and " +
590 "explicit interface implementation methods " +
591 "are inherited from the base method so they " +
592 "cannot be specified directly");
596 MethodBase mb
= implementing
;
597 if (mb
.Mono_IsInflatedMethod
)
598 mb
= mb
.GetGenericMethodDefinition ();
600 int pos
= type
.GenericParameterPosition
;
601 ParameterData pd
= Invocation
.GetParameterData (mb
);
602 GenericConstraints temp_gc
= pd
.GenericConstraints (pos
);
603 Type mparam
= mb
.GetGenericArguments () [pos
];
606 gc
= new InflatedConstraints (temp_gc
, implementing
.DeclaringType
);
607 else if (constraints
!= null)
608 gc
= new InflatedConstraints (constraints
, implementing
.DeclaringType
);
611 if (constraints
!= null) {
614 else if (!constraints
.CheckInterfaceMethod (ec
, gc
))
617 if (!is_override
&& (temp_gc
!= null))
622 Report
.SymbolRelatedToPreviousError (implementing
);
625 425, loc
, "The constraints for type " +
626 "parameter `{0}' of method `{1}' must match " +
627 "the constraints for type parameter `{2}' " +
628 "of interface method `{3}'. Consider using " +
629 "an explicit interface implementation instead",
630 Name
, TypeManager
.CSharpSignature (builder
),
631 mparam
, TypeManager
.CSharpSignature (mb
));
635 gc
= (GenericConstraints
) constraints
;
641 if (gc
.HasClassConstraint
)
642 type
.SetBaseTypeConstraint (gc
.ClassConstraint
);
644 type
.SetInterfaceConstraints (gc
.InterfaceConstraints
);
645 TypeManager
.RegisterBuilder (type
, gc
.InterfaceConstraints
);
650 public bool CheckDependencies (EmitContext ec
)
652 if (constraints
!= null)
653 return constraints
.CheckDependencies (ec
);
658 public bool UpdateConstraints (EmitContext ec
, Constraints new_constraints
, bool check
)
661 // We're used in partial generic type definitions.
662 // If `check' is false, we just encountered the first ClassPart which has
663 // constraints - they become our "real" constraints.
664 // Otherwise we're called after the type parameters have already been defined
665 // and check whether the constraints are the same in all parts.
669 throw new InvalidOperationException ();
670 constraints
= new_constraints
;
675 throw new InvalidOperationException ();
677 if (constraints
== null)
678 return new_constraints
== null;
679 else if (new_constraints
== null)
682 if (!new_constraints
.Resolve (ec
))
684 if (!new_constraints
.ResolveTypes (ec
))
687 return constraints
.CheckInterfaceMethod (ec
, new_constraints
);
690 public override string DocCommentHeader
{
692 throw new InvalidOperationException (
693 "Unexpected attempt to get doc comment from " + this.GetType () + ".");
701 public override bool Define ()
706 protected override void VerifyObsoleteAttribute ()
709 public override void ApplyAttributeBuilder (Attribute a
,
710 CustomAttributeBuilder cb
)
713 public override AttributeTargets AttributeTargets
{
715 return (AttributeTargets
) 0;
719 public override string[] ValidAttributeTargets
{
721 return new string [0];
729 string IMemberContainer
.Name
{
733 MemberCache IMemberContainer
.BaseCache
{
737 bool IMemberContainer
.IsInterface
{
741 MemberList IMemberContainer
.GetMembers (MemberTypes mt
, BindingFlags bf
)
743 return FindMembers (mt
, bf
, null, null);
746 MemberCache IMemberContainer
.MemberCache
{
750 public MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
751 MemberFilter filter
, object criteria
)
753 if (constraints
== null)
754 return MemberList
.Empty
;
756 ArrayList members
= new ArrayList ();
758 GenericConstraints gc
= (GenericConstraints
) constraints
;
760 if (gc
.HasClassConstraint
) {
761 MemberList list
= TypeManager
.FindMembers (
762 gc
.ClassConstraint
, mt
, bf
, filter
, criteria
);
764 members
.AddRange (list
);
767 foreach (Type t
in gc
.InterfaceConstraints
) {
768 MemberList list
= TypeManager
.FindMembers (
769 t
, mt
, bf
, filter
, criteria
);
771 members
.AddRange (list
);
774 return new MemberList (members
);
777 public bool IsSubclassOf (Type t
)
782 if (constraints
!= null)
783 return constraints
.IsSubclassOf (t
);
788 public override string ToString ()
790 return "TypeParameter[" + name
+ "]";
793 protected class InflatedConstraints
: GenericConstraints
795 GenericConstraints gc
;
797 Type class_constraint
;
798 Type
[] iface_constraints
;
802 public InflatedConstraints (GenericConstraints gc
, Type declaring
)
805 this.declaring
= declaring
;
807 dargs
= TypeManager
.GetTypeArguments (declaring
);
809 ArrayList list
= new ArrayList ();
810 if (gc
.HasClassConstraint
)
811 list
.Add (inflate (gc
.ClassConstraint
));
812 foreach (Type iface
in gc
.InterfaceConstraints
)
813 list
.Add (inflate (iface
));
815 bool has_class_constr
= false;
816 if (list
.Count
> 0) {
817 Type first
= (Type
) list
[0];
818 has_class_constr
= !first
.IsInterface
&& !first
.IsGenericParameter
;
821 if ((list
.Count
> 0) && has_class_constr
) {
822 class_constraint
= (Type
) list
[0];
823 iface_constraints
= new Type
[list
.Count
- 1];
824 list
.CopyTo (1, iface_constraints
, 0, list
.Count
- 1);
826 iface_constraints
= new Type
[list
.Count
];
827 list
.CopyTo (iface_constraints
, 0);
830 if (HasValueTypeConstraint
)
831 base_type
= TypeManager
.value_type
;
832 else if (class_constraint
!= null)
833 base_type
= class_constraint
;
835 base_type
= TypeManager
.object_type
;
838 Type
inflate (Type t
)
842 if (t
.IsGenericParameter
)
843 return dargs
[t
.GenericParameterPosition
];
844 if (t
.IsGenericInstance
) {
845 t
= t
.GetGenericTypeDefinition ();
846 t
= t
.MakeGenericType (dargs
);
852 public override GenericParameterAttributes Attributes
{
853 get { return gc.Attributes; }
856 public override Type ClassConstraint
{
857 get { return class_constraint; }
860 public override Type EffectiveBaseClass
{
861 get { return base_type; }
864 public override Type
[] InterfaceConstraints
{
865 get { return iface_constraints; }
871 // This type represents a generic type parameter reference.
873 // These expressions are born in a fully resolved state.
875 public class TypeParameterExpr
: TypeExpr
{
876 TypeParameter type_parameter
;
878 public override string Name
{
880 return type_parameter
.Name
;
884 public override string FullName
{
886 return type_parameter
.Name
;
890 public TypeParameter TypeParameter
{
892 return type_parameter
;
896 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
898 this.type_parameter
= type_parameter
;
902 protected override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
904 type
= type_parameter
.Type
;
909 public override bool IsInterface
{
910 get { return false; }
913 public override bool CheckAccessLevel (DeclSpace ds
)
918 public void Error_CannotUseAsUnmanagedType (Location loc
)
920 Report
.Error (-203, loc
, "Can not use type parameter as unamanged type");
924 public class TypeArguments
{
925 public readonly Location Location
;
932 public TypeArguments (Location loc
)
934 args
= new ArrayList ();
938 public TypeArguments (int dimension
, Location loc
)
940 this.dimension
= dimension
;
944 public void Add (Expression type
)
947 throw new InvalidOperationException ();
952 public void Add (TypeArguments new_args
)
955 throw new InvalidOperationException ();
957 args
.AddRange (new_args
.args
);
960 public string[] GetDeclarations ()
962 string[] ret
= new string [args
.Count
];
963 for (int i
= 0; i
< args
.Count
; i
++) {
964 SimpleName sn
= args
[i
] as SimpleName
;
970 Report
.Error (81, Location
, "Type parameter declaration " +
971 "must be an identifier not a type");
977 public Type
[] Arguments
{
983 public bool HasTypeArguments
{
985 return has_type_args
;
998 public bool IsUnbound
{
1000 return dimension
> 0;
1004 public override string ToString ()
1006 StringBuilder s
= new StringBuilder ();
1009 for (int i
= 0; i
< count
; i
++){
1011 // FIXME: Use TypeManager.CSharpname once we have the type
1014 s
.Append (args
[i
].ToString ());
1018 return s
.ToString ();
1021 public bool Resolve (EmitContext ec
)
1023 int count
= args
.Count
;
1026 atypes
= new Type
[count
];
1028 for (int i
= 0; i
< count
; i
++){
1029 TypeExpr te
= ((Expression
) args
[i
]).ResolveAsTypeTerminal (ec
);
1034 if (te
is TypeParameterExpr
)
1035 has_type_args
= true;
1037 if (te
.Type
.IsPointer
) {
1038 Report
.Error (306, Location
, "The type `{0}' may not be used " +
1039 "as a type argument.", TypeManager
.CSharpName (te
.Type
));
1043 atypes
[i
] = te
.Type
;
1049 public class ConstructedType
: TypeExpr
{
1050 string name
, full_name
;
1052 Type
[] gen_params
, atypes
;
1055 public ConstructedType (string name
, TypeArguments args
, Location l
)
1058 this.name
= MemberName
.MakeName (name
, args
.Count
);
1061 eclass
= ExprClass
.Type
;
1062 full_name
= name
+ "<" + args
.ToString () + ">";
1065 public ConstructedType (string name
, TypeParameter
[] type_params
, Location l
)
1066 : this (type_params
, l
)
1071 full_name
= name
+ "<" + args
.ToString () + ">";
1074 public ConstructedType (FullNamedExpression fname
, TypeArguments args
, Location l
)
1077 this.name
= fname
.FullName
;
1080 eclass
= ExprClass
.Type
;
1081 full_name
= name
+ "<" + args
.ToString () + ">";
1084 protected ConstructedType (TypeArguments args
, Location l
)
1089 eclass
= ExprClass
.Type
;
1092 protected ConstructedType (TypeParameter
[] type_params
, Location l
)
1096 args
= new TypeArguments (l
);
1097 foreach (TypeParameter type_param
in type_params
)
1098 args
.Add (new TypeParameterExpr (type_param
, l
));
1100 eclass
= ExprClass
.Type
;
1103 public ConstructedType (Type t
, TypeParameter
[] type_params
, Location l
)
1104 : this (type_params
, l
)
1106 gt
= t
.GetGenericTypeDefinition ();
1108 this.name
= gt
.FullName
;
1109 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1112 public ConstructedType (Type t
, TypeArguments args
, Location l
)
1115 gt
= t
.GetGenericTypeDefinition ();
1117 this.name
= gt
.FullName
;
1118 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1121 public TypeArguments TypeArguments
{
1122 get { return args; }
1125 protected string DeclarationName
{
1127 StringBuilder sb
= new StringBuilder ();
1128 sb
.Append (gt
.FullName
);
1130 for (int i
= 0; i
< gen_params
.Length
; i
++) {
1133 sb
.Append (gen_params
[i
]);
1136 return sb
.ToString ();
1140 protected bool CheckConstraint (EmitContext ec
, Type ptype
, Expression expr
,
1143 if (TypeManager
.HasGenericArguments (ctype
)) {
1144 Type
[] types
= TypeManager
.GetTypeArguments (ctype
);
1146 TypeArguments new_args
= new TypeArguments (loc
);
1148 for (int i
= 0; i
< types
.Length
; i
++) {
1151 if (t
.IsGenericParameter
) {
1152 int pos
= t
.GenericParameterPosition
;
1153 t
= args
.Arguments
[pos
];
1155 new_args
.Add (new TypeExpression (t
, loc
));
1158 TypeExpr ct
= new ConstructedType (ctype
, new_args
, loc
);
1159 if (ct
.ResolveAsTypeTerminal (ec
) == null)
1164 return Convert
.WideningStandardConversionExists (ec
, expr
, ctype
);
1167 protected bool CheckConstraints (EmitContext ec
, int index
)
1169 Type atype
= atypes
[index
];
1170 Type ptype
= gen_params
[index
];
1175 Expression aexpr
= new EmptyExpression (atype
);
1177 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (ptype
);
1181 bool is_class
, is_struct
;
1182 if (atype
.IsGenericParameter
) {
1183 GenericConstraints agc
= TypeManager
.GetTypeParameterConstraints (atype
);
1185 is_class
= agc
.HasReferenceTypeConstraint
;
1186 is_struct
= agc
.HasValueTypeConstraint
;
1188 is_class
= is_struct
= false;
1191 is_class
= atype
.IsClass
;
1192 is_struct
= atype
.IsValueType
;
1196 // First, check the `class' and `struct' constraints.
1198 if (gc
.HasReferenceTypeConstraint
&& !is_class
) {
1199 Report
.Error (452, loc
, "The type `{0}' must be " +
1200 "a reference type in order to use it " +
1201 "as type parameter `{1}' in the " +
1202 "generic type or method `{2}'.",
1203 atype
, ptype
, DeclarationName
);
1205 } else if (gc
.HasValueTypeConstraint
&& !is_struct
) {
1206 Report
.Error (453, loc
, "The type `{0}' must be " +
1207 "a value type in order to use it " +
1208 "as type parameter `{1}' in the " +
1209 "generic type or method `{2}'.",
1210 atype
, ptype
, DeclarationName
);
1215 // The class constraint comes next.
1217 if (gc
.HasClassConstraint
) {
1218 if (!CheckConstraint (ec
, ptype
, aexpr
, gc
.ClassConstraint
)) {
1219 Report
.Error (309, loc
, "The type `{0}' must be " +
1220 "convertible to `{1}' in order to " +
1221 "use it as parameter `{2}' in the " +
1222 "generic type or method `{3}'",
1223 atype
, gc
.ClassConstraint
, ptype
, DeclarationName
);
1229 // Now, check the interface constraints.
1231 foreach (Type it
in gc
.InterfaceConstraints
) {
1233 if (it
.IsGenericParameter
)
1234 itype
= atypes
[it
.GenericParameterPosition
];
1238 if (!CheckConstraint (ec
, ptype
, aexpr
, itype
)) {
1239 Report
.Error (309, loc
, "The type `{0}' must be " +
1240 "convertible to `{1}' in order to " +
1241 "use it as parameter `{2}' in the " +
1242 "generic type or method `{3}'",
1243 atype
, itype
, ptype
, DeclarationName
);
1249 // Finally, check the constructor constraint.
1252 if (!gc
.HasConstructorConstraint
)
1255 if (TypeManager
.IsBuiltinType (atype
) || atype
.IsValueType
)
1258 MethodGroupExpr mg
= Expression
.MemberLookup (
1259 ec
, atype
, ".ctor", MemberTypes
.Constructor
,
1260 BindingFlags
.Public
| BindingFlags
.Instance
|
1261 BindingFlags
.DeclaredOnly
, loc
)
1264 if (atype
.IsAbstract
|| (mg
== null) || !mg
.IsInstance
) {
1265 Report
.Error (310, loc
, "The type `{0}' must have a public " +
1266 "parameterless constructor in order to use it " +
1267 "as parameter `{1}' in the generic type or " +
1268 "method `{2}'", atype
, ptype
, DeclarationName
);
1275 protected override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
1277 if (!ResolveConstructedType (ec
))
1283 public bool CheckConstraints (EmitContext ec
)
1285 for (int i
= 0; i
< gen_params
.Length
; i
++) {
1286 if (!CheckConstraints (ec
, i
))
1293 public override TypeExpr
ResolveAsTypeTerminal (EmitContext ec
)
1295 if (base.ResolveAsTypeTerminal (ec
) == null)
1298 if (!CheckConstraints (ec
))
1304 public bool ResolveConstructedType (EmitContext ec
)
1309 return DoResolveType (ec
);
1312 // First, resolve the generic type.
1315 Type nested
= ec
.DeclSpace
.FindNestedType (loc
, name
, out ds
);
1316 if (nested
!= null) {
1317 gt
= nested
.GetGenericTypeDefinition ();
1319 TypeArguments new_args
= new TypeArguments (loc
);
1321 foreach (TypeParameter param
in ds
.TypeParameters
)
1322 new_args
.Add (new TypeParameterExpr (param
, loc
));
1324 new_args
.Add (args
);
1327 return DoResolveType (ec
);
1333 SimpleName sn
= new SimpleName (name
, loc
);
1334 TypeExpr resolved
= sn
.ResolveAsTypeTerminal (ec
);
1335 if (resolved
== null)
1340 Report
.Error (246, loc
, "Cannot find type `{0}'<...>",
1345 num_args
= TypeManager
.GetNumberOfTypeArguments (t
);
1346 if (num_args
== 0) {
1347 Report
.Error (308, loc
,
1348 "The non-generic type `{0}' cannot " +
1349 "be used with type arguments.",
1350 TypeManager
.CSharpName (t
));
1354 gt
= t
.GetGenericTypeDefinition ();
1355 return DoResolveType (ec
);
1358 bool DoResolveType (EmitContext ec
)
1361 // Resolve the arguments.
1363 if (args
.Resolve (ec
) == false)
1366 gen_params
= gt
.GetGenericArguments ();
1367 atypes
= args
.Arguments
;
1369 if (atypes
.Length
!= gen_params
.Length
) {
1370 Report
.Error (305, loc
,
1371 "Using the generic type `{0}' " +
1372 "requires {1} type arguments",
1373 TypeManager
.GetFullName (gt
),
1379 // Now bind the parameters.
1381 type
= gt
.MakeGenericType (atypes
);
1385 public Expression
GetSimpleName (EmitContext ec
)
1387 return new SimpleName (Basename
, args
, loc
);
1390 public override bool CheckAccessLevel (DeclSpace ds
)
1392 return ds
.CheckAccessLevel (gt
);
1395 public override bool AsAccessible (DeclSpace ds
, int flags
)
1397 return ds
.AsAccessible (gt
, flags
);
1400 public override bool IsClass
{
1401 get { return gt.IsClass; }
1404 public override bool IsValueType
{
1405 get { return gt.IsValueType; }
1408 public override bool IsInterface
{
1409 get { return gt.IsInterface; }
1412 public override bool IsSealed
{
1413 get { return gt.IsSealed; }
1416 public override bool IsAttribute
{
1417 get { return false; }
1420 public override bool Equals (object obj
)
1422 ConstructedType cobj
= obj
as ConstructedType
;
1426 if ((type
== null) || (cobj
.type
== null))
1429 return type
== cobj
.type
;
1432 public override int GetHashCode ()
1434 return base.GetHashCode ();
1437 public string Basename
{
1439 int pos
= name
.LastIndexOf ('`');
1441 return name
.Substring (0, pos
);
1447 public override string Name
{
1454 public override string FullName
{
1461 public class GenericMethod
: DeclSpace
1463 public GenericMethod (NamespaceEntry ns
, TypeContainer parent
,
1464 MemberName name
, Location l
)
1465 : base (ns
, parent
, name
, null, l
)
1468 public override TypeBuilder
DefineType ()
1470 throw new Exception ();
1473 public override bool Define ()
1475 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1476 if (!TypeParameters
[i
].Resolve (Parent
))
1482 public bool Define (MethodBuilder mb
, Type return_type
)
1487 GenericTypeParameterBuilder
[] gen_params
;
1488 string[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1489 gen_params
= mb
.DefineGenericParameters (names
);
1490 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1491 TypeParameters
[i
].Define (gen_params
[i
]);
1493 ec
= new EmitContext (
1494 this, this, Location
, null, return_type
, ModFlags
, false);
1496 for (int i
= 0; i
< TypeParameters
.Length
; i
++) {
1497 if (!TypeParameters
[i
].ResolveType (ec
))
1504 public bool DefineType (EmitContext ec
, MethodBuilder mb
,
1505 MethodInfo implementing
, bool is_override
)
1507 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1508 if (!TypeParameters
[i
].DefineType (
1509 ec
, mb
, implementing
, is_override
))
1515 public override bool DefineMembers (TypeContainer parent
)
1520 public override MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
1521 MemberFilter filter
, object criteria
)
1523 throw new Exception ();
1526 public override MemberCache MemberCache
{
1532 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
1537 protected override void VerifyObsoleteAttribute()
1542 public override AttributeTargets AttributeTargets
{
1544 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
1548 public override string DocCommentHeader
{
1549 get { return "M:"; }
1553 public class DefaultValueExpression
: Expression
1556 LocalTemporary temp_storage
;
1558 public DefaultValueExpression (Expression expr
, Location loc
)
1564 public override Expression
DoResolve (EmitContext ec
)
1566 TypeExpr texpr
= expr
.ResolveAsTypeTerminal (ec
);
1571 if (type
.IsGenericParameter
|| TypeManager
.IsValueType (type
))
1572 temp_storage
= new LocalTemporary (ec
, type
);
1574 eclass
= ExprClass
.Variable
;
1578 public override void Emit (EmitContext ec
)
1580 if (temp_storage
!= null) {
1581 temp_storage
.AddressOf (ec
, AddressOp
.LoadStore
);
1582 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
1583 temp_storage
.Emit (ec
);
1585 ec
.ig
.Emit (OpCodes
.Ldnull
);
1589 public class NullableType
: TypeExpr
1591 Expression underlying
;
1593 public NullableType (Expression underlying
, Location l
)
1595 this.underlying
= underlying
;
1598 eclass
= ExprClass
.Type
;
1601 public NullableType (Type type
, Location loc
)
1602 : this (new TypeExpression (type
, loc
), loc
)
1605 public override string Name
{
1606 get { return underlying.ToString () + "?"; }
1609 public override string FullName
{
1610 get { return underlying.ToString () + "?"; }
1613 protected override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
1615 TypeArguments args
= new TypeArguments (loc
);
1616 args
.Add (underlying
);
1618 ConstructedType ctype
= new ConstructedType (TypeManager
.generic_nullable_type
, args
, loc
);
1619 return ctype
.ResolveAsTypeTerminal (ec
);
1623 public partial class TypeManager
1626 // A list of core types that the compiler requires or uses
1628 static public Type new_constraint_attr_type
;
1629 static public Type activator_type
;
1630 static public Type generic_ienumerator_type
;
1631 static public Type generic_ienumerable_type
;
1632 static public Type generic_nullable_type
;
1635 // Tracks the generic parameters.
1637 static PtrHashtable builder_to_type_param
;
1640 // These methods are called by code generated by the compiler
1642 static public MethodInfo activator_create_instance
;
1644 static void InitGenerics ()
1646 builder_to_type_param
= new PtrHashtable ();
1649 static void CleanUpGenerics ()
1651 builder_to_type_param
= null;
1654 static void InitGenericCoreTypes ()
1656 activator_type
= CoreLookupType ("System.Activator");
1657 new_constraint_attr_type
= CoreLookupType (
1658 "System.Runtime.CompilerServices.NewConstraintAttribute");
1660 generic_ienumerator_type
= CoreLookupType ("System.Collections.Generic.IEnumerator", 1);
1661 generic_ienumerable_type
= CoreLookupType ("System.Collections.Generic.IEnumerable", 1);
1662 generic_nullable_type
= CoreLookupType ("System.Nullable", 1);
1665 static void InitGenericCodeHelpers ()
1668 Type
[] type_arg
= { type_type }
;
1669 activator_create_instance
= GetMethod (
1670 activator_type
, "CreateInstance", type_arg
);
1673 static Type
CoreLookupType (string name
, int arity
)
1675 return CoreLookupType (MemberName
.MakeName (name
, arity
));
1678 public static void AddTypeParameter (Type t
, TypeParameter tparam
)
1680 if (!builder_to_type_param
.Contains (t
))
1681 builder_to_type_param
.Add (t
, tparam
);
1684 public static TypeContainer
LookupGenericTypeContainer (Type t
)
1686 while (t
.IsGenericInstance
)
1687 t
= t
.GetGenericTypeDefinition ();
1689 return LookupTypeContainer (t
);
1692 public static TypeParameter
LookupTypeParameter (Type t
)
1694 return (TypeParameter
) builder_to_type_param
[t
];
1697 public static bool HasConstructorConstraint (Type t
)
1699 GenericConstraints gc
= GetTypeParameterConstraints (t
);
1703 return (gc
.Attributes
& GenericParameterAttributes
.DefaultConstructorConstraint
) != 0;
1706 public static GenericConstraints
GetTypeParameterConstraints (Type t
)
1708 if (!t
.IsGenericParameter
)
1709 throw new InvalidOperationException ();
1711 TypeParameter tparam
= LookupTypeParameter (t
);
1713 return tparam
.GenericConstraints
;
1715 return new ReflectionConstraints (t
);
1718 public static bool IsGeneric (Type t
)
1720 DeclSpace ds
= (DeclSpace
) builder_to_declspace
[t
];
1722 return ds
.IsGeneric
;
1725 public static bool HasGenericArguments (Type t
)
1727 return GetNumberOfTypeArguments (t
) > 0;
1730 public static int GetNumberOfTypeArguments (Type t
)
1732 DeclSpace tc
= LookupDeclSpace (t
);
1734 return tc
.IsGeneric
? tc
.CountTypeParameters
: 0;
1736 return t
.IsGenericType
? t
.GetGenericArguments ().Length
: 0;
1739 public static Type
[] GetTypeArguments (Type t
)
1741 DeclSpace tc
= LookupDeclSpace (t
);
1744 return Type
.EmptyTypes
;
1746 TypeParameter
[] tparam
= tc
.TypeParameters
;
1747 Type
[] ret
= new Type
[tparam
.Length
];
1748 for (int i
= 0; i
< tparam
.Length
; i
++) {
1749 ret
[i
] = tparam
[i
].Type
;
1750 if (ret
[i
] == null)
1751 throw new InternalErrorException ();
1756 return t
.GetGenericArguments ();
1760 // Whether `array' is an array of T and `enumerator' is `IEnumerable<T>'.
1761 // For instance "string[]" -> "IEnumerable<string>".
1763 public static bool IsIEnumerable (Type array
, Type enumerator
)
1765 if (!array
.IsArray
|| !enumerator
.IsGenericInstance
)
1768 if (enumerator
.GetGenericTypeDefinition () != generic_ienumerable_type
)
1771 Type
[] args
= GetTypeArguments (enumerator
);
1772 return args
[0] == GetElementType (array
);
1775 public static bool IsEqual (Type a
, Type b
)
1780 if ((a
is TypeBuilder
) && a
.IsGenericTypeDefinition
&& b
.IsGenericInstance
) {
1782 // `a' is a generic type definition's TypeBuilder and `b' is a
1783 // generic instance of the same type.
1789 // void Test (Stack<T> stack) { }
1792 // The first argument of `Test' will be the generic instance
1793 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1796 // We hit this via Closure.Filter() for gen-82.cs.
1798 if (a
!= b
.GetGenericTypeDefinition ())
1801 Type
[] aparams
= a
.GetGenericArguments ();
1802 Type
[] bparams
= b
.GetGenericArguments ();
1804 if (aparams
.Length
!= bparams
.Length
)
1807 for (int i
= 0; i
< aparams
.Length
; i
++)
1808 if (!IsEqual (aparams
[i
], bparams
[i
]))
1814 if ((b
is TypeBuilder
) && b
.IsGenericTypeDefinition
&& a
.IsGenericInstance
)
1815 return IsEqual (b
, a
);
1817 if (a
.IsGenericParameter
&& b
.IsGenericParameter
) {
1818 if ((a
.DeclaringMethod
== null) || (b
.DeclaringMethod
== null))
1820 return a
.GenericParameterPosition
== b
.GenericParameterPosition
;
1823 if (a
.IsArray
&& b
.IsArray
) {
1824 if (a
.GetArrayRank () != b
.GetArrayRank ())
1826 return IsEqual (a
.GetElementType (), b
.GetElementType ());
1829 if (a
.IsGenericInstance
&& b
.IsGenericInstance
) {
1830 if (a
.GetGenericTypeDefinition () != b
.GetGenericTypeDefinition ())
1833 Type
[] aargs
= a
.GetGenericArguments ();
1834 Type
[] bargs
= b
.GetGenericArguments ();
1836 if (aargs
.Length
!= bargs
.Length
)
1839 for (int i
= 0; i
< aargs
.Length
; i
++) {
1840 if (!IsEqual (aargs
[i
], bargs
[i
]))
1850 public static bool MayBecomeEqualGenericTypes (Type a
, Type b
, Type
[] class_infered
, Type
[] method_infered
)
1852 if (a
.IsGenericParameter
) {
1854 // If a is an array of a's type, they may never
1858 b
= b
.GetElementType ();
1864 // If b is a generic parameter or an actual type,
1865 // they may become equal:
1867 // class X<T,U> : I<T>, I<U>
1868 // class X<T> : I<T>, I<float>
1870 if (b
.IsGenericParameter
|| !b
.IsGenericInstance
) {
1871 int pos
= a
.GenericParameterPosition
;
1872 Type
[] args
= a
.DeclaringMethod
!= null ? method_infered
: class_infered
;
1873 if (args
[pos
] == null) {
1878 return args
[pos
] == a
;
1882 // We're now comparing a type parameter with a
1883 // generic instance. They may become equal unless
1884 // the type parameter appears anywhere in the
1885 // generic instance:
1887 // class X<T,U> : I<T>, I<X<U>>
1888 // -> error because you could instanciate it as
1891 // class X<T> : I<T>, I<X<T>> -> ok
1894 Type
[] bargs
= GetTypeArguments (b
);
1895 for (int i
= 0; i
< bargs
.Length
; i
++) {
1896 if (a
.Equals (bargs
[i
]))
1903 if (b
.IsGenericParameter
)
1904 return MayBecomeEqualGenericTypes (b
, a
, class_infered
, method_infered
);
1907 // At this point, neither a nor b are a type parameter.
1909 // If one of them is a generic instance, let
1910 // MayBecomeEqualGenericInstances() compare them (if the
1911 // other one is not a generic instance, they can never
1915 if (a
.IsGenericInstance
|| b
.IsGenericInstance
)
1916 return MayBecomeEqualGenericInstances (a
, b
, class_infered
, method_infered
);
1919 // If both of them are arrays.
1922 if (a
.IsArray
&& b
.IsArray
) {
1923 if (a
.GetArrayRank () != b
.GetArrayRank ())
1926 a
= a
.GetElementType ();
1927 b
= b
.GetElementType ();
1929 return MayBecomeEqualGenericTypes (a
, b
, class_infered
, method_infered
);
1933 // Ok, two ordinary types.
1936 return a
.Equals (b
);
1940 // Checks whether two generic instances may become equal for some
1941 // particular instantiation (26.3.1).
1943 public static bool MayBecomeEqualGenericInstances (Type a
, Type b
,
1944 Type
[] class_infered
, Type
[] method_infered
)
1946 if (!a
.IsGenericInstance
|| !b
.IsGenericInstance
)
1948 if (a
.GetGenericTypeDefinition () != b
.GetGenericTypeDefinition ())
1951 return MayBecomeEqualGenericInstances (
1952 GetTypeArguments (a
), GetTypeArguments (b
), class_infered
, method_infered
);
1955 public static bool MayBecomeEqualGenericInstances (Type
[] aargs
, Type
[] bargs
,
1956 Type
[] class_infered
, Type
[] method_infered
)
1958 if (aargs
.Length
!= bargs
.Length
)
1961 for (int i
= 0; i
< aargs
.Length
; i
++) {
1962 if (!MayBecomeEqualGenericTypes (aargs
[i
], bargs
[i
], class_infered
, method_infered
))
1969 public static bool IsEqualGenericInstance (Type type
, Type parent
)
1971 int tcount
= GetNumberOfTypeArguments (type
);
1972 int pcount
= GetNumberOfTypeArguments (parent
);
1974 if (type
.IsGenericInstance
)
1975 type
= type
.GetGenericTypeDefinition ();
1976 if (parent
.IsGenericInstance
)
1977 parent
= parent
.GetGenericTypeDefinition ();
1979 if (tcount
!= pcount
)
1982 return type
.Equals (parent
);
1985 static public bool IsGenericMethod (MethodBase mb
)
1987 if (mb
.DeclaringType
is TypeBuilder
) {
1988 IMethodData method
= (IMethodData
) builder_to_method
[mb
];
1992 return method
.GenericMethod
!= null;
1995 return mb
.IsGenericMethodDefinition
;
2002 static bool InferType (Type pt
, Type at
, Type
[] infered
)
2004 if (pt
.IsGenericParameter
&& (pt
.DeclaringMethod
!= null)) {
2005 int pos
= pt
.GenericParameterPosition
;
2007 if (infered
[pos
] == null) {
2009 while (check
.IsArray
)
2010 check
= check
.GetElementType ();
2019 if (infered
[pos
] != at
)
2025 if (!pt
.ContainsGenericParameters
) {
2026 if (at
.ContainsGenericParameters
)
2027 return InferType (at
, pt
, infered
);
2034 (at
.GetArrayRank () != pt
.GetArrayRank ()))
2037 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2042 (pt
.GetArrayRank () != at
.GetArrayRank ()))
2045 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2048 if (pt
.IsByRef
&& at
.IsByRef
)
2049 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2050 ArrayList list
= new ArrayList ();
2051 if (at
.IsGenericInstance
)
2054 for (Type bt
= at
.BaseType
; bt
!= null; bt
= bt
.BaseType
)
2057 list
.AddRange (TypeManager
.GetInterfaces (at
));
2060 bool found_one
= false;
2062 foreach (Type type
in list
) {
2063 if (!type
.IsGenericInstance
)
2066 Type
[] infered_types
= new Type
[infered
.Length
];
2068 if (!InferGenericInstance (pt
, type
, infered_types
))
2071 for (int i
= 0; i
< infered_types
.Length
; i
++) {
2072 if (infered
[i
] == null) {
2073 infered
[i
] = infered_types
[i
];
2077 if (infered
[i
] != infered_types
[i
])
2087 static bool InferGenericInstance (Type pt
, Type at
, Type
[] infered_types
)
2089 Type
[] at_args
= at
.GetGenericArguments ();
2090 Type
[] pt_args
= pt
.GetGenericArguments ();
2092 if (at_args
.Length
!= pt_args
.Length
)
2095 for (int i
= 0; i
< at_args
.Length
; i
++) {
2096 if (!InferType (pt_args
[i
], at_args
[i
], infered_types
))
2100 for (int i
= 0; i
< infered_types
.Length
; i
++) {
2101 if (infered_types
[i
] == null)
2108 public static bool InferParamsTypeArguments (EmitContext ec
, ArrayList arguments
,
2109 ref MethodBase method
)
2111 if ((arguments
== null) || !TypeManager
.IsGenericMethod (method
))
2116 if (arguments
== null)
2119 arg_count
= arguments
.Count
;
2121 ParameterData pd
= Invocation
.GetParameterData (method
);
2123 int pd_count
= pd
.Count
;
2128 if (pd
.ParameterModifier (pd_count
- 1) != Parameter
.Modifier
.PARAMS
)
2131 if (pd_count
- 1 > arg_count
)
2134 if (pd_count
== 1 && arg_count
== 0)
2137 Type
[] method_args
= method
.GetGenericArguments ();
2138 Type
[] infered_types
= new Type
[method_args
.Length
];
2141 // If we have come this far, the case which
2142 // remains is when the number of parameters is
2143 // less than or equal to the argument count.
2145 for (int i
= 0; i
< pd_count
- 1; ++i
) {
2146 Argument a
= (Argument
) arguments
[i
];
2148 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2151 Type pt
= pd
.ParameterType (i
);
2154 if (!InferType (pt
, at
, infered_types
))
2158 Type element_type
= TypeManager
.GetElementType (pd
.ParameterType (pd_count
- 1));
2160 for (int i
= pd_count
- 1; i
< arg_count
; i
++) {
2161 Argument a
= (Argument
) arguments
[i
];
2163 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2166 if (!InferType (element_type
, a
.Type
, infered_types
))
2170 for (int i
= 0; i
< infered_types
.Length
; i
++)
2171 if (infered_types
[i
] == null)
2174 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2178 public static bool InferTypeArguments (Type
[] param_types
, Type
[] arg_types
, Type
[] infered_types
)
2180 if (infered_types
== null)
2183 for (int i
= 0; i
< arg_types
.Length
; i
++) {
2184 if (arg_types
[i
] == null)
2187 if (!InferType (param_types
[i
], arg_types
[i
], infered_types
))
2191 for (int i
= 0; i
< infered_types
.Length
; i
++)
2192 if (infered_types
[i
] == null)
2198 public static bool InferTypeArguments (EmitContext ec
, ArrayList arguments
,
2199 ref MethodBase method
)
2201 if (!TypeManager
.IsGenericMethod (method
))
2205 if (arguments
!= null)
2206 arg_count
= arguments
.Count
;
2210 ParameterData pd
= Invocation
.GetParameterData (method
);
2211 if (arg_count
!= pd
.Count
)
2214 Type
[] method_args
= method
.GetGenericArguments ();
2216 bool is_open
= false;
2217 for (int i
= 0; i
< method_args
.Length
; i
++) {
2218 if (method_args
[i
].IsGenericParameter
) {
2226 Type
[] infered_types
= new Type
[method_args
.Length
];
2228 Type
[] param_types
= new Type
[pd
.Count
];
2229 Type
[] arg_types
= new Type
[pd
.Count
];
2231 for (int i
= 0; i
< arg_count
; i
++) {
2232 param_types
[i
] = pd
.ParameterType (i
);
2234 Argument a
= (Argument
) arguments
[i
];
2235 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2238 arg_types
[i
] = a
.Type
;
2241 if (!InferTypeArguments (param_types
, arg_types
, infered_types
))
2244 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2248 public static bool InferTypeArguments (EmitContext ec
, ParameterData apd
,
2249 ref MethodBase method
)
2251 if (!TypeManager
.IsGenericMethod (method
))
2254 ParameterData pd
= Invocation
.GetParameterData (method
);
2255 if (apd
.Count
!= pd
.Count
)
2258 Type
[] method_args
= method
.GetGenericArguments ();
2259 Type
[] infered_types
= new Type
[method_args
.Length
];
2261 Type
[] param_types
= new Type
[pd
.Count
];
2262 Type
[] arg_types
= new Type
[pd
.Count
];
2264 for (int i
= 0; i
< apd
.Count
; i
++) {
2265 param_types
[i
] = pd
.ParameterType (i
);
2266 arg_types
[i
] = apd
.ParameterType (i
);
2269 if (!InferTypeArguments (param_types
, arg_types
, infered_types
))
2272 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2276 public static bool IsNullableType (Type t
)
2278 if (!t
.IsGenericInstance
)
2281 Type gt
= t
.GetGenericTypeDefinition ();
2282 return gt
== generic_nullable_type
;
2286 public abstract class Nullable
2288 protected sealed class NullableInfo
2290 public readonly Type Type
;
2291 public readonly Type UnderlyingType
;
2292 public readonly MethodInfo HasValue
;
2293 public readonly MethodInfo Value
;
2294 public readonly ConstructorInfo Constructor
;
2296 public NullableInfo (Type type
)
2299 UnderlyingType
= TypeManager
.GetTypeArguments (type
) [0];
2301 PropertyInfo has_value_pi
= type
.GetProperty ("HasValue");
2302 PropertyInfo value_pi
= type
.GetProperty ("Value");
2304 HasValue
= has_value_pi
.GetGetMethod (false);
2305 Value
= value_pi
.GetGetMethod (false);
2306 Constructor
= type
.GetConstructor (new Type
[] { UnderlyingType }
);
2310 protected class Unwrap
: Expression
, IMemoryLocation
, IAssignMethod
2315 LocalTemporary temp
;
2318 public Unwrap (Expression expr
, Location loc
)
2324 public override Expression
DoResolve (EmitContext ec
)
2326 expr
= expr
.Resolve (ec
);
2330 if (!(expr
is IMemoryLocation
))
2331 temp
= new LocalTemporary (ec
, expr
.Type
);
2333 info
= new NullableInfo (expr
.Type
);
2334 type
= info
.UnderlyingType
;
2335 eclass
= expr
.eclass
;
2339 public override void Emit (EmitContext ec
)
2341 AddressOf (ec
, AddressOp
.LoadStore
);
2342 ec
.ig
.EmitCall (OpCodes
.Call
, info
.Value
, null);
2345 public void EmitCheck (EmitContext ec
)
2347 AddressOf (ec
, AddressOp
.LoadStore
);
2348 ec
.ig
.EmitCall (OpCodes
.Call
, info
.HasValue
, null);
2351 void create_temp (EmitContext ec
)
2353 if ((temp
!= null) && !has_temp
) {
2360 public void AddressOf (EmitContext ec
, AddressOp mode
)
2364 temp
.AddressOf (ec
, AddressOp
.LoadStore
);
2366 ((IMemoryLocation
) expr
).AddressOf (ec
, AddressOp
.LoadStore
);
2369 public void Emit (EmitContext ec
, bool leave_copy
)
2382 public void EmitAssign (EmitContext ec
, Expression source
,
2383 bool leave_copy
, bool prepare_for_load
)
2386 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2389 ec
.ig
.Emit (OpCodes
.Dup
);
2391 Expression empty
= new EmptyExpression (expr
.Type
);
2392 ((IAssignMethod
) expr
).EmitAssign (ec
, empty
, false, prepare_for_load
);
2396 protected class Wrap
: Expression
2401 public Wrap (Expression expr
, Location loc
)
2407 public override Expression
DoResolve (EmitContext ec
)
2409 expr
= expr
.Resolve (ec
);
2413 TypeExpr target_type
= new NullableType (expr
.Type
, loc
);
2414 target_type
= target_type
.ResolveAsTypeTerminal (ec
);
2415 if (target_type
== null)
2418 type
= target_type
.Type
;
2419 info
= new NullableInfo (type
);
2420 eclass
= ExprClass
.Value
;
2424 public override void Emit (EmitContext ec
)
2427 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2431 public class NullableLiteral
: Expression
, IMemoryLocation
{
2432 public NullableLiteral (Type target_type
, Location loc
)
2434 this.type
= target_type
;
2437 eclass
= ExprClass
.Value
;
2440 public override Expression
DoResolve (EmitContext ec
)
2445 public override void Emit (EmitContext ec
)
2447 LocalTemporary value_target
= new LocalTemporary (ec
, type
);
2449 value_target
.AddressOf (ec
, AddressOp
.Store
);
2450 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2451 value_target
.Emit (ec
);
2454 public void AddressOf (EmitContext ec
, AddressOp Mode
)
2456 LocalTemporary value_target
= new LocalTemporary (ec
, type
);
2458 value_target
.AddressOf (ec
, AddressOp
.Store
);
2459 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2460 ((IMemoryLocation
) value_target
).AddressOf (ec
, Mode
);
2464 public abstract class Lifted
: Expression
, IMemoryLocation
2466 Expression expr
, underlying
, wrap
, null_value
;
2469 protected Lifted (Expression expr
, Location loc
)
2475 public override Expression
DoResolve (EmitContext ec
)
2477 expr
= expr
.Resolve (ec
);
2481 unwrap
= (Unwrap
) new Unwrap (expr
, loc
).Resolve (ec
);
2485 underlying
= ResolveUnderlying (unwrap
, ec
);
2486 if (underlying
== null)
2489 wrap
= new Wrap (underlying
, loc
).Resolve (ec
);
2493 null_value
= new NullableLiteral (wrap
.Type
, loc
).Resolve (ec
);
2494 if (null_value
== null)
2498 eclass
= ExprClass
.Value
;
2502 protected abstract Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
);
2504 public override void Emit (EmitContext ec
)
2506 ILGenerator ig
= ec
.ig
;
2507 Label is_null_label
= ig
.DefineLabel ();
2508 Label end_label
= ig
.DefineLabel ();
2510 unwrap
.EmitCheck (ec
);
2511 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2514 ig
.Emit (OpCodes
.Br
, end_label
);
2516 ig
.MarkLabel (is_null_label
);
2517 null_value
.Emit (ec
);
2519 ig
.MarkLabel (end_label
);
2522 public void AddressOf (EmitContext ec
, AddressOp mode
)
2524 unwrap
.AddressOf (ec
, mode
);
2528 public class LiftedConversion
: Lifted
2530 public readonly bool IsUser
;
2531 public readonly bool IsExplicit
;
2532 public readonly Type TargetType
;
2534 public LiftedConversion (Expression expr
, Type target_type
, bool is_user
,
2535 bool is_explicit
, Location loc
)
2538 this.IsUser
= is_user
;
2539 this.IsExplicit
= is_explicit
;
2540 this.TargetType
= target_type
;
2543 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2545 Type type
= TypeManager
.GetTypeArguments (TargetType
) [0];
2548 return Convert
.UserDefinedConversion (ec
, unwrap
, type
, loc
, IsExplicit
);
2551 return Convert
.WideningAndNarrowingConversion (ec
, unwrap
, type
, loc
);
2553 return Convert
.WideningConversion (ec
, unwrap
, type
, loc
);
2558 public class LiftedUnaryOperator
: Lifted
2560 public readonly Unary
.Operator Oper
;
2562 public LiftedUnaryOperator (Unary
.Operator op
, Expression expr
, Location loc
)
2568 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2570 return new Unary (Oper
, unwrap
, loc
);
2574 public class LiftedConditional
: Lifted
2576 Expression expr
, true_expr
, false_expr
;
2579 public LiftedConditional (Expression expr
, Expression true_expr
, Expression false_expr
,
2583 this.true_expr
= true_expr
;
2584 this.false_expr
= false_expr
;
2587 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2589 return new Conditional (unwrap
, true_expr
, false_expr
, loc
);
2593 public class LiftedBinaryOperator
: Expression
2595 public readonly Binary
.Operator Oper
;
2597 Expression left
, right
, underlying
, null_value
, bool_wrap
;
2598 Unwrap left_unwrap
, right_unwrap
;
2599 bool is_equality
, is_comparision
, is_boolean
;
2601 public LiftedBinaryOperator (Binary
.Operator op
, Expression left
, Expression right
,
2610 public override Expression
DoResolve (EmitContext ec
)
2612 if (TypeManager
.IsNullableType (left
.Type
)) {
2613 left_unwrap
= new Unwrap (left
, loc
);
2614 left
= left_unwrap
.Resolve (ec
);
2619 if (TypeManager
.IsNullableType (right
.Type
)) {
2620 right_unwrap
= new Unwrap (right
, loc
);
2621 right
= right_unwrap
.Resolve (ec
);
2626 if (((Oper
== Binary
.Operator
.BitwiseAnd
) || (Oper
== Binary
.Operator
.BitwiseOr
) ||
2627 (Oper
== Binary
.Operator
.LogicalAndAlso
) || (Oper
== Binary
.Operator
.LogicalOrElse
)) &&
2628 ((left
.Type
== TypeManager
.bool_type
) && (right
.Type
== TypeManager
.bool_type
))) {
2629 Expression empty
= new EmptyExpression (TypeManager
.bool_type
);
2630 bool_wrap
= new Wrap (empty
, loc
).Resolve (ec
);
2631 null_value
= new NullableLiteral (bool_wrap
.Type
, loc
).Resolve (ec
);
2633 type
= bool_wrap
.Type
;
2635 } else if ((Oper
== Binary
.Operator
.Equality
) || (Oper
== Binary
.Operator
.Inequality
)) {
2636 if (!(left
is NullLiteral
) && !(right
is NullLiteral
)) {
2637 underlying
= new Binary (Oper
, left
, right
, loc
).Resolve (ec
);
2638 if (underlying
== null)
2642 type
= TypeManager
.bool_type
;
2644 } else if ((Oper
== Binary
.Operator
.LessThan
) ||
2645 (Oper
== Binary
.Operator
.GreaterThan
) ||
2646 (Oper
== Binary
.Operator
.LessThanOrEqual
) ||
2647 (Oper
== Binary
.Operator
.GreaterThanOrEqual
)) {
2648 underlying
= new Binary (Oper
, left
, right
, loc
).Resolve (ec
);
2649 if (underlying
== null)
2652 type
= TypeManager
.bool_type
;
2653 is_comparision
= true;
2655 underlying
= new Binary (Oper
, left
, right
, loc
).Resolve (ec
);
2656 if (underlying
== null)
2659 underlying
= new Wrap (underlying
, loc
).Resolve (ec
);
2660 if (underlying
== null)
2663 type
= underlying
.Type
;
2664 null_value
= new NullableLiteral (type
, loc
).Resolve (ec
);
2667 eclass
= ExprClass
.Value
;
2671 void EmitBoolean (EmitContext ec
)
2673 ILGenerator ig
= ec
.ig
;
2675 Label left_is_null_label
= ig
.DefineLabel ();
2676 Label right_is_null_label
= ig
.DefineLabel ();
2677 Label is_null_label
= ig
.DefineLabel ();
2678 Label wrap_label
= ig
.DefineLabel ();
2679 Label end_label
= ig
.DefineLabel ();
2681 if (left_unwrap
!= null) {
2682 left_unwrap
.EmitCheck (ec
);
2683 ig
.Emit (OpCodes
.Brfalse
, left_is_null_label
);
2687 ig
.Emit (OpCodes
.Dup
);
2688 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOrElse
))
2689 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
2691 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
2693 if (right_unwrap
!= null) {
2694 right_unwrap
.EmitCheck (ec
);
2695 ig
.Emit (OpCodes
.Brfalse
, right_is_null_label
);
2698 if ((Oper
== Binary
.Operator
.LogicalAndAlso
) || (Oper
== Binary
.Operator
.LogicalOrElse
))
2699 ig
.Emit (OpCodes
.Pop
);
2702 if (Oper
== Binary
.Operator
.BitwiseOr
)
2703 ig
.Emit (OpCodes
.Or
);
2704 else if (Oper
== Binary
.Operator
.BitwiseAnd
)
2705 ig
.Emit (OpCodes
.And
);
2706 ig
.Emit (OpCodes
.Br
, wrap_label
);
2708 ig
.MarkLabel (left_is_null_label
);
2709 if (right_unwrap
!= null) {
2710 right_unwrap
.EmitCheck (ec
);
2711 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2715 ig
.Emit (OpCodes
.Dup
);
2716 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOrElse
))
2717 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
2719 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
2721 ig
.MarkLabel (right_is_null_label
);
2722 ig
.Emit (OpCodes
.Pop
);
2723 ig
.MarkLabel (is_null_label
);
2724 null_value
.Emit (ec
);
2725 ig
.Emit (OpCodes
.Br
, end_label
);
2727 ig
.MarkLabel (wrap_label
);
2728 ig
.Emit (OpCodes
.Nop
);
2729 bool_wrap
.Emit (ec
);
2730 ig
.Emit (OpCodes
.Nop
);
2732 ig
.MarkLabel (end_label
);
2735 void EmitEquality (EmitContext ec
)
2737 ILGenerator ig
= ec
.ig
;
2739 Label left_not_null_label
= ig
.DefineLabel ();
2740 Label false_label
= ig
.DefineLabel ();
2741 Label true_label
= ig
.DefineLabel ();
2742 Label end_label
= ig
.DefineLabel ();
2744 if (left_unwrap
!= null) {
2745 left_unwrap
.EmitCheck (ec
);
2746 if (right
is NullLiteral
) {
2747 if (Oper
== Binary
.Operator
.Equality
)
2748 ig
.Emit (OpCodes
.Brfalse
, true_label
);
2750 ig
.Emit (OpCodes
.Brfalse
, false_label
);
2751 } else if (right_unwrap
!= null) {
2752 ig
.Emit (OpCodes
.Dup
);
2753 ig
.Emit (OpCodes
.Brtrue
, left_not_null_label
);
2754 right_unwrap
.EmitCheck (ec
);
2755 ig
.Emit (OpCodes
.Ceq
);
2756 if (Oper
== Binary
.Operator
.Inequality
) {
2757 ig
.Emit (OpCodes
.Ldc_I4_0
);
2758 ig
.Emit (OpCodes
.Ceq
);
2760 ig
.Emit (OpCodes
.Br
, end_label
);
2762 ig
.MarkLabel (left_not_null_label
);
2763 ig
.Emit (OpCodes
.Pop
);
2765 if (Oper
== Binary
.Operator
.Equality
)
2766 ig
.Emit (OpCodes
.Brfalse
, false_label
);
2768 ig
.Emit (OpCodes
.Brfalse
, true_label
);
2772 if (right_unwrap
!= null) {
2773 right_unwrap
.EmitCheck (ec
);
2774 if (left
is NullLiteral
) {
2775 if (Oper
== Binary
.Operator
.Equality
)
2776 ig
.Emit (OpCodes
.Brfalse
, true_label
);
2778 ig
.Emit (OpCodes
.Brfalse
, false_label
);
2780 if (Oper
== Binary
.Operator
.Equality
)
2781 ig
.Emit (OpCodes
.Brfalse
, false_label
);
2783 ig
.Emit (OpCodes
.Brfalse
, true_label
);
2787 bool left_is_null
= left
is NullLiteral
;
2788 bool right_is_null
= right
is NullLiteral
;
2789 if (left_is_null
|| right_is_null
) {
2790 if (((Oper
== Binary
.Operator
.Equality
) && (left_is_null
== right_is_null
)) ||
2791 ((Oper
== Binary
.Operator
.Inequality
) && (left_is_null
!= right_is_null
)))
2792 ig
.Emit (OpCodes
.Br
, true_label
);
2794 ig
.Emit (OpCodes
.Br
, false_label
);
2796 underlying
.Emit (ec
);
2797 ig
.Emit (OpCodes
.Br
, end_label
);
2800 ig
.MarkLabel (false_label
);
2801 ig
.Emit (OpCodes
.Ldc_I4_0
);
2802 ig
.Emit (OpCodes
.Br
, end_label
);
2804 ig
.MarkLabel (true_label
);
2805 ig
.Emit (OpCodes
.Ldc_I4_1
);
2807 ig
.MarkLabel (end_label
);
2810 void EmitComparision (EmitContext ec
)
2812 ILGenerator ig
= ec
.ig
;
2814 Label is_null_label
= ig
.DefineLabel ();
2815 Label end_label
= ig
.DefineLabel ();
2817 if (left_unwrap
!= null) {
2818 left_unwrap
.EmitCheck (ec
);
2819 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2822 if (right_unwrap
!= null) {
2823 right_unwrap
.EmitCheck (ec
);
2824 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2827 underlying
.Emit (ec
);
2828 ig
.Emit (OpCodes
.Br
, end_label
);
2830 ig
.MarkLabel (is_null_label
);
2831 ig
.Emit (OpCodes
.Ldc_I4_0
);
2833 ig
.MarkLabel (end_label
);
2836 public override void Emit (EmitContext ec
)
2841 } else if (is_equality
) {
2844 } else if (is_comparision
) {
2845 EmitComparision (ec
);
2849 ILGenerator ig
= ec
.ig
;
2851 Label is_null_label
= ig
.DefineLabel ();
2852 Label end_label
= ig
.DefineLabel ();
2854 if (left_unwrap
!= null) {
2855 left_unwrap
.EmitCheck (ec
);
2856 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2859 if (right_unwrap
!= null) {
2860 right_unwrap
.EmitCheck (ec
);
2861 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2864 underlying
.Emit (ec
);
2865 ig
.Emit (OpCodes
.Br
, end_label
);
2867 ig
.MarkLabel (is_null_label
);
2868 null_value
.Emit (ec
);
2870 ig
.MarkLabel (end_label
);
2874 public class OperatorTrueOrFalse
: Expression
2876 public readonly bool IsTrue
;
2881 public OperatorTrueOrFalse (Expression expr
, bool is_true
, Location loc
)
2883 this.IsTrue
= is_true
;
2888 public override Expression
DoResolve (EmitContext ec
)
2890 unwrap
= new Unwrap (expr
, loc
);
2891 expr
= unwrap
.Resolve (ec
);
2895 if (unwrap
.Type
!= TypeManager
.bool_type
)
2898 type
= TypeManager
.bool_type
;
2899 eclass
= ExprClass
.Value
;
2903 public override void Emit (EmitContext ec
)
2905 ILGenerator ig
= ec
.ig
;
2907 Label is_null_label
= ig
.DefineLabel ();
2908 Label end_label
= ig
.DefineLabel ();
2910 unwrap
.EmitCheck (ec
);
2911 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2915 ig
.Emit (OpCodes
.Ldc_I4_0
);
2916 ig
.Emit (OpCodes
.Ceq
);
2918 ig
.Emit (OpCodes
.Br
, end_label
);
2920 ig
.MarkLabel (is_null_label
);
2921 ig
.Emit (OpCodes
.Ldc_I4_0
);
2923 ig
.MarkLabel (end_label
);
2927 public class NullCoalescingOperator
: Expression
2929 Expression left
, right
;
2933 public NullCoalescingOperator (Expression left
, Expression right
, Location loc
)
2939 eclass
= ExprClass
.Value
;
2942 public override Expression
DoResolve (EmitContext ec
)
2947 left
= left
.Resolve (ec
);
2951 right
= right
.Resolve (ec
);
2955 Type ltype
= left
.Type
, rtype
= right
.Type
;
2957 if (!TypeManager
.IsNullableType (ltype
) && ltype
.IsValueType
) {
2958 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
2962 if (TypeManager
.IsNullableType (ltype
)) {
2963 NullableInfo info
= new NullableInfo (ltype
);
2965 unwrap
= (Unwrap
) new Unwrap (left
, loc
).Resolve (ec
);
2969 expr
= Convert
.WideningConversion (ec
, right
, info
.UnderlyingType
, loc
);
2977 expr
= Convert
.WideningConversion (ec
, right
, ltype
, loc
);
2983 if (unwrap
!= null) {
2984 expr
= Convert
.WideningConversion (ec
, unwrap
, rtype
, loc
);
2993 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
2997 public override void Emit (EmitContext ec
)
2999 ILGenerator ig
= ec
.ig
;
3001 Label is_null_label
= ig
.DefineLabel ();
3002 Label end_label
= ig
.DefineLabel ();
3004 if (unwrap
!= null) {
3005 unwrap
.EmitCheck (ec
);
3006 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3010 ig
.Emit (OpCodes
.Br
, end_label
);
3012 ig
.MarkLabel (is_null_label
);
3015 ig
.MarkLabel (end_label
);
3019 public class LiftedUnaryMutator
: ExpressionStatement
3021 public readonly UnaryMutator
.Mode Mode
;
3022 Expression expr
, null_value
;
3023 UnaryMutator underlying
;
3026 public LiftedUnaryMutator (UnaryMutator
.Mode mode
, Expression expr
, Location loc
)
3032 eclass
= ExprClass
.Value
;
3035 public override Expression
DoResolve (EmitContext ec
)
3037 expr
= expr
.Resolve (ec
);
3041 unwrap
= (Unwrap
) new Unwrap (expr
, loc
).Resolve (ec
);
3045 underlying
= (UnaryMutator
) new UnaryMutator (Mode
, unwrap
, loc
).Resolve (ec
);
3046 if (underlying
== null)
3049 null_value
= new NullableLiteral (expr
.Type
, loc
).Resolve (ec
);
3050 if (null_value
== null)
3057 void DoEmit (EmitContext ec
, bool is_expr
)
3059 ILGenerator ig
= ec
.ig
;
3060 Label is_null_label
= ig
.DefineLabel ();
3061 Label end_label
= ig
.DefineLabel ();
3063 unwrap
.EmitCheck (ec
);
3064 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3067 underlying
.Emit (ec
);
3069 underlying
.EmitStatement (ec
);
3070 ig
.Emit (OpCodes
.Br
, end_label
);
3072 ig
.MarkLabel (is_null_label
);
3074 null_value
.Emit (ec
);
3076 ig
.MarkLabel (end_label
);
3079 public override void Emit (EmitContext ec
)
3084 public override void EmitStatement (EmitContext ec
)