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
{
23 /// Abstract base class for type parameter constraints.
24 /// The type parameter can come from a generic type definition or from reflection.
26 public abstract class GenericConstraints
{
27 public abstract string TypeParameter
{
31 public abstract GenericParameterAttributes Attributes
{
35 public bool HasConstructorConstraint
{
36 get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
39 public bool HasReferenceTypeConstraint
{
40 get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
43 public bool HasValueTypeConstraint
{
44 get { return (Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; }
47 public virtual bool HasClassConstraint
{
48 get { return ClassConstraint != null; }
51 public abstract Type ClassConstraint
{
55 public abstract Type
[] InterfaceConstraints
{
59 public abstract Type EffectiveBaseClass
{
64 // Returns whether the type parameter is "known to be a reference type".
66 public virtual bool IsReferenceType
{
68 if (HasReferenceTypeConstraint
)
70 if (HasValueTypeConstraint
)
73 if (ClassConstraint
!= null) {
74 if (ClassConstraint
.IsValueType
)
77 if (ClassConstraint
!= TypeManager
.object_type
)
81 foreach (Type t
in InterfaceConstraints
) {
82 if (!t
.IsGenericParameter
)
85 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (t
);
86 if ((gc
!= null) && gc
.IsReferenceType
)
95 // Returns whether the type parameter is "known to be a value type".
97 public virtual bool IsValueType
{
99 if (HasValueTypeConstraint
)
101 if (HasReferenceTypeConstraint
)
104 if (ClassConstraint
!= null) {
105 if (!ClassConstraint
.IsValueType
)
108 if (ClassConstraint
!= TypeManager
.value_type
)
112 foreach (Type t
in InterfaceConstraints
) {
113 if (!t
.IsGenericParameter
)
116 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (t
);
117 if ((gc
!= null) && gc
.IsValueType
)
126 public enum SpecialConstraint
134 /// Tracks the constraints for a type parameter from a generic type definition.
136 public class Constraints
: GenericConstraints
{
138 ArrayList constraints
;
142 // name is the identifier, constraints is an arraylist of
143 // Expressions (with types) or `true' for the constructor constraint.
145 public Constraints (string name
, ArrayList constraints
,
149 this.constraints
= constraints
;
153 public override string TypeParameter
{
159 GenericParameterAttributes attrs
;
160 TypeExpr class_constraint
;
161 ArrayList iface_constraints
;
162 ArrayList type_param_constraints
;
164 Type class_constraint_type
;
165 Type
[] iface_constraint_types
;
166 Type effective_base_type
;
171 /// Resolve the constraints - but only resolve things into Expression's, not
172 /// into actual types.
174 public bool Resolve (IResolveContext ec
)
179 iface_constraints
= new ArrayList ();
180 type_param_constraints
= new ArrayList ();
182 foreach (object obj
in constraints
) {
183 if (HasConstructorConstraint
) {
184 Report
.Error (401, loc
,
185 "The new() constraint must be last.");
189 if (obj
is SpecialConstraint
) {
190 SpecialConstraint sc
= (SpecialConstraint
) obj
;
192 if (sc
== SpecialConstraint
.Constructor
) {
193 if (!HasValueTypeConstraint
) {
194 attrs
|= GenericParameterAttributes
.DefaultConstructorConstraint
;
199 451, loc
, "The new () constraint " +
200 "cannot be used with the `struct' " +
205 if ((num_constraints
> 0) || HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
206 Report
.Error (449, loc
,
207 "The `class' or `struct' " +
208 "constraint must be first");
212 if (sc
== SpecialConstraint
.ReferenceType
)
213 attrs
|= GenericParameterAttributes
.ReferenceTypeConstraint
;
215 attrs
|= GenericParameterAttributes
.NotNullableValueTypeConstraint
;
219 int errors
= Report
.Errors
;
220 FullNamedExpression fn
= ((Expression
) obj
).ResolveAsTypeStep (ec
, false);
223 if (errors
!= Report
.Errors
)
226 Report
.Error (246, loc
, "Cannot find type '{0}'", ((Expression
) obj
).GetSignatureForError ());
231 ConstructedType cexpr
= fn
as ConstructedType
;
233 if (!cexpr
.ResolveConstructedType (ec
))
238 expr
= fn
.ResolveAsTypeTerminal (ec
, false);
240 if ((expr
== null) || (expr
.Type
== null))
243 TypeParameterExpr texpr
= expr
as TypeParameterExpr
;
245 type_param_constraints
.Add (expr
);
246 else if (expr
.IsInterface
)
247 iface_constraints
.Add (expr
);
248 else if (class_constraint
!= null) {
249 Report
.Error (406, loc
,
250 "`{0}': the class constraint for `{1}' " +
251 "must come before any other constraints.",
254 } else if (HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
255 Report
.Error (450, loc
, "`{0}': cannot specify both " +
256 "a constraint class and the `class' " +
257 "or `struct' constraint.", expr
.Name
);
260 class_constraint
= expr
;
265 ArrayList list
= new ArrayList ();
266 foreach (TypeExpr iface_constraint
in iface_constraints
) {
267 foreach (Type type
in list
) {
268 if (!type
.Equals (iface_constraint
.Type
))
271 Report
.Error (405, loc
,
272 "Duplicate constraint `{0}' for type " +
273 "parameter `{1}'.", iface_constraint
.GetSignatureForError (),
278 list
.Add (iface_constraint
.Type
);
281 foreach (TypeParameterExpr expr
in type_param_constraints
) {
282 foreach (Type type
in list
) {
283 if (!type
.Equals (expr
.Type
))
286 Report
.Error (405, loc
,
287 "Duplicate constraint `{0}' for type " +
288 "parameter `{1}'.", expr
.GetSignatureForError (), name
);
292 list
.Add (expr
.Type
);
295 iface_constraint_types
= new Type
[list
.Count
];
296 list
.CopyTo (iface_constraint_types
, 0);
298 if (class_constraint
!= null) {
299 class_constraint_type
= class_constraint
.Type
;
300 if (class_constraint_type
== null)
303 if (class_constraint_type
.IsSealed
) {
304 Report
.Error (701, loc
,
305 "`{0}' is not a valid bound. Bounds " +
306 "must be interfaces or non sealed " +
307 "classes", TypeManager
.CSharpName (class_constraint_type
));
311 if ((class_constraint_type
== TypeManager
.array_type
) ||
312 (class_constraint_type
== TypeManager
.delegate_type
) ||
313 (class_constraint_type
== TypeManager
.enum_type
) ||
314 (class_constraint_type
== TypeManager
.value_type
) ||
315 (class_constraint_type
== TypeManager
.object_type
)) {
316 Report
.Error (702, loc
,
317 "Bound cannot be special class `{0}'",
318 TypeManager
.CSharpName (class_constraint_type
));
323 if (class_constraint_type
!= null)
324 effective_base_type
= class_constraint_type
;
325 else if (HasValueTypeConstraint
)
326 effective_base_type
= TypeManager
.value_type
;
328 effective_base_type
= TypeManager
.object_type
;
334 bool CheckTypeParameterConstraints (TypeParameter tparam
, Hashtable seen
)
336 seen
.Add (tparam
, true);
338 Constraints constraints
= tparam
.Constraints
;
339 if (constraints
== null)
342 if (constraints
.HasValueTypeConstraint
) {
343 Report
.Error (456, loc
, "Type parameter `{0}' has " +
344 "the `struct' constraint, so it cannot " +
345 "be used as a constraint for `{1}'",
350 if (constraints
.type_param_constraints
== null)
353 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
354 if (seen
.Contains (expr
.TypeParameter
)) {
355 Report
.Error (454, loc
, "Circular constraint " +
356 "dependency involving `{0}' and `{1}'",
357 tparam
.Name
, expr
.Name
);
361 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
369 /// Resolve the constraints into actual types.
371 public bool ResolveTypes (IResolveContext ec
)
376 resolved_types
= true;
378 foreach (object obj
in constraints
) {
379 ConstructedType cexpr
= obj
as ConstructedType
;
383 if (!cexpr
.CheckConstraints (ec
))
387 foreach (TypeParameterExpr expr
in type_param_constraints
) {
388 Hashtable seen
= new Hashtable ();
389 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
393 for (int i
= 0; i
< iface_constraints
.Count
; ++i
) {
394 TypeExpr iface_constraint
= (TypeExpr
) iface_constraints
[i
];
395 iface_constraint
= iface_constraint
.ResolveAsTypeTerminal (ec
, false);
396 if (iface_constraint
== null)
398 iface_constraints
[i
] = iface_constraint
;
401 if (class_constraint
!= null) {
402 class_constraint
= class_constraint
.ResolveAsTypeTerminal (ec
, false);
403 if (class_constraint
== null)
411 /// Check whether there are no conflicts in our type parameter constraints.
413 /// This is an example:
417 /// where U : T, struct
419 public bool CheckDependencies ()
421 foreach (TypeParameterExpr expr
in type_param_constraints
) {
422 if (!CheckDependencies (expr
.TypeParameter
))
429 bool CheckDependencies (TypeParameter tparam
)
431 Constraints constraints
= tparam
.Constraints
;
432 if (constraints
== null)
435 if (HasValueTypeConstraint
&& constraints
.HasClassConstraint
) {
436 Report
.Error (455, loc
, "Type parameter `{0}' inherits " +
437 "conflicting constraints `{1}' and `{2}'",
438 name
, TypeManager
.CSharpName (constraints
.ClassConstraint
),
443 if (HasClassConstraint
&& constraints
.HasClassConstraint
) {
444 Type t1
= ClassConstraint
;
445 TypeExpr e1
= class_constraint
;
446 Type t2
= constraints
.ClassConstraint
;
447 TypeExpr e2
= constraints
.class_constraint
;
449 if (!Convert
.ImplicitReferenceConversionExists (e1
, t2
) &&
450 !Convert
.ImplicitReferenceConversionExists (e2
, t1
)) {
451 Report
.Error (455, loc
,
452 "Type parameter `{0}' inherits " +
453 "conflicting constraints `{1}' and `{2}'",
454 name
, TypeManager
.CSharpName (t1
), TypeManager
.CSharpName (t2
));
459 if (constraints
.type_param_constraints
== null)
462 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
463 if (!CheckDependencies (expr
.TypeParameter
))
470 public override GenericParameterAttributes Attributes
{
471 get { return attrs; }
474 public override bool HasClassConstraint
{
475 get { return class_constraint != null; }
478 public override Type ClassConstraint
{
479 get { return class_constraint_type; }
482 public override Type
[] InterfaceConstraints
{
483 get { return iface_constraint_types; }
486 public override Type EffectiveBaseClass
{
487 get { return effective_base_type; }
490 public bool IsSubclassOf (Type t
)
492 if ((class_constraint_type
!= null) &&
493 class_constraint_type
.IsSubclassOf (t
))
496 if (iface_constraint_types
== null)
499 foreach (Type iface
in iface_constraint_types
) {
500 if (TypeManager
.IsSubclassOf (iface
, t
))
508 /// This is used when we're implementing a generic interface method.
509 /// Each method type parameter in implementing method must have the same
510 /// constraints than the corresponding type parameter in the interface
511 /// method. To do that, we're called on each of the implementing method's
514 public bool CheckInterfaceMethod (GenericConstraints gc
)
516 if (gc
.Attributes
!= attrs
)
519 if (HasClassConstraint
!= gc
.HasClassConstraint
)
521 if (HasClassConstraint
&& !TypeManager
.IsEqual (gc
.ClassConstraint
, ClassConstraint
))
524 int gc_icount
= gc
.InterfaceConstraints
!= null ?
525 gc
.InterfaceConstraints
.Length
: 0;
526 int icount
= InterfaceConstraints
!= null ?
527 InterfaceConstraints
.Length
: 0;
529 if (gc_icount
!= icount
)
532 foreach (Type iface
in gc
.InterfaceConstraints
) {
534 foreach (Type check
in InterfaceConstraints
) {
535 if (TypeManager
.IsEqual (iface
, check
)) {
550 /// A type parameter from a generic type definition.
552 public class TypeParameter
: MemberCore
, IMemberContainer
{
555 GenericConstraints gc
;
556 Constraints constraints
;
558 GenericTypeParameterBuilder type
;
560 public TypeParameter (DeclSpace parent
, DeclSpace decl
, string name
,
561 Constraints constraints
, Attributes attrs
, Location loc
)
562 : base (parent
, new MemberName (name
, loc
), attrs
)
566 this.constraints
= constraints
;
570 public GenericConstraints GenericConstraints
{
572 return gc
!= null ? gc
: constraints
;
576 public Constraints Constraints
{
582 public bool HasConstructorConstraint
{
584 if (constraints
!= null)
585 return constraints
.HasConstructorConstraint
;
591 public DeclSpace DeclSpace
{
603 // FIXME: This should be removed once we fix the handling of RootContext.Tree.Types
604 public override DeclSpace DeclContainer
{
605 get { return DeclSpace; }
609 /// This is the first method which is called during the resolving
610 /// process; we're called immediately after creating the type parameters
611 /// with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
614 /// We're either called from TypeContainer.DefineType() or from
615 /// GenericMethod.Define() (called from Method.Define()).
617 public void Define (GenericTypeParameterBuilder type
)
619 if (this.type
!= null)
620 throw new InvalidOperationException ();
623 TypeManager
.AddTypeParameter (type
, this);
627 /// This is the second method which is called during the resolving
628 /// process - in case of class type parameters, we're called from
629 /// TypeContainer.ResolveType() - after it resolved the class'es
630 /// base class and interfaces. For method type parameters, we're
631 /// called immediately after Define().
633 /// We're just resolving the constraints into expressions here, we
634 /// don't resolve them into actual types.
636 /// Note that in the special case of partial generic classes, we may be
637 /// called _before_ Define() and we may also be called multiple types.
639 public bool Resolve (DeclSpace ds
)
641 if (constraints
!= null) {
642 if (!constraints
.Resolve (ds
)) {
652 /// This is the third method which is called during the resolving
653 /// process. We're called immediately after calling DefineConstraints()
654 /// on all of the current class'es type parameters.
656 /// Our job is to resolve the constraints to actual types.
658 /// Note that we may have circular dependencies on type parameters - this
659 /// is why Resolve() and ResolveType() are separate.
661 public bool ResolveType (IResolveContext ec
)
663 if (constraints
!= null) {
664 if (!constraints
.ResolveTypes (ec
)) {
674 /// This is the fourth and last method which is called during the resolving
675 /// process. We're called after everything is fully resolved and actually
676 /// register the constraints with SRE and the TypeManager.
678 public bool DefineType (IResolveContext ec
)
680 return DefineType (ec
, null, null, false);
684 /// This is the fith and last method which is called during the resolving
685 /// process. We're called after everything is fully resolved and actually
686 /// register the constraints with SRE and the TypeManager.
688 /// The `builder', `implementing' and `is_override' arguments are only
689 /// applicable to method type parameters.
691 public bool DefineType (IResolveContext ec
, MethodBuilder builder
,
692 MethodInfo implementing
, bool is_override
)
694 if (!ResolveType (ec
))
697 if (implementing
!= null) {
698 if (is_override
&& (constraints
!= null)) {
700 460, loc
, "Constraints for override and " +
701 "explicit interface implementation methods " +
702 "are inherited from the base method so they " +
703 "cannot be specified directly");
707 MethodBase mb
= TypeManager
.DropGenericMethodArguments (implementing
);
709 int pos
= type
.GenericParameterPosition
;
710 Type mparam
= mb
.GetGenericArguments () [pos
];
711 GenericConstraints temp_gc
= ReflectionConstraints
.GetConstraints (mparam
);
714 gc
= new InflatedConstraints (temp_gc
, implementing
.DeclaringType
);
715 else if (constraints
!= null)
716 gc
= new InflatedConstraints (constraints
, implementing
.DeclaringType
);
719 if (constraints
!= null) {
722 else if (!constraints
.CheckInterfaceMethod (gc
))
725 if (!is_override
&& (temp_gc
!= null))
730 Report
.SymbolRelatedToPreviousError (implementing
);
733 425, loc
, "The constraints for type " +
734 "parameter `{0}' of method `{1}' must match " +
735 "the constraints for type parameter `{2}' " +
736 "of interface method `{3}'. Consider using " +
737 "an explicit interface implementation instead",
738 Name
, TypeManager
.CSharpSignature (builder
),
739 TypeManager
.CSharpName (mparam
), TypeManager
.CSharpSignature (mb
));
742 } else if (DeclSpace
is Iterator
) {
743 TypeParameter
[] tparams
= DeclSpace
.TypeParameters
;
744 Type
[] types
= new Type
[tparams
.Length
];
745 for (int i
= 0; i
< tparams
.Length
; i
++)
746 types
[i
] = tparams
[i
].Type
;
748 if (constraints
!= null)
749 gc
= new InflatedConstraints (constraints
, types
);
751 gc
= (GenericConstraints
) constraints
;
757 if (gc
.HasClassConstraint
)
758 type
.SetBaseTypeConstraint (gc
.ClassConstraint
);
760 type
.SetInterfaceConstraints (gc
.InterfaceConstraints
);
761 type
.SetGenericParameterAttributes (gc
.Attributes
);
762 TypeManager
.RegisterBuilder (type
, gc
.InterfaceConstraints
);
768 /// Check whether there are no conflicts in our type parameter constraints.
770 /// This is an example:
774 /// where U : T, struct
776 public bool CheckDependencies ()
778 if (constraints
!= null)
779 return constraints
.CheckDependencies ();
785 /// This is called for each part of a partial generic type definition.
787 /// If `new_constraints' is not null and we don't already have constraints,
788 /// they become our constraints. If we already have constraints, we must
789 /// check that they're the same.
792 public bool UpdateConstraints (IResolveContext ec
, Constraints new_constraints
)
795 throw new InvalidOperationException ();
797 if (new_constraints
== null)
800 if (!new_constraints
.Resolve (ec
))
802 if (!new_constraints
.ResolveTypes (ec
))
805 if (constraints
!= null)
806 return constraints
.CheckInterfaceMethod (new_constraints
);
808 constraints
= new_constraints
;
812 public void EmitAttributes ()
814 if (OptAttributes
!= null)
815 OptAttributes
.Emit ();
818 public override string DocCommentHeader
{
820 throw new InvalidOperationException (
821 "Unexpected attempt to get doc comment from " + this.GetType () + ".");
829 public override bool Define ()
834 public override void ApplyAttributeBuilder (Attribute a
,
835 CustomAttributeBuilder cb
)
837 type
.SetCustomAttribute (cb
);
840 public override AttributeTargets AttributeTargets
{
842 return (AttributeTargets
) AttributeTargets
.GenericParameter
;
846 public override string[] ValidAttributeTargets
{
848 return new string [] { "type parameter" }
;
856 string IMemberContainer
.Name
{
860 MemberCache IMemberContainer
.BaseCache
{
864 bool IMemberContainer
.IsInterface
{
868 MemberList IMemberContainer
.GetMembers (MemberTypes mt
, BindingFlags bf
)
870 return FindMembers (mt
, bf
, null, null);
873 MemberCache IMemberContainer
.MemberCache
{
877 public MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
878 MemberFilter filter
, object criteria
)
880 if (constraints
== null)
881 return MemberList
.Empty
;
883 ArrayList members
= new ArrayList ();
885 if (gc
.HasClassConstraint
) {
886 MemberList list
= TypeManager
.FindMembers (
887 gc
.ClassConstraint
, mt
, bf
, filter
, criteria
);
889 members
.AddRange (list
);
892 Type
[] ifaces
= TypeManager
.ExpandInterfaces (gc
.InterfaceConstraints
);
893 foreach (Type t
in ifaces
) {
894 MemberList list
= TypeManager
.FindMembers (
895 t
, mt
, bf
, filter
, criteria
);
897 members
.AddRange (list
);
900 return new MemberList (members
);
903 public bool IsSubclassOf (Type t
)
908 if (constraints
!= null)
909 return constraints
.IsSubclassOf (t
);
914 public override string ToString ()
916 return "TypeParameter[" + name
+ "]";
919 public static string GetSignatureForError (TypeParameter
[] tp
)
921 if (tp
== null || tp
.Length
== 0)
924 StringBuilder sb
= new StringBuilder ("<");
925 for (int i
= 0; i
< tp
.Length
; ++i
) {
928 sb
.Append (tp
[i
].GetSignatureForError ());
931 return sb
.ToString ();
934 public void InflateConstraints (Type declaring
)
936 if (constraints
!= null)
937 gc
= new InflatedConstraints (constraints
, declaring
);
940 protected class InflatedConstraints
: GenericConstraints
942 GenericConstraints gc
;
944 Type class_constraint
;
945 Type
[] iface_constraints
;
948 public InflatedConstraints (GenericConstraints gc
, Type declaring
)
949 : this (gc
, TypeManager
.GetTypeArguments (declaring
))
952 public InflatedConstraints (GenericConstraints gc
, Type
[] dargs
)
957 ArrayList list
= new ArrayList ();
958 if (gc
.HasClassConstraint
)
959 list
.Add (inflate (gc
.ClassConstraint
));
960 foreach (Type iface
in gc
.InterfaceConstraints
)
961 list
.Add (inflate (iface
));
963 bool has_class_constr
= false;
964 if (list
.Count
> 0) {
965 Type first
= (Type
) list
[0];
966 has_class_constr
= !first
.IsInterface
&& !first
.IsGenericParameter
;
969 if ((list
.Count
> 0) && has_class_constr
) {
970 class_constraint
= (Type
) list
[0];
971 iface_constraints
= new Type
[list
.Count
- 1];
972 list
.CopyTo (1, iface_constraints
, 0, list
.Count
- 1);
974 iface_constraints
= new Type
[list
.Count
];
975 list
.CopyTo (iface_constraints
, 0);
978 if (HasValueTypeConstraint
)
979 base_type
= TypeManager
.value_type
;
980 else if (class_constraint
!= null)
981 base_type
= class_constraint
;
983 base_type
= TypeManager
.object_type
;
986 Type
inflate (Type t
)
990 if (t
.IsGenericParameter
)
991 return dargs
[t
.GenericParameterPosition
];
992 if (t
.IsGenericType
) {
993 t
= t
.GetGenericTypeDefinition ();
994 t
= t
.MakeGenericType (dargs
);
1000 public override string TypeParameter
{
1001 get { return gc.TypeParameter; }
1004 public override GenericParameterAttributes Attributes
{
1005 get { return gc.Attributes; }
1008 public override Type ClassConstraint
{
1009 get { return class_constraint; }
1012 public override Type EffectiveBaseClass
{
1013 get { return base_type; }
1016 public override Type
[] InterfaceConstraints
{
1017 get { return iface_constraints; }
1023 /// A TypeExpr which already resolved to a type parameter.
1025 public class TypeParameterExpr
: TypeExpr
{
1026 TypeParameter type_parameter
;
1028 public override string Name
{
1030 return type_parameter
.Name
;
1034 public override string FullName
{
1036 return type_parameter
.Name
;
1040 public TypeParameter TypeParameter
{
1042 return type_parameter
;
1046 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1048 this.type_parameter
= type_parameter
;
1052 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
1054 type
= type_parameter
.Type
;
1059 public override bool IsInterface
{
1060 get { return false; }
1063 public override bool CheckAccessLevel (DeclSpace ds
)
1068 public void Error_CannotUseAsUnmanagedType (Location loc
)
1070 Report
.Error (-203, loc
, "Can not use type parameter as unamanged type");
1075 /// Tracks the type arguments when instantiating a generic type. We're used in
1076 /// ConstructedType.
1078 public class TypeArguments
{
1079 public readonly Location Location
;
1086 public TypeArguments (Location loc
)
1088 args
= new ArrayList ();
1089 this.Location
= loc
;
1092 public TypeArguments (int dimension
, Location loc
)
1094 this.dimension
= dimension
;
1095 this.Location
= loc
;
1098 public void Add (Expression type
)
1101 throw new InvalidOperationException ();
1106 public void Add (TypeArguments new_args
)
1109 throw new InvalidOperationException ();
1111 args
.AddRange (new_args
.args
);
1115 /// We're used during the parsing process: the parser can't distinguish
1116 /// between type parameters and type arguments. Because of that, the
1117 /// parser creates a `MemberName' with `TypeArguments' for both cases and
1118 /// in case of a generic type definition, we call GetDeclarations().
1120 public TypeParameterName
[] GetDeclarations ()
1122 TypeParameterName
[] ret
= new TypeParameterName
[args
.Count
];
1123 for (int i
= 0; i
< args
.Count
; i
++) {
1124 TypeParameterName name
= args
[i
] as TypeParameterName
;
1129 SimpleName sn
= args
[i
] as SimpleName
;
1131 ret
[i
] = new TypeParameterName (sn
.Name
, null, sn
.Location
);
1135 Report
.Error (81, Location
, "Type parameter declaration " +
1136 "must be an identifier not a type");
1143 /// We may only be used after Resolve() is called and return the fully
1146 public Type
[] Arguments
{
1152 public bool HasTypeArguments
{
1154 return has_type_args
;
1167 public bool IsUnbound
{
1169 return dimension
> 0;
1173 public override string ToString ()
1175 StringBuilder s
= new StringBuilder ();
1178 for (int i
= 0; i
< count
; i
++){
1180 // FIXME: Use TypeManager.CSharpname once we have the type
1183 s
.Append (args
[i
].ToString ());
1187 return s
.ToString ();
1191 /// Resolve the type arguments.
1193 public bool Resolve (IResolveContext ec
)
1195 int count
= args
.Count
;
1198 atypes
= new Type
[count
];
1200 for (int i
= 0; i
< count
; i
++){
1201 TypeExpr te
= ((Expression
) args
[i
]).ResolveAsTypeTerminal (ec
, false);
1206 if (te
is TypeParameterExpr
)
1207 has_type_args
= true;
1209 if (te
.Type
.IsPointer
) {
1210 Report
.Error (306, Location
, "The type `{0}' may not be used " +
1211 "as a type argument.", TypeManager
.CSharpName (te
.Type
));
1213 } else if (te
.Type
== TypeManager
.void_type
) {
1214 Report
.Error (1547, Location
,
1215 "Keyword `void' cannot be used in this context");
1219 atypes
[i
] = te
.Type
;
1225 public class TypeParameterName
: SimpleName
1227 Attributes attributes
;
1229 public TypeParameterName (string name
, Attributes attrs
, Location loc
)
1235 public Attributes OptAttributes
{
1243 /// An instantiation of a generic type.
1245 public class ConstructedType
: TypeExpr
{
1247 FullNamedExpression name
;
1249 Type
[] gen_params
, atypes
;
1253 /// Instantiate the generic type `fname' with the type arguments `args'.
1255 public ConstructedType (FullNamedExpression fname
, TypeArguments args
, Location l
)
1261 eclass
= ExprClass
.Type
;
1262 full_name
= name
+ "<" + args
.ToString () + ">";
1265 protected ConstructedType (TypeArguments args
, Location l
)
1270 eclass
= ExprClass
.Type
;
1273 protected ConstructedType (TypeParameter
[] type_params
, Location l
)
1277 args
= new TypeArguments (l
);
1278 foreach (TypeParameter type_param
in type_params
)
1279 args
.Add (new TypeParameterExpr (type_param
, l
));
1281 eclass
= ExprClass
.Type
;
1285 /// This is used to construct the `this' type inside a generic type definition.
1287 public ConstructedType (Type t
, TypeParameter
[] type_params
, Location l
)
1288 : this (type_params
, l
)
1290 gt
= t
.GetGenericTypeDefinition ();
1292 this.name
= new TypeExpression (gt
, l
);
1293 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1297 /// Instantiate the generic type `t' with the type arguments `args'.
1298 /// Use this constructor if you already know the fully resolved
1301 public ConstructedType (Type t
, TypeArguments args
, Location l
)
1304 gt
= t
.GetGenericTypeDefinition ();
1306 this.name
= new TypeExpression (gt
, l
);
1307 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1310 public TypeArguments TypeArguments
{
1311 get { return args; }
1314 public override string GetSignatureForError ()
1316 return TypeManager
.CSharpName (gt
);
1319 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
1321 if (!ResolveConstructedType (ec
))
1328 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1329 /// after fully resolving the constructed type.
1331 public bool CheckConstraints (IResolveContext ec
)
1333 return ConstraintChecker
.CheckConstraints (ec
, gt
, gen_params
, atypes
, loc
);
1337 /// Resolve the constructed type, but don't check the constraints.
1339 public bool ResolveConstructedType (IResolveContext ec
)
1343 // If we already know the fully resolved generic type.
1345 return DoResolveType (ec
);
1351 Report
.Error (246, loc
, "Cannot find type `{0}'<...>", Name
);
1355 num_args
= TypeManager
.GetNumberOfTypeArguments (t
);
1356 if (num_args
== 0) {
1357 Report
.Error (308, loc
,
1358 "The non-generic type `{0}' cannot " +
1359 "be used with type arguments.",
1360 TypeManager
.CSharpName (t
));
1364 gt
= t
.GetGenericTypeDefinition ();
1365 return DoResolveType (ec
);
1368 bool DoResolveType (IResolveContext ec
)
1371 // Resolve the arguments.
1373 if (args
.Resolve (ec
) == false)
1376 gen_params
= gt
.GetGenericArguments ();
1377 atypes
= args
.Arguments
;
1379 if (atypes
.Length
!= gen_params
.Length
) {
1380 Report
.Error (305, loc
,
1381 "Using the generic type `{0}' " +
1382 "requires {1} type arguments",
1383 TypeManager
.CSharpName (gt
),
1384 gen_params
.Length
.ToString ());
1389 // Now bind the parameters.
1391 type
= gt
.MakeGenericType (atypes
);
1395 public Expression
GetSimpleName (EmitContext ec
)
1400 public override bool CheckAccessLevel (DeclSpace ds
)
1402 return ds
.CheckAccessLevel (gt
);
1405 public override bool AsAccessible (DeclSpace ds
, int flags
)
1407 return ds
.AsAccessible (gt
, flags
);
1410 public override bool IsClass
{
1411 get { return gt.IsClass; }
1414 public override bool IsValueType
{
1415 get { return gt.IsValueType; }
1418 public override bool IsInterface
{
1419 get { return gt.IsInterface; }
1422 public override bool IsSealed
{
1423 get { return gt.IsSealed; }
1426 public override bool Equals (object obj
)
1428 ConstructedType cobj
= obj
as ConstructedType
;
1432 if ((type
== null) || (cobj
.type
== null))
1435 return type
== cobj
.type
;
1438 public override int GetHashCode ()
1440 return base.GetHashCode ();
1443 public override string Name
{
1450 public override string FullName
{
1457 public abstract class ConstraintChecker
1459 protected readonly Type
[] gen_params
;
1460 protected readonly Type
[] atypes
;
1461 protected readonly Location loc
;
1463 protected ConstraintChecker (Type
[] gen_params
, Type
[] atypes
, Location loc
)
1465 this.gen_params
= gen_params
;
1466 this.atypes
= atypes
;
1471 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1472 /// after fully resolving the constructed type.
1474 public bool CheckConstraints (IResolveContext ec
)
1476 for (int i
= 0; i
< gen_params
.Length
; i
++) {
1477 if (!CheckConstraints (ec
, i
))
1484 protected bool CheckConstraints (IResolveContext ec
, int index
)
1486 Type atype
= atypes
[index
];
1487 Type ptype
= gen_params
[index
];
1492 Expression aexpr
= new EmptyExpression (atype
);
1494 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (ptype
);
1498 bool is_class
, is_struct
;
1499 if (atype
.IsGenericParameter
) {
1500 GenericConstraints agc
= TypeManager
.GetTypeParameterConstraints (atype
);
1502 if (agc
is Constraints
)
1503 ((Constraints
) agc
).Resolve (ec
);
1504 is_class
= agc
.HasReferenceTypeConstraint
;
1505 is_struct
= agc
.HasValueTypeConstraint
;
1507 is_class
= is_struct
= false;
1512 if (!atype
.IsGenericType
)
1514 is_class
= atype
.IsClass
|| atype
.IsInterface
;
1515 is_struct
= atype
.IsValueType
&& !TypeManager
.IsNullableType (atype
);
1519 // First, check the `class' and `struct' constraints.
1521 if (gc
.HasReferenceTypeConstraint
&& !is_class
) {
1522 Report
.Error (452, loc
, "The type `{0}' must be " +
1523 "a reference type in order to use it " +
1524 "as type parameter `{1}' in the " +
1525 "generic type or method `{2}'.",
1526 TypeManager
.CSharpName (atype
),
1527 TypeManager
.CSharpName (ptype
),
1528 GetSignatureForError ());
1530 } else if (gc
.HasValueTypeConstraint
&& !is_struct
) {
1531 Report
.Error (453, loc
, "The type `{0}' must be a " +
1532 "non-nullable value type in order to use it " +
1533 "as type parameter `{1}' in the " +
1534 "generic type or method `{2}'.",
1535 TypeManager
.CSharpName (atype
),
1536 TypeManager
.CSharpName (ptype
),
1537 GetSignatureForError ());
1542 // The class constraint comes next.
1544 if (gc
.HasClassConstraint
) {
1545 if (!CheckConstraint (ec
, ptype
, aexpr
, gc
.ClassConstraint
))
1550 // Now, check the interface constraints.
1552 if (gc
.InterfaceConstraints
!= null) {
1553 foreach (Type it
in gc
.InterfaceConstraints
) {
1554 if (!CheckConstraint (ec
, ptype
, aexpr
, it
))
1560 // Finally, check the constructor constraint.
1563 if (!gc
.HasConstructorConstraint
)
1566 if (TypeManager
.IsBuiltinType (atype
) || atype
.IsValueType
)
1569 if (HasDefaultConstructor (ec
.DeclContainer
.TypeBuilder
, atype
))
1572 Report_SymbolRelatedToPreviousError ();
1573 Report
.SymbolRelatedToPreviousError (atype
);
1574 Report
.Error (310, loc
, "The type `{0}' must have a public " +
1575 "parameterless constructor in order to use it " +
1576 "as parameter `{1}' in the generic type or " +
1578 TypeManager
.CSharpName (atype
),
1579 TypeManager
.CSharpName (ptype
),
1580 GetSignatureForError ());
1584 protected bool CheckConstraint (IResolveContext ec
, Type ptype
, Expression expr
,
1587 if (TypeManager
.HasGenericArguments (ctype
)) {
1588 Type
[] types
= TypeManager
.GetTypeArguments (ctype
);
1590 TypeArguments new_args
= new TypeArguments (loc
);
1592 for (int i
= 0; i
< types
.Length
; i
++) {
1595 if (t
.IsGenericParameter
) {
1596 int pos
= t
.GenericParameterPosition
;
1599 new_args
.Add (new TypeExpression (t
, loc
));
1602 TypeExpr ct
= new ConstructedType (ctype
, new_args
, loc
);
1603 if (ct
.ResolveAsTypeStep (ec
, false) == null)
1606 } else if (ctype
.IsGenericParameter
) {
1607 int pos
= ctype
.GenericParameterPosition
;
1608 ctype
= atypes
[pos
];
1611 if (Convert
.ImplicitStandardConversionExists (expr
, ctype
))
1614 Error_TypeMustBeConvertible (expr
.Type
, ctype
, ptype
);
1618 bool HasDefaultConstructor (Type containerType
, Type atype
)
1620 if (atype
.IsAbstract
)
1624 atype
= TypeManager
.DropGenericTypeArguments (atype
);
1625 if (atype
is TypeBuilder
) {
1626 TypeContainer tc
= TypeManager
.LookupTypeContainer (atype
);
1627 if (tc
.InstanceConstructors
== null) {
1628 atype
= atype
.BaseType
;
1632 foreach (Constructor c
in tc
.InstanceConstructors
) {
1633 if ((c
.ModFlags
& Modifiers
.PUBLIC
) == 0)
1635 if ((c
.Parameters
.FixedParameters
!= null) &&
1636 (c
.Parameters
.FixedParameters
.Length
!= 0))
1638 if (c
.Parameters
.HasArglist
|| c
.Parameters
.HasParams
)
1645 MethodGroupExpr mg
= Expression
.MemberLookup (
1646 containerType
, atype
, ".ctor", MemberTypes
.Constructor
,
1647 BindingFlags
.Public
| BindingFlags
.Instance
|
1648 BindingFlags
.DeclaredOnly
, loc
)
1651 if (!atype
.IsAbstract
&& (mg
!= null) && mg
.IsInstance
) {
1652 foreach (MethodBase mb
in mg
.Methods
) {
1653 ParameterData pd
= TypeManager
.GetParameterData (mb
);
1662 protected abstract string GetSignatureForError ();
1663 protected abstract void Report_SymbolRelatedToPreviousError ();
1665 void Error_TypeMustBeConvertible (Type atype
, Type gc
, Type ptype
)
1667 Report_SymbolRelatedToPreviousError ();
1668 Report
.SymbolRelatedToPreviousError (atype
);
1669 Report
.Error (309, loc
,
1670 "The type `{0}' must be convertible to `{1}' in order to " +
1671 "use it as parameter `{2}' in the generic type or method `{3}'",
1672 TypeManager
.CSharpName (atype
), TypeManager
.CSharpName (gc
),
1673 TypeManager
.CSharpName (ptype
), GetSignatureForError ());
1676 public static bool CheckConstraints (EmitContext ec
, MethodBase definition
,
1677 MethodBase instantiated
, Location loc
)
1679 MethodConstraintChecker checker
= new MethodConstraintChecker (
1680 definition
, definition
.GetGenericArguments (),
1681 instantiated
.GetGenericArguments (), loc
);
1683 return checker
.CheckConstraints (ec
);
1686 public static bool CheckConstraints (IResolveContext ec
, Type gt
, Type
[] gen_params
,
1687 Type
[] atypes
, Location loc
)
1689 TypeConstraintChecker checker
= new TypeConstraintChecker (
1690 gt
, gen_params
, atypes
, loc
);
1692 return checker
.CheckConstraints (ec
);
1695 protected class MethodConstraintChecker
: ConstraintChecker
1697 MethodBase definition
;
1699 public MethodConstraintChecker (MethodBase definition
, Type
[] gen_params
,
1700 Type
[] atypes
, Location loc
)
1701 : base (gen_params
, atypes
, loc
)
1703 this.definition
= definition
;
1706 protected override string GetSignatureForError ()
1708 return TypeManager
.CSharpSignature (definition
);
1711 protected override void Report_SymbolRelatedToPreviousError ()
1713 Report
.SymbolRelatedToPreviousError (definition
);
1717 protected class TypeConstraintChecker
: ConstraintChecker
1721 public TypeConstraintChecker (Type gt
, Type
[] gen_params
, Type
[] atypes
,
1723 : base (gen_params
, atypes
, loc
)
1728 protected override string GetSignatureForError ()
1730 return TypeManager
.CSharpName (gt
);
1733 protected override void Report_SymbolRelatedToPreviousError ()
1735 Report
.SymbolRelatedToPreviousError (gt
);
1741 /// A generic method definition.
1743 public class GenericMethod
: DeclSpace
1745 Expression return_type
;
1746 Parameters parameters
;
1748 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1749 Expression return_type
, Parameters parameters
)
1750 : base (ns
, parent
, name
, null)
1752 this.return_type
= return_type
;
1753 this.parameters
= parameters
;
1756 public override TypeBuilder
DefineType ()
1758 throw new Exception ();
1761 public override bool Define ()
1763 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1764 if (!TypeParameters
[i
].Resolve (this))
1771 /// Define and resolve the type parameters.
1772 /// We're called from Method.Define().
1774 public bool Define (MethodBuilder mb
)
1776 GenericTypeParameterBuilder
[] gen_params
;
1777 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1778 string[] snames
= new string [names
.Length
];
1779 for (int i
= 0; i
< names
.Length
; i
++)
1780 snames
[i
] = names
[i
].Name
;
1781 gen_params
= mb
.DefineGenericParameters (snames
);
1782 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1783 TypeParameters
[i
].Define (gen_params
[i
]);
1788 for (int i
= 0; i
< TypeParameters
.Length
; i
++) {
1789 if (!TypeParameters
[i
].ResolveType (this))
1797 /// We're called from MethodData.Define() after creating the MethodBuilder.
1799 public bool DefineType (EmitContext ec
, MethodBuilder mb
,
1800 MethodInfo implementing
, bool is_override
)
1802 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1803 if (!TypeParameters
[i
].DefineType (
1804 ec
, mb
, implementing
, is_override
))
1808 foreach (Parameter p
in parameters
.FixedParameters
){
1809 if (!p
.Resolve (ec
))
1812 if ((return_type
!= null) && (return_type
.ResolveAsTypeTerminal (ec
, false) == null))
1818 public void EmitAttributes ()
1820 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1821 TypeParameters
[i
].EmitAttributes ();
1823 if (OptAttributes
!= null)
1824 OptAttributes
.Emit ();
1827 public override bool DefineMembers ()
1832 public override MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
1833 MemberFilter filter
, object criteria
)
1835 throw new Exception ();
1838 public override MemberCache MemberCache
{
1844 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
1846 base.ApplyAttributeBuilder (a
, cb
);
1849 public override AttributeTargets AttributeTargets
{
1851 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
1855 public override string DocCommentHeader
{
1856 get { return "M:"; }
1860 public class DefaultValueExpression
: Expression
1864 public DefaultValueExpression (Expression expr
, Location loc
)
1870 public override Expression
DoResolve (EmitContext ec
)
1872 TypeExpr texpr
= expr
.ResolveAsTypeTerminal (ec
, false);
1878 eclass
= ExprClass
.Variable
;
1882 public override void Emit (EmitContext ec
)
1884 if (type
.IsGenericParameter
|| TypeManager
.IsValueType (type
)) {
1885 LocalTemporary temp_storage
= new LocalTemporary (type
);
1887 temp_storage
.AddressOf (ec
, AddressOp
.LoadStore
);
1888 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
1889 temp_storage
.Emit (ec
);
1891 ec
.ig
.Emit (OpCodes
.Ldnull
);
1895 public class NullableType
: TypeExpr
1897 Expression underlying
;
1899 public NullableType (Expression underlying
, Location l
)
1901 this.underlying
= underlying
;
1904 eclass
= ExprClass
.Type
;
1907 public NullableType (Type type
, Location loc
)
1908 : this (new TypeExpression (type
, loc
), loc
)
1911 public override string Name
{
1912 get { return underlying.ToString () + "?"; }
1915 public override string FullName
{
1916 get { return underlying.ToString () + "?"; }
1919 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
1921 TypeArguments args
= new TypeArguments (loc
);
1922 args
.Add (underlying
);
1924 ConstructedType ctype
= new ConstructedType (TypeManager
.generic_nullable_type
, args
, loc
);
1925 return ctype
.ResolveAsTypeTerminal (ec
, false);
1929 public partial class TypeManager
1932 // A list of core types that the compiler requires or uses
1934 static public Type activator_type
;
1935 static public Type generic_ienumerator_type
;
1936 static public Type generic_ienumerable_type
;
1937 static public Type generic_nullable_type
;
1940 // Tracks the generic parameters.
1942 static PtrHashtable builder_to_type_param
;
1945 // These methods are called by code generated by the compiler
1947 static public MethodInfo activator_create_instance
;
1949 static void InitGenerics ()
1951 builder_to_type_param
= new PtrHashtable ();
1954 static void CleanUpGenerics ()
1956 builder_to_type_param
= null;
1959 static void InitGenericCoreTypes ()
1961 activator_type
= CoreLookupType ("System", "Activator");
1963 generic_ienumerator_type
= CoreLookupType (
1964 "System.Collections.Generic", "IEnumerator", 1);
1965 generic_ienumerable_type
= CoreLookupType (
1966 "System.Collections.Generic", "IEnumerable", 1);
1967 generic_nullable_type
= CoreLookupType (
1968 "System", "Nullable", 1);
1971 static void InitGenericCodeHelpers ()
1974 Type
[] type_arg
= { type_type }
;
1975 activator_create_instance
= GetMethod (
1976 activator_type
, "CreateInstance", type_arg
);
1979 static Type
CoreLookupType (string ns
, string name
, int arity
)
1981 return CoreLookupType (ns
, MemberName
.MakeName (name
, arity
));
1984 public static void AddTypeParameter (Type t
, TypeParameter tparam
)
1986 if (!builder_to_type_param
.Contains (t
))
1987 builder_to_type_param
.Add (t
, tparam
);
1990 public static TypeContainer
LookupGenericTypeContainer (Type t
)
1992 t
= DropGenericTypeArguments (t
);
1993 return LookupTypeContainer (t
);
1996 public static TypeParameter
LookupTypeParameter (Type t
)
1998 return (TypeParameter
) builder_to_type_param
[t
];
2001 public static GenericConstraints
GetTypeParameterConstraints (Type t
)
2003 if (!t
.IsGenericParameter
)
2004 throw new InvalidOperationException ();
2006 TypeParameter tparam
= LookupTypeParameter (t
);
2008 return tparam
.GenericConstraints
;
2010 return ReflectionConstraints
.GetConstraints (t
);
2013 public static bool HasGenericArguments (Type t
)
2015 return GetNumberOfTypeArguments (t
) > 0;
2018 public static int GetNumberOfTypeArguments (Type t
)
2020 if (t
.IsGenericParameter
)
2022 DeclSpace tc
= LookupDeclSpace (t
);
2024 return tc
.IsGeneric
? tc
.CountTypeParameters
: 0;
2026 return t
.IsGenericType
? t
.GetGenericArguments ().Length
: 0;
2029 public static Type
[] GetTypeArguments (Type t
)
2031 DeclSpace tc
= LookupDeclSpace (t
);
2034 return Type
.EmptyTypes
;
2036 TypeParameter
[] tparam
= tc
.TypeParameters
;
2037 Type
[] ret
= new Type
[tparam
.Length
];
2038 for (int i
= 0; i
< tparam
.Length
; i
++) {
2039 ret
[i
] = tparam
[i
].Type
;
2040 if (ret
[i
] == null)
2041 throw new InternalErrorException ();
2046 return t
.GetGenericArguments ();
2049 public static Type
DropGenericTypeArguments (Type t
)
2051 if (!t
.IsGenericType
)
2053 // Micro-optimization: a generic typebuilder is always a generic type definition
2054 if (t
is TypeBuilder
)
2056 return t
.GetGenericTypeDefinition ();
2059 public static MethodBase
DropGenericMethodArguments (MethodBase m
)
2061 if (m
.IsGenericMethodDefinition
)
2063 if (m
.IsGenericMethod
)
2064 return ((MethodInfo
) m
).GetGenericMethodDefinition ();
2065 if (!m
.DeclaringType
.IsGenericType
)
2068 Type t
= m
.DeclaringType
.GetGenericTypeDefinition ();
2069 BindingFlags bf
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
2070 BindingFlags
.Static
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
;
2072 if (m
is ConstructorInfo
) {
2073 foreach (ConstructorInfo c
in t
.GetConstructors (bf
))
2074 if (c
.MetadataToken
== m
.MetadataToken
)
2077 foreach (MethodBase mb
in t
.GetMethods (bf
))
2078 if (mb
.MetadataToken
== m
.MetadataToken
)
2085 public static FieldInfo
GetGenericFieldDefinition (FieldInfo fi
)
2087 if (fi
.DeclaringType
.IsGenericTypeDefinition
||
2088 !fi
.DeclaringType
.IsGenericType
)
2091 Type t
= fi
.DeclaringType
.GetGenericTypeDefinition ();
2092 BindingFlags bf
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
2093 BindingFlags
.Static
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
;
2095 foreach (FieldInfo f
in t
.GetFields (bf
))
2096 if (f
.MetadataToken
== fi
.MetadataToken
)
2103 // Whether `array' is an array of T and `enumerator' is `IEnumerable<T>'.
2104 // For instance "string[]" -> "IEnumerable<string>".
2106 public static bool IsIEnumerable (Type array
, Type enumerator
)
2108 if (!array
.IsArray
|| !enumerator
.IsGenericType
)
2111 if (enumerator
.GetGenericTypeDefinition () != generic_ienumerable_type
)
2114 Type
[] args
= GetTypeArguments (enumerator
);
2115 return args
[0] == GetElementType (array
);
2118 public static bool IsEqual (Type a
, Type b
)
2123 if (a
.IsGenericParameter
&& b
.IsGenericParameter
) {
2124 if (a
.DeclaringMethod
!= b
.DeclaringMethod
&&
2125 (a
.DeclaringMethod
== null || b
.DeclaringMethod
== null))
2127 return a
.GenericParameterPosition
== b
.GenericParameterPosition
;
2130 if (a
.IsArray
&& b
.IsArray
) {
2131 if (a
.GetArrayRank () != b
.GetArrayRank ())
2133 return IsEqual (a
.GetElementType (), b
.GetElementType ());
2136 if (a
.IsByRef
&& b
.IsByRef
)
2137 return IsEqual (a
.GetElementType (), b
.GetElementType ());
2139 if (a
.IsGenericType
&& b
.IsGenericType
) {
2140 if (a
.GetGenericTypeDefinition () != b
.GetGenericTypeDefinition ())
2143 Type
[] aargs
= a
.GetGenericArguments ();
2144 Type
[] bargs
= b
.GetGenericArguments ();
2146 if (aargs
.Length
!= bargs
.Length
)
2149 for (int i
= 0; i
< aargs
.Length
; i
++) {
2150 if (!IsEqual (aargs
[i
], bargs
[i
]))
2158 // This is to build with the broken circular dependencies between
2159 // System and System.Configuration in the 2.x profile where we
2160 // end up with a situation where:
2162 // System on the second build is referencing the System.Configuration
2163 // that has references to the first System build.
2165 // Point in case: NameValueCollection built on the first pass, vs
2166 // NameValueCollection build on the second one. The problem is that
2167 // we need to override some methods sometimes, or we need to
2169 if (RootContext
.BrokenCircularDeps
){
2170 if (a
.Name
== b
.Name
&& a
.Namespace
== b
.Namespace
){
2171 Console
.WriteLine ("GonziMatch: {0}.{1}", a
.Namespace
, a
.Name
);
2179 /// Check whether `a' and `b' may become equal generic types.
2180 /// The algorithm to do that is a little bit complicated.
2182 public static bool MayBecomeEqualGenericTypes (Type a
, Type b
, Type
[] class_infered
,
2183 Type
[] method_infered
)
2185 if (a
.IsGenericParameter
) {
2187 // If a is an array of a's type, they may never
2191 b
= b
.GetElementType ();
2197 // If b is a generic parameter or an actual type,
2198 // they may become equal:
2200 // class X<T,U> : I<T>, I<U>
2201 // class X<T> : I<T>, I<float>
2203 if (b
.IsGenericParameter
|| !b
.IsGenericType
) {
2204 int pos
= a
.GenericParameterPosition
;
2205 Type
[] args
= a
.DeclaringMethod
!= null ? method_infered
: class_infered
;
2206 if (args
[pos
] == null) {
2211 return args
[pos
] == a
;
2215 // We're now comparing a type parameter with a
2216 // generic instance. They may become equal unless
2217 // the type parameter appears anywhere in the
2218 // generic instance:
2220 // class X<T,U> : I<T>, I<X<U>>
2221 // -> error because you could instanciate it as
2224 // class X<T> : I<T>, I<X<T>> -> ok
2227 Type
[] bargs
= GetTypeArguments (b
);
2228 for (int i
= 0; i
< bargs
.Length
; i
++) {
2229 if (a
.Equals (bargs
[i
]))
2236 if (b
.IsGenericParameter
)
2237 return MayBecomeEqualGenericTypes (b
, a
, class_infered
, method_infered
);
2240 // At this point, neither a nor b are a type parameter.
2242 // If one of them is a generic instance, let
2243 // MayBecomeEqualGenericInstances() compare them (if the
2244 // other one is not a generic instance, they can never
2248 if (a
.IsGenericType
|| b
.IsGenericType
)
2249 return MayBecomeEqualGenericInstances (a
, b
, class_infered
, method_infered
);
2252 // If both of them are arrays.
2255 if (a
.IsArray
&& b
.IsArray
) {
2256 if (a
.GetArrayRank () != b
.GetArrayRank ())
2259 a
= a
.GetElementType ();
2260 b
= b
.GetElementType ();
2262 return MayBecomeEqualGenericTypes (a
, b
, class_infered
, method_infered
);
2266 // Ok, two ordinary types.
2269 return a
.Equals (b
);
2273 // Checks whether two generic instances may become equal for some
2274 // particular instantiation (26.3.1).
2276 public static bool MayBecomeEqualGenericInstances (Type a
, Type b
,
2277 Type
[] class_infered
,
2278 Type
[] method_infered
)
2280 if (!a
.IsGenericType
|| !b
.IsGenericType
)
2282 if (a
.GetGenericTypeDefinition () != b
.GetGenericTypeDefinition ())
2285 return MayBecomeEqualGenericInstances (
2286 GetTypeArguments (a
), GetTypeArguments (b
), class_infered
, method_infered
);
2289 public static bool MayBecomeEqualGenericInstances (Type
[] aargs
, Type
[] bargs
,
2290 Type
[] class_infered
,
2291 Type
[] method_infered
)
2293 if (aargs
.Length
!= bargs
.Length
)
2296 for (int i
= 0; i
< aargs
.Length
; i
++) {
2297 if (!MayBecomeEqualGenericTypes (aargs
[i
], bargs
[i
], class_infered
, method_infered
))
2305 /// Check whether `type' and `parent' are both instantiations of the same
2306 /// generic type. Note that we do not check the type parameters here.
2308 public static bool IsInstantiationOfSameGenericType (Type type
, Type parent
)
2310 int tcount
= GetNumberOfTypeArguments (type
);
2311 int pcount
= GetNumberOfTypeArguments (parent
);
2313 if (tcount
!= pcount
)
2316 type
= DropGenericTypeArguments (type
);
2317 parent
= DropGenericTypeArguments (parent
);
2319 return type
.Equals (parent
);
2323 /// Whether `mb' is a generic method definition.
2325 public static bool IsGenericMethodDefinition (MethodBase mb
)
2327 if (mb
.DeclaringType
is TypeBuilder
) {
2328 IMethodData method
= (IMethodData
) builder_to_method
[mb
];
2332 return method
.GenericMethod
!= null;
2335 return mb
.IsGenericMethodDefinition
;
2339 /// Whether `mb' is a generic method definition.
2341 public static bool IsGenericMethod (MethodBase mb
)
2343 if (mb
.DeclaringType
is TypeBuilder
) {
2344 IMethodData method
= (IMethodData
) builder_to_method
[mb
];
2348 return method
.GenericMethod
!= null;
2351 return mb
.IsGenericMethod
;
2358 static bool InferType (Type pt
, Type at
, Type
[] infered
)
2360 if (pt
.IsGenericParameter
) {
2361 if (pt
.DeclaringMethod
== null)
2364 int pos
= pt
.GenericParameterPosition
;
2366 if (infered
[pos
] == null) {
2371 if (infered
[pos
] != at
)
2377 if (!pt
.ContainsGenericParameters
) {
2378 if (at
.ContainsGenericParameters
)
2379 return InferType (at
, pt
, infered
);
2386 if (at
.GetArrayRank () != pt
.GetArrayRank ())
2389 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2392 if (!pt
.IsGenericType
||
2393 (pt
.GetGenericTypeDefinition () != generic_ienumerable_type
))
2396 Type
[] args
= GetTypeArguments (pt
);
2397 return InferType (args
[0], at
.GetElementType (), infered
);
2402 (pt
.GetArrayRank () != at
.GetArrayRank ()))
2405 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2408 if (pt
.IsByRef
&& at
.IsByRef
)
2409 return InferType (pt
.GetElementType (), at
.GetElementType (), infered
);
2410 ArrayList list
= new ArrayList ();
2411 if (at
.IsGenericType
)
2413 for (Type bt
= at
.BaseType
; bt
!= null; bt
= bt
.BaseType
)
2416 list
.AddRange (TypeManager
.GetInterfaces (at
));
2418 bool found_one
= false;
2420 foreach (Type type
in list
) {
2421 if (!type
.IsGenericType
)
2424 Type
[] infered_types
= new Type
[infered
.Length
];
2426 if (!InferGenericInstance (pt
, type
, infered_types
))
2429 for (int i
= 0; i
< infered_types
.Length
; i
++) {
2430 if (infered
[i
] == null) {
2431 infered
[i
] = infered_types
[i
];
2435 if (infered
[i
] != infered_types
[i
])
2445 static bool InferGenericInstance (Type pt
, Type at
, Type
[] infered_types
)
2447 Type
[] at_args
= at
.GetGenericArguments ();
2448 Type
[] pt_args
= pt
.GetGenericArguments ();
2450 if (at_args
.Length
!= pt_args
.Length
)
2453 for (int i
= 0; i
< at_args
.Length
; i
++) {
2454 if (!InferType (pt_args
[i
], at_args
[i
], infered_types
))
2458 for (int i
= 0; i
< infered_types
.Length
; i
++) {
2459 if (infered_types
[i
] == null)
2467 /// Type inference. Try to infer the type arguments from the params method
2468 /// `method', which is invoked with the arguments `arguments'. This is used
2469 /// when resolving an Invocation or a DelegateInvocation and the user
2470 /// did not explicitly specify type arguments.
2472 public static bool InferParamsTypeArguments (EmitContext ec
, ArrayList arguments
,
2473 ref MethodBase method
)
2475 if ((arguments
== null) || !TypeManager
.IsGenericMethod (method
))
2480 if (arguments
== null)
2483 arg_count
= arguments
.Count
;
2485 ParameterData pd
= TypeManager
.GetParameterData (method
);
2487 int pd_count
= pd
.Count
;
2492 if (pd
.ParameterModifier (pd_count
- 1) != Parameter
.Modifier
.PARAMS
)
2495 if (pd_count
- 1 > arg_count
)
2498 if (pd_count
== 1 && arg_count
== 0)
2501 Type
[] method_args
= method
.GetGenericArguments ();
2502 Type
[] infered_types
= new Type
[method_args
.Length
];
2505 // If we have come this far, the case which
2506 // remains is when the number of parameters is
2507 // less than or equal to the argument count.
2509 for (int i
= 0; i
< pd_count
- 1; ++i
) {
2510 Argument a
= (Argument
) arguments
[i
];
2512 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2515 Type pt
= pd
.ParameterType (i
);
2518 if (!InferType (pt
, at
, infered_types
))
2522 Type element_type
= TypeManager
.GetElementType (pd
.ParameterType (pd_count
- 1));
2524 for (int i
= pd_count
- 1; i
< arg_count
; i
++) {
2525 Argument a
= (Argument
) arguments
[i
];
2527 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2530 if (!InferType (element_type
, a
.Type
, infered_types
))
2534 for (int i
= 0; i
< infered_types
.Length
; i
++)
2535 if (infered_types
[i
] == null)
2538 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2542 static bool InferTypeArguments (Type
[] param_types
, Type
[] arg_types
,
2543 Type
[] infered_types
)
2545 if (infered_types
== null)
2548 for (int i
= 0; i
< arg_types
.Length
; i
++) {
2549 if (arg_types
[i
] == null)
2552 if (!InferType (param_types
[i
], arg_types
[i
], infered_types
))
2556 for (int i
= 0; i
< infered_types
.Length
; i
++)
2557 if (infered_types
[i
] == null)
2564 /// Type inference. Try to infer the type arguments from `method',
2565 /// which is invoked with the arguments `arguments'. This is used
2566 /// when resolving an Invocation or a DelegateInvocation and the user
2567 /// did not explicitly specify type arguments.
2569 public static bool InferTypeArguments (ArrayList arguments
,
2570 ref MethodBase method
)
2572 if (!TypeManager
.IsGenericMethod (method
))
2576 if (arguments
!= null)
2577 arg_count
= arguments
.Count
;
2581 ParameterData pd
= TypeManager
.GetParameterData (method
);
2582 if (arg_count
!= pd
.Count
)
2585 Type
[] method_args
= method
.GetGenericArguments ();
2587 bool is_open
= false;
2588 for (int i
= 0; i
< method_args
.Length
; i
++) {
2589 if (method_args
[i
].IsGenericParameter
) {
2595 // If none of the method parameters mention a generic parameter, we can't infer the generic parameters
2597 return !TypeManager
.IsGenericMethodDefinition (method
);
2599 Type
[] infered_types
= new Type
[method_args
.Length
];
2601 Type
[] param_types
= new Type
[pd
.Count
];
2602 Type
[] arg_types
= new Type
[pd
.Count
];
2604 for (int i
= 0; i
< arg_count
; i
++) {
2605 param_types
[i
] = pd
.ParameterType (i
);
2607 Argument a
= (Argument
) arguments
[i
];
2608 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
) ||
2609 (a
.Expr
is AnonymousMethod
))
2612 arg_types
[i
] = a
.Type
;
2615 if (!InferTypeArguments (param_types
, arg_types
, infered_types
))
2618 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2625 public static bool InferTypeArguments (ParameterData apd
,
2626 ref MethodBase method
)
2628 if (!TypeManager
.IsGenericMethod (method
))
2631 ParameterData pd
= TypeManager
.GetParameterData (method
);
2632 if (apd
.Count
!= pd
.Count
)
2635 Type
[] method_args
= method
.GetGenericArguments ();
2636 Type
[] infered_types
= new Type
[method_args
.Length
];
2638 Type
[] param_types
= new Type
[pd
.Count
];
2639 Type
[] arg_types
= new Type
[pd
.Count
];
2641 for (int i
= 0; i
< apd
.Count
; i
++) {
2642 param_types
[i
] = pd
.ParameterType (i
);
2643 arg_types
[i
] = apd
.ParameterType (i
);
2646 if (!InferTypeArguments (param_types
, arg_types
, infered_types
))
2649 method
= ((MethodInfo
)method
).MakeGenericMethod (infered_types
);
2653 public static bool IsNullableType (Type t
)
2655 return generic_nullable_type
== DropGenericTypeArguments (t
);
2658 public static bool IsNullableValueType (Type t
)
2660 if (!IsNullableType (t
))
2663 return GetTypeArguments (t
) [0].IsValueType
;
2667 public abstract class Nullable
2669 protected sealed class NullableInfo
2671 public readonly Type Type
;
2672 public readonly Type UnderlyingType
;
2673 public readonly MethodInfo HasValue
;
2674 public readonly MethodInfo Value
;
2675 public readonly ConstructorInfo Constructor
;
2677 public NullableInfo (Type type
)
2680 UnderlyingType
= TypeManager
.GetTypeArguments (type
) [0];
2682 PropertyInfo has_value_pi
= TypeManager
.GetProperty (type
, "HasValue");
2683 PropertyInfo value_pi
= TypeManager
.GetProperty (type
, "Value");
2685 HasValue
= has_value_pi
.GetGetMethod (false);
2686 Value
= value_pi
.GetGetMethod (false);
2687 Constructor
= type
.GetConstructor (new Type
[] { UnderlyingType }
);
2691 protected class Unwrap
: Expression
, IMemoryLocation
, IAssignMethod
2696 LocalTemporary temp
;
2699 public Unwrap (Expression expr
, Location loc
)
2705 public override Expression
DoResolve (EmitContext ec
)
2707 expr
= expr
.Resolve (ec
);
2711 temp
= new LocalTemporary (expr
.Type
);
2713 info
= new NullableInfo (expr
.Type
);
2714 type
= info
.UnderlyingType
;
2715 eclass
= expr
.eclass
;
2719 public override void Emit (EmitContext ec
)
2721 AddressOf (ec
, AddressOp
.LoadStore
);
2722 ec
.ig
.EmitCall (OpCodes
.Call
, info
.Value
, null);
2725 public void EmitCheck (EmitContext ec
)
2727 AddressOf (ec
, AddressOp
.LoadStore
);
2728 ec
.ig
.EmitCall (OpCodes
.Call
, info
.HasValue
, null);
2731 public void Store (EmitContext ec
)
2736 void create_temp (EmitContext ec
)
2738 if ((temp
!= null) && !has_temp
) {
2745 public void AddressOf (EmitContext ec
, AddressOp mode
)
2749 temp
.AddressOf (ec
, AddressOp
.LoadStore
);
2751 ((IMemoryLocation
) expr
).AddressOf (ec
, AddressOp
.LoadStore
);
2754 public void Emit (EmitContext ec
, bool leave_copy
)
2767 public void EmitAssign (EmitContext ec
, Expression source
,
2768 bool leave_copy
, bool prepare_for_load
)
2770 InternalWrap wrap
= new InternalWrap (source
, info
, loc
);
2771 ((IAssignMethod
) expr
).EmitAssign (ec
, wrap
, leave_copy
, false);
2774 protected class InternalWrap
: Expression
2776 public Expression expr
;
2777 public NullableInfo info
;
2779 public InternalWrap (Expression expr
, NullableInfo info
, Location loc
)
2786 eclass
= ExprClass
.Value
;
2789 public override Expression
DoResolve (EmitContext ec
)
2794 public override void Emit (EmitContext ec
)
2797 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2802 protected class Wrap
: Expression
2807 public Wrap (Expression expr
, Location loc
)
2813 public override Expression
DoResolve (EmitContext ec
)
2815 expr
= expr
.Resolve (ec
);
2819 TypeExpr target_type
= new NullableType (expr
.Type
, loc
);
2820 target_type
= target_type
.ResolveAsTypeTerminal (ec
, false);
2821 if (target_type
== null)
2824 type
= target_type
.Type
;
2825 info
= new NullableInfo (type
);
2826 eclass
= ExprClass
.Value
;
2830 public override void Emit (EmitContext ec
)
2833 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2837 public class NullableLiteral
: NullLiteral
, IMemoryLocation
{
2838 public NullableLiteral (Type target_type
, Location loc
)
2841 this.type
= target_type
;
2843 eclass
= ExprClass
.Value
;
2846 public override Expression
DoResolve (EmitContext ec
)
2851 public override void Emit (EmitContext ec
)
2853 LocalTemporary value_target
= new LocalTemporary (type
);
2855 value_target
.AddressOf (ec
, AddressOp
.Store
);
2856 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2857 value_target
.Emit (ec
);
2860 public void AddressOf (EmitContext ec
, AddressOp Mode
)
2862 LocalTemporary value_target
= new LocalTemporary (type
);
2864 value_target
.AddressOf (ec
, AddressOp
.Store
);
2865 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2866 ((IMemoryLocation
) value_target
).AddressOf (ec
, Mode
);
2870 public abstract class Lifted
: Expression
, IMemoryLocation
2872 Expression expr
, underlying
, wrap
, null_value
;
2875 protected Lifted (Expression expr
, Location loc
)
2881 public override Expression
DoResolve (EmitContext ec
)
2883 expr
= expr
.Resolve (ec
);
2887 unwrap
= (Unwrap
) new Unwrap (expr
, loc
).Resolve (ec
);
2891 underlying
= ResolveUnderlying (unwrap
, ec
);
2892 if (underlying
== null)
2895 wrap
= new Wrap (underlying
, loc
).Resolve (ec
);
2899 null_value
= new NullableLiteral (wrap
.Type
, loc
).Resolve (ec
);
2900 if (null_value
== null)
2904 eclass
= ExprClass
.Value
;
2908 protected abstract Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
);
2910 public override void Emit (EmitContext ec
)
2912 ILGenerator ig
= ec
.ig
;
2913 Label is_null_label
= ig
.DefineLabel ();
2914 Label end_label
= ig
.DefineLabel ();
2916 unwrap
.EmitCheck (ec
);
2917 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
2920 ig
.Emit (OpCodes
.Br
, end_label
);
2922 ig
.MarkLabel (is_null_label
);
2923 null_value
.Emit (ec
);
2925 ig
.MarkLabel (end_label
);
2928 public void AddressOf (EmitContext ec
, AddressOp mode
)
2930 unwrap
.AddressOf (ec
, mode
);
2934 public class LiftedConversion
: Lifted
2936 public readonly bool IsUser
;
2937 public readonly bool IsExplicit
;
2938 public readonly Type TargetType
;
2940 public LiftedConversion (Expression expr
, Type target_type
, bool is_user
,
2941 bool is_explicit
, Location loc
)
2944 this.IsUser
= is_user
;
2945 this.IsExplicit
= is_explicit
;
2946 this.TargetType
= target_type
;
2949 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2951 Type type
= TypeManager
.GetTypeArguments (TargetType
) [0];
2954 return Convert
.UserDefinedConversion (ec
, unwrap
, type
, loc
, IsExplicit
);
2957 return Convert
.ExplicitConversion (ec
, unwrap
, type
, loc
);
2959 return Convert
.ImplicitConversion (ec
, unwrap
, type
, loc
);
2964 public class LiftedUnaryOperator
: Lifted
2966 public readonly Unary
.Operator Oper
;
2968 public LiftedUnaryOperator (Unary
.Operator op
, Expression expr
, Location loc
)
2974 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2976 return new Unary (Oper
, unwrap
, loc
);
2980 public class LiftedConditional
: Lifted
2982 Expression true_expr
, false_expr
;
2984 public LiftedConditional (Expression expr
, Expression true_expr
, Expression false_expr
,
2988 this.true_expr
= true_expr
;
2989 this.false_expr
= false_expr
;
2992 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
2994 return new Conditional (unwrap
, true_expr
, false_expr
);
2998 public class LiftedBinaryOperator
: Expression
3000 public readonly Binary
.Operator Oper
;
3002 Expression left
, right
, original_left
, original_right
;
3003 Expression underlying
, null_value
, bool_wrap
;
3004 Unwrap left_unwrap
, right_unwrap
;
3005 bool is_equality
, is_comparision
, is_boolean
;
3007 public LiftedBinaryOperator (Binary
.Operator op
, Expression left
, Expression right
,
3011 this.left
= original_left
= left
;
3012 this.right
= original_right
= right
;
3016 public override Expression
DoResolve (EmitContext ec
)
3018 if (TypeManager
.IsNullableType (left
.Type
)) {
3019 left_unwrap
= new Unwrap (left
, loc
);
3020 left
= left_unwrap
.Resolve (ec
);
3025 if (TypeManager
.IsNullableType (right
.Type
)) {
3026 right_unwrap
= new Unwrap (right
, loc
);
3027 right
= right_unwrap
.Resolve (ec
);
3032 if ((Oper
== Binary
.Operator
.LogicalAnd
) ||
3033 (Oper
== Binary
.Operator
.LogicalOr
)) {
3034 Binary
.Error_OperatorCannotBeApplied (
3035 loc
, Binary
.OperName (Oper
),
3036 original_left
.GetSignatureForError (),
3037 original_right
.GetSignatureForError ());
3041 if (((Oper
== Binary
.Operator
.BitwiseAnd
) || (Oper
== Binary
.Operator
.BitwiseOr
)) &&
3042 ((left
.Type
== TypeManager
.bool_type
) && (right
.Type
== TypeManager
.bool_type
))) {
3043 Expression empty
= new EmptyExpression (TypeManager
.bool_type
);
3044 bool_wrap
= new Wrap (empty
, loc
).Resolve (ec
);
3045 null_value
= new NullableLiteral (bool_wrap
.Type
, loc
).Resolve (ec
);
3047 type
= bool_wrap
.Type
;
3049 } else if ((Oper
== Binary
.Operator
.Equality
) || (Oper
== Binary
.Operator
.Inequality
)) {
3050 if (!(left
is NullLiteral
) && !(right
is NullLiteral
)) {
3051 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3052 if (underlying
== null)
3056 type
= TypeManager
.bool_type
;
3058 } else if ((Oper
== Binary
.Operator
.LessThan
) ||
3059 (Oper
== Binary
.Operator
.GreaterThan
) ||
3060 (Oper
== Binary
.Operator
.LessThanOrEqual
) ||
3061 (Oper
== Binary
.Operator
.GreaterThanOrEqual
)) {
3062 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3063 if (underlying
== null)
3066 type
= TypeManager
.bool_type
;
3067 is_comparision
= true;
3069 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3070 if (underlying
== null)
3073 underlying
= new Wrap (underlying
, loc
).Resolve (ec
);
3074 if (underlying
== null)
3077 type
= underlying
.Type
;
3078 null_value
= new NullableLiteral (type
, loc
).Resolve (ec
);
3081 eclass
= ExprClass
.Value
;
3085 void EmitBoolean (EmitContext ec
)
3087 ILGenerator ig
= ec
.ig
;
3089 Label left_is_null_label
= ig
.DefineLabel ();
3090 Label right_is_null_label
= ig
.DefineLabel ();
3091 Label is_null_label
= ig
.DefineLabel ();
3092 Label wrap_label
= ig
.DefineLabel ();
3093 Label end_label
= ig
.DefineLabel ();
3095 if (left_unwrap
!= null) {
3096 left_unwrap
.EmitCheck (ec
);
3097 ig
.Emit (OpCodes
.Brfalse
, left_is_null_label
);
3101 ig
.Emit (OpCodes
.Dup
);
3102 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOr
))
3103 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
3105 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
3107 if (right_unwrap
!= null) {
3108 right_unwrap
.EmitCheck (ec
);
3109 ig
.Emit (OpCodes
.Brfalse
, right_is_null_label
);
3112 if ((Oper
== Binary
.Operator
.LogicalAnd
) || (Oper
== Binary
.Operator
.LogicalOr
))
3113 ig
.Emit (OpCodes
.Pop
);
3116 if (Oper
== Binary
.Operator
.BitwiseOr
)
3117 ig
.Emit (OpCodes
.Or
);
3118 else if (Oper
== Binary
.Operator
.BitwiseAnd
)
3119 ig
.Emit (OpCodes
.And
);
3120 ig
.Emit (OpCodes
.Br
, wrap_label
);
3122 ig
.MarkLabel (left_is_null_label
);
3123 if (right_unwrap
!= null) {
3124 right_unwrap
.EmitCheck (ec
);
3125 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3129 ig
.Emit (OpCodes
.Dup
);
3130 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOr
))
3131 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
3133 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
3135 ig
.MarkLabel (right_is_null_label
);
3136 ig
.Emit (OpCodes
.Pop
);
3137 ig
.MarkLabel (is_null_label
);
3138 null_value
.Emit (ec
);
3139 ig
.Emit (OpCodes
.Br
, end_label
);
3141 ig
.MarkLabel (wrap_label
);
3142 ig
.Emit (OpCodes
.Nop
);
3143 bool_wrap
.Emit (ec
);
3144 ig
.Emit (OpCodes
.Nop
);
3146 ig
.MarkLabel (end_label
);
3149 void EmitEquality (EmitContext ec
)
3151 ILGenerator ig
= ec
.ig
;
3153 Label left_not_null_label
= ig
.DefineLabel ();
3154 Label false_label
= ig
.DefineLabel ();
3155 Label true_label
= ig
.DefineLabel ();
3156 Label end_label
= ig
.DefineLabel ();
3158 bool false_label_used
= false;
3159 bool true_label_used
= false;
3161 if (left_unwrap
!= null) {
3162 left_unwrap
.EmitCheck (ec
);
3163 if (right
is NullLiteral
) {
3164 if (Oper
== Binary
.Operator
.Equality
) {
3165 true_label_used
= true;
3166 ig
.Emit (OpCodes
.Brfalse
, true_label
);
3168 false_label_used
= true;
3169 ig
.Emit (OpCodes
.Brfalse
, false_label
);
3171 } else if (right_unwrap
!= null) {
3172 ig
.Emit (OpCodes
.Dup
);
3173 ig
.Emit (OpCodes
.Brtrue
, left_not_null_label
);
3174 right_unwrap
.EmitCheck (ec
);
3175 ig
.Emit (OpCodes
.Ceq
);
3176 if (Oper
== Binary
.Operator
.Inequality
) {
3177 ig
.Emit (OpCodes
.Ldc_I4_0
);
3178 ig
.Emit (OpCodes
.Ceq
);
3180 ig
.Emit (OpCodes
.Br
, end_label
);
3182 ig
.MarkLabel (left_not_null_label
);
3183 ig
.Emit (OpCodes
.Pop
);
3185 if (Oper
== Binary
.Operator
.Equality
) {
3186 false_label_used
= true;
3187 ig
.Emit (OpCodes
.Brfalse
, false_label
);
3189 true_label_used
= true;
3190 ig
.Emit (OpCodes
.Brfalse
, true_label
);
3195 if (right_unwrap
!= null) {
3196 right_unwrap
.EmitCheck (ec
);
3197 if (left
is NullLiteral
) {
3198 if (Oper
== Binary
.Operator
.Equality
) {
3199 true_label_used
= true;
3200 ig
.Emit (OpCodes
.Brfalse
, true_label
);
3202 false_label_used
= true;
3203 ig
.Emit (OpCodes
.Brfalse
, false_label
);
3206 if (Oper
== Binary
.Operator
.Equality
) {
3207 false_label_used
= true;
3208 ig
.Emit (OpCodes
.Brfalse
, false_label
);
3210 true_label_used
= true;
3211 ig
.Emit (OpCodes
.Brfalse
, true_label
);
3216 bool left_is_null
= left
is NullLiteral
;
3217 bool right_is_null
= right
is NullLiteral
;
3218 if (left_is_null
|| right_is_null
) {
3219 if (((Oper
== Binary
.Operator
.Equality
) && (left_is_null
== right_is_null
)) ||
3220 ((Oper
== Binary
.Operator
.Inequality
) && (left_is_null
!= right_is_null
))) {
3221 true_label_used
= true;
3222 ig
.Emit (OpCodes
.Br
, true_label
);
3224 false_label_used
= true;
3225 ig
.Emit (OpCodes
.Br
, false_label
);
3228 underlying
.Emit (ec
);
3229 ig
.Emit (OpCodes
.Br
, end_label
);
3232 ig
.MarkLabel (false_label
);
3233 if (false_label_used
) {
3234 ig
.Emit (OpCodes
.Ldc_I4_0
);
3235 if (true_label_used
)
3236 ig
.Emit (OpCodes
.Br
, end_label
);
3239 ig
.MarkLabel (true_label
);
3240 if (true_label_used
)
3241 ig
.Emit (OpCodes
.Ldc_I4_1
);
3243 ig
.MarkLabel (end_label
);
3246 void EmitComparision (EmitContext ec
)
3248 ILGenerator ig
= ec
.ig
;
3250 Label is_null_label
= ig
.DefineLabel ();
3251 Label end_label
= ig
.DefineLabel ();
3253 if (left_unwrap
!= null) {
3254 left_unwrap
.EmitCheck (ec
);
3255 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3258 if (right_unwrap
!= null) {
3259 right_unwrap
.EmitCheck (ec
);
3260 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3263 underlying
.Emit (ec
);
3264 ig
.Emit (OpCodes
.Br
, end_label
);
3266 ig
.MarkLabel (is_null_label
);
3267 ig
.Emit (OpCodes
.Ldc_I4_0
);
3269 ig
.MarkLabel (end_label
);
3272 public override void Emit (EmitContext ec
)
3274 if (left_unwrap
!= null)
3275 left_unwrap
.Store (ec
);
3276 if (right_unwrap
!= null)
3277 right_unwrap
.Store (ec
);
3282 } else if (is_equality
) {
3285 } else if (is_comparision
) {
3286 EmitComparision (ec
);
3290 ILGenerator ig
= ec
.ig
;
3292 Label is_null_label
= ig
.DefineLabel ();
3293 Label end_label
= ig
.DefineLabel ();
3295 if (left_unwrap
!= null) {
3296 left_unwrap
.EmitCheck (ec
);
3297 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3300 if (right_unwrap
!= null) {
3301 right_unwrap
.EmitCheck (ec
);
3302 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3305 underlying
.Emit (ec
);
3306 ig
.Emit (OpCodes
.Br
, end_label
);
3308 ig
.MarkLabel (is_null_label
);
3309 null_value
.Emit (ec
);
3311 ig
.MarkLabel (end_label
);
3315 public class OperatorTrueOrFalse
: Expression
3317 public readonly bool IsTrue
;
3322 public OperatorTrueOrFalse (Expression expr
, bool is_true
, Location loc
)
3324 this.IsTrue
= is_true
;
3329 public override Expression
DoResolve (EmitContext ec
)
3331 unwrap
= new Unwrap (expr
, loc
);
3332 expr
= unwrap
.Resolve (ec
);
3336 if (unwrap
.Type
!= TypeManager
.bool_type
)
3339 type
= TypeManager
.bool_type
;
3340 eclass
= ExprClass
.Value
;
3344 public override void Emit (EmitContext ec
)
3346 ILGenerator ig
= ec
.ig
;
3348 Label is_null_label
= ig
.DefineLabel ();
3349 Label end_label
= ig
.DefineLabel ();
3351 unwrap
.EmitCheck (ec
);
3352 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3356 ig
.Emit (OpCodes
.Ldc_I4_0
);
3357 ig
.Emit (OpCodes
.Ceq
);
3359 ig
.Emit (OpCodes
.Br
, end_label
);
3361 ig
.MarkLabel (is_null_label
);
3362 ig
.Emit (OpCodes
.Ldc_I4_0
);
3364 ig
.MarkLabel (end_label
);
3368 public class NullCoalescingOperator
: Expression
3370 Expression left
, right
;
3374 public NullCoalescingOperator (Expression left
, Expression right
, Location loc
)
3380 eclass
= ExprClass
.Value
;
3383 public override Expression
DoResolve (EmitContext ec
)
3388 left
= left
.Resolve (ec
);
3392 right
= right
.Resolve (ec
);
3396 Type ltype
= left
.Type
, rtype
= right
.Type
;
3398 if (!TypeManager
.IsNullableType (ltype
) && ltype
.IsValueType
) {
3399 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
3403 if (TypeManager
.IsNullableType (ltype
)) {
3404 NullableInfo info
= new NullableInfo (ltype
);
3406 unwrap
= (Unwrap
) new Unwrap (left
, loc
).Resolve (ec
);
3410 expr
= Convert
.ImplicitConversion (ec
, right
, info
.UnderlyingType
, loc
);
3418 expr
= Convert
.ImplicitConversion (ec
, right
, ltype
, loc
);
3424 if (unwrap
!= null) {
3425 expr
= Convert
.ImplicitConversion (ec
, unwrap
, rtype
, loc
);
3434 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
3438 public override void Emit (EmitContext ec
)
3440 ILGenerator ig
= ec
.ig
;
3442 Label is_null_label
= ig
.DefineLabel ();
3443 Label end_label
= ig
.DefineLabel ();
3445 if (unwrap
!= null) {
3446 unwrap
.EmitCheck (ec
);
3447 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3450 ig
.Emit (OpCodes
.Br
, end_label
);
3452 ig
.MarkLabel (is_null_label
);
3455 ig
.MarkLabel (end_label
);
3458 ig
.Emit (OpCodes
.Dup
);
3459 ig
.Emit (OpCodes
.Brtrue
, end_label
);
3461 ig
.MarkLabel (is_null_label
);
3463 ig
.Emit (OpCodes
.Pop
);
3466 ig
.MarkLabel (end_label
);
3471 public class LiftedUnaryMutator
: ExpressionStatement
3473 public readonly UnaryMutator
.Mode Mode
;
3474 Expression expr
, null_value
;
3475 UnaryMutator underlying
;
3478 public LiftedUnaryMutator (UnaryMutator
.Mode mode
, Expression expr
, Location loc
)
3484 eclass
= ExprClass
.Value
;
3487 public override Expression
DoResolve (EmitContext ec
)
3489 expr
= expr
.Resolve (ec
);
3493 unwrap
= (Unwrap
) new Unwrap (expr
, loc
).Resolve (ec
);
3497 underlying
= (UnaryMutator
) new UnaryMutator (Mode
, unwrap
, loc
).Resolve (ec
);
3498 if (underlying
== null)
3501 null_value
= new NullableLiteral (expr
.Type
, loc
).Resolve (ec
);
3502 if (null_value
== null)
3509 void DoEmit (EmitContext ec
, bool is_expr
)
3511 ILGenerator ig
= ec
.ig
;
3512 Label is_null_label
= ig
.DefineLabel ();
3513 Label end_label
= ig
.DefineLabel ();
3515 unwrap
.EmitCheck (ec
);
3516 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3519 underlying
.Emit (ec
);
3521 underlying
.EmitStatement (ec
);
3522 ig
.Emit (OpCodes
.Br
, end_label
);
3524 ig
.MarkLabel (is_null_label
);
3526 null_value
.Emit (ec
);
3528 ig
.MarkLabel (end_label
);
3531 public override void Emit (EmitContext ec
)
3536 public override void EmitStatement (EmitContext ec
)