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 public Constraints
Clone ()
161 return new Constraints (name
, constraints
, loc
);
164 GenericParameterAttributes attrs
;
165 TypeExpr class_constraint
;
166 ArrayList iface_constraints
;
167 ArrayList type_param_constraints
;
169 Type class_constraint_type
;
170 Type
[] iface_constraint_types
;
171 Type effective_base_type
;
176 /// Resolve the constraints - but only resolve things into Expression's, not
177 /// into actual types.
179 public bool Resolve (IResolveContext ec
)
184 iface_constraints
= new ArrayList ();
185 type_param_constraints
= new ArrayList ();
187 foreach (object obj
in constraints
) {
188 if (HasConstructorConstraint
) {
189 Report
.Error (401, loc
,
190 "The new() constraint must be the last constraint specified");
194 if (obj
is SpecialConstraint
) {
195 SpecialConstraint sc
= (SpecialConstraint
) obj
;
197 if (sc
== SpecialConstraint
.Constructor
) {
198 if (!HasValueTypeConstraint
) {
199 attrs
|= GenericParameterAttributes
.DefaultConstructorConstraint
;
203 Report
.Error (451, loc
, "The `new()' constraint " +
204 "cannot be used with the `struct' constraint");
208 if ((num_constraints
> 0) || HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
209 Report
.Error (449, loc
, "The `class' or `struct' " +
210 "constraint must be the first constraint specified");
214 if (sc
== SpecialConstraint
.ReferenceType
)
215 attrs
|= GenericParameterAttributes
.ReferenceTypeConstraint
;
217 attrs
|= GenericParameterAttributes
.NotNullableValueTypeConstraint
;
221 int errors
= Report
.Errors
;
222 FullNamedExpression fn
= ((Expression
) obj
).ResolveAsTypeStep (ec
, false);
225 if (errors
!= Report
.Errors
)
228 NamespaceEntry
.Error_NamespaceNotFound (loc
, ((Expression
)obj
).GetSignatureForError ());
233 ConstructedType cexpr
= fn
as ConstructedType
;
235 if (!cexpr
.ResolveConstructedType (ec
))
240 expr
= ((Expression
) obj
).ResolveAsTypeTerminal (ec
, false);
242 if ((expr
== null) || (expr
.Type
== null))
245 // TODO: It's aleady done in ResolveAsBaseTerminal
246 if (!ec
.GenericDeclContainer
.AsAccessible (fn
.Type
, ec
.GenericDeclContainer
.ModFlags
)) {
247 Report
.SymbolRelatedToPreviousError (fn
.Type
);
248 Report
.Error (703, loc
,
249 "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
250 fn
.GetSignatureForError (), ec
.GenericDeclContainer
.GetSignatureForError ());
254 TypeParameterExpr texpr
= expr
as TypeParameterExpr
;
256 type_param_constraints
.Add (expr
);
257 else if (expr
.IsInterface
)
258 iface_constraints
.Add (expr
);
259 else if (class_constraint
!= null) {
260 Report
.Error (406, loc
,
261 "`{0}': the class constraint for `{1}' " +
262 "must come before any other constraints.",
265 } else if (HasReferenceTypeConstraint
|| HasValueTypeConstraint
) {
266 Report
.Error (450, loc
, "`{0}': cannot specify both " +
267 "a constraint class and the `class' " +
268 "or `struct' constraint", expr
.GetSignatureForError ());
271 class_constraint
= expr
;
276 ArrayList list
= new ArrayList ();
277 foreach (TypeExpr iface_constraint
in iface_constraints
) {
278 foreach (Type type
in list
) {
279 if (!type
.Equals (iface_constraint
.Type
))
282 Report
.Error (405, loc
,
283 "Duplicate constraint `{0}' for type " +
284 "parameter `{1}'.", iface_constraint
.GetSignatureForError (),
289 list
.Add (iface_constraint
.Type
);
292 foreach (TypeParameterExpr expr
in type_param_constraints
) {
293 foreach (Type type
in list
) {
294 if (!type
.Equals (expr
.Type
))
297 Report
.Error (405, loc
,
298 "Duplicate constraint `{0}' for type " +
299 "parameter `{1}'.", expr
.GetSignatureForError (), name
);
303 list
.Add (expr
.Type
);
306 iface_constraint_types
= new Type
[list
.Count
];
307 list
.CopyTo (iface_constraint_types
, 0);
309 if (class_constraint
!= null) {
310 class_constraint_type
= class_constraint
.Type
;
311 if (class_constraint_type
== null)
314 if (class_constraint_type
.IsSealed
) {
315 if (class_constraint_type
.IsAbstract
)
317 Report
.Error (717, loc
, "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
318 TypeManager
.CSharpName (class_constraint_type
));
322 Report
.Error (701, loc
, "`{0}' is not a valid constraint. A constraint must be an interface, " +
323 "a non-sealed class or a type parameter", TypeManager
.CSharpName(class_constraint_type
));
328 if ((class_constraint_type
== TypeManager
.array_type
) ||
329 (class_constraint_type
== TypeManager
.delegate_type
) ||
330 (class_constraint_type
== TypeManager
.enum_type
) ||
331 (class_constraint_type
== TypeManager
.value_type
) ||
332 (class_constraint_type
== TypeManager
.object_type
)) {
333 Report
.Error (702, loc
,
334 "Bound cannot be special class `{0}'",
335 TypeManager
.CSharpName (class_constraint_type
));
340 if (class_constraint_type
!= null)
341 effective_base_type
= class_constraint_type
;
342 else if (HasValueTypeConstraint
)
343 effective_base_type
= TypeManager
.value_type
;
345 effective_base_type
= TypeManager
.object_type
;
351 bool CheckTypeParameterConstraints (TypeParameter tparam
, Hashtable seen
)
353 seen
.Add (tparam
, true);
355 Constraints constraints
= tparam
.Constraints
;
356 if (constraints
== null)
359 if (constraints
.HasValueTypeConstraint
) {
360 Report
.Error (456, loc
, "Type parameter `{0}' has " +
361 "the `struct' constraint, so it cannot " +
362 "be used as a constraint for `{1}'",
367 if (constraints
.type_param_constraints
== null)
370 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
371 if (seen
.Contains (expr
.TypeParameter
)) {
372 Report
.Error (454, loc
, "Circular constraint " +
373 "dependency involving `{0}' and `{1}'",
374 tparam
.Name
, expr
.Name
);
378 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
386 /// Resolve the constraints into actual types.
388 public bool ResolveTypes (IResolveContext ec
)
393 resolved_types
= true;
395 foreach (object obj
in constraints
) {
396 ConstructedType cexpr
= obj
as ConstructedType
;
400 if (!cexpr
.CheckConstraints (ec
))
404 foreach (TypeParameterExpr expr
in type_param_constraints
) {
405 Hashtable seen
= new Hashtable ();
406 if (!CheckTypeParameterConstraints (expr
.TypeParameter
, seen
))
410 for (int i
= 0; i
< iface_constraints
.Count
; ++i
) {
411 TypeExpr iface_constraint
= (TypeExpr
) iface_constraints
[i
];
412 iface_constraint
= iface_constraint
.ResolveAsTypeTerminal (ec
, false);
413 if (iface_constraint
== null)
415 iface_constraints
[i
] = iface_constraint
;
418 if (class_constraint
!= null) {
419 class_constraint
= class_constraint
.ResolveAsTypeTerminal (ec
, false);
420 if (class_constraint
== null)
428 /// Check whether there are no conflicts in our type parameter constraints.
430 /// This is an example:
434 /// where U : T, struct
436 public bool CheckDependencies ()
438 foreach (TypeParameterExpr expr
in type_param_constraints
) {
439 if (!CheckDependencies (expr
.TypeParameter
))
446 bool CheckDependencies (TypeParameter tparam
)
448 Constraints constraints
= tparam
.Constraints
;
449 if (constraints
== null)
452 if (HasValueTypeConstraint
&& constraints
.HasClassConstraint
) {
453 Report
.Error (455, loc
, "Type parameter `{0}' inherits " +
454 "conflicting constraints `{1}' and `{2}'",
455 name
, TypeManager
.CSharpName (constraints
.ClassConstraint
),
460 if (HasClassConstraint
&& constraints
.HasClassConstraint
) {
461 Type t1
= ClassConstraint
;
462 TypeExpr e1
= class_constraint
;
463 Type t2
= constraints
.ClassConstraint
;
464 TypeExpr e2
= constraints
.class_constraint
;
466 if (!Convert
.ImplicitReferenceConversionExists (e1
, t2
) &&
467 !Convert
.ImplicitReferenceConversionExists (e2
, t1
)) {
468 Report
.Error (455, loc
,
469 "Type parameter `{0}' inherits " +
470 "conflicting constraints `{1}' and `{2}'",
471 name
, TypeManager
.CSharpName (t1
), TypeManager
.CSharpName (t2
));
476 if (constraints
.type_param_constraints
== null)
479 foreach (TypeParameterExpr expr
in constraints
.type_param_constraints
) {
480 if (!CheckDependencies (expr
.TypeParameter
))
487 public override GenericParameterAttributes Attributes
{
488 get { return attrs; }
491 public override bool HasClassConstraint
{
492 get { return class_constraint != null; }
495 public override Type ClassConstraint
{
496 get { return class_constraint_type; }
499 public override Type
[] InterfaceConstraints
{
500 get { return iface_constraint_types; }
503 public override Type EffectiveBaseClass
{
504 get { return effective_base_type; }
507 public bool IsSubclassOf (Type t
)
509 if ((class_constraint_type
!= null) &&
510 class_constraint_type
.IsSubclassOf (t
))
513 if (iface_constraint_types
== null)
516 foreach (Type iface
in iface_constraint_types
) {
517 if (TypeManager
.IsSubclassOf (iface
, t
))
524 public Location Location
{
531 /// This is used when we're implementing a generic interface method.
532 /// Each method type parameter in implementing method must have the same
533 /// constraints than the corresponding type parameter in the interface
534 /// method. To do that, we're called on each of the implementing method's
537 public bool CheckInterfaceMethod (GenericConstraints gc
)
539 if (gc
.Attributes
!= attrs
)
542 if (HasClassConstraint
!= gc
.HasClassConstraint
)
544 if (HasClassConstraint
&& !TypeManager
.IsEqual (gc
.ClassConstraint
, ClassConstraint
))
547 int gc_icount
= gc
.InterfaceConstraints
!= null ?
548 gc
.InterfaceConstraints
.Length
: 0;
549 int icount
= InterfaceConstraints
!= null ?
550 InterfaceConstraints
.Length
: 0;
552 if (gc_icount
!= icount
)
555 foreach (Type iface
in gc
.InterfaceConstraints
) {
557 foreach (Type check
in InterfaceConstraints
) {
558 if (TypeManager
.IsEqual (iface
, check
)) {
571 public void VerifyClsCompliance ()
573 if (class_constraint_type
!= null && !AttributeTester
.IsClsCompliant (class_constraint_type
))
574 Warning_ConstrainIsNotClsCompliant (class_constraint_type
, class_constraint
.Location
);
576 if (iface_constraint_types
!= null) {
577 for (int i
= 0; i
< iface_constraint_types
.Length
; ++i
) {
578 if (!AttributeTester
.IsClsCompliant (iface_constraint_types
[i
]))
579 Warning_ConstrainIsNotClsCompliant (iface_constraint_types
[i
],
580 ((TypeExpr
)iface_constraints
[i
]).Location
);
585 void Warning_ConstrainIsNotClsCompliant (Type t
, Location loc
)
587 Report
.SymbolRelatedToPreviousError (t
);
588 Report
.Warning (3024, 1, loc
, "Constraint type `{0}' is not CLS-compliant",
589 TypeManager
.CSharpName (t
));
594 /// A type parameter from a generic type definition.
596 public class TypeParameter
: MemberCore
, IMemberContainer
{
599 GenericConstraints gc
;
600 Constraints constraints
;
602 GenericTypeParameterBuilder type
;
603 MemberCache member_cache
;
605 public TypeParameter (DeclSpace parent
, DeclSpace decl
, string name
,
606 Constraints constraints
, Attributes attrs
, Location loc
)
607 : base (parent
, new MemberName (name
, loc
), attrs
)
611 this.constraints
= constraints
;
615 public GenericConstraints GenericConstraints
{
616 get { return gc != null ? gc : constraints; }
619 public Constraints Constraints
{
620 get { return constraints; }
623 public DeclSpace DeclSpace
{
632 /// This is the first method which is called during the resolving
633 /// process; we're called immediately after creating the type parameters
634 /// with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
637 /// We're either called from TypeContainer.DefineType() or from
638 /// GenericMethod.Define() (called from Method.Define()).
640 public void Define (GenericTypeParameterBuilder type
)
642 if (this.type
!= null)
643 throw new InvalidOperationException ();
646 TypeManager
.AddTypeParameter (type
, this);
650 /// This is the second method which is called during the resolving
651 /// process - in case of class type parameters, we're called from
652 /// TypeContainer.ResolveType() - after it resolved the class'es
653 /// base class and interfaces. For method type parameters, we're
654 /// called immediately after Define().
656 /// We're just resolving the constraints into expressions here, we
657 /// don't resolve them into actual types.
659 /// Note that in the special case of partial generic classes, we may be
660 /// called _before_ Define() and we may also be called multiple types.
662 public bool Resolve (DeclSpace ds
)
664 if (constraints
!= null) {
665 if (!constraints
.Resolve (ds
)) {
675 /// This is the third method which is called during the resolving
676 /// process. We're called immediately after calling DefineConstraints()
677 /// on all of the current class'es type parameters.
679 /// Our job is to resolve the constraints to actual types.
681 /// Note that we may have circular dependencies on type parameters - this
682 /// is why Resolve() and ResolveType() are separate.
684 public bool ResolveType (IResolveContext ec
)
686 if (constraints
!= null) {
687 if (!constraints
.ResolveTypes (ec
)) {
697 /// This is the fourth and last method which is called during the resolving
698 /// process. We're called after everything is fully resolved and actually
699 /// register the constraints with SRE and the TypeManager.
701 public bool DefineType (IResolveContext ec
)
703 return DefineType (ec
, null, null, false);
707 /// This is the fith and last method which is called during the resolving
708 /// process. We're called after everything is fully resolved and actually
709 /// register the constraints with SRE and the TypeManager.
711 /// The `builder', `implementing' and `is_override' arguments are only
712 /// applicable to method type parameters.
714 public bool DefineType (IResolveContext ec
, MethodBuilder builder
,
715 MethodInfo implementing
, bool is_override
)
717 if (!ResolveType (ec
))
720 if (implementing
!= null) {
721 if (is_override
&& (constraints
!= null)) {
722 Report
.Error (460, loc
,
723 "`{0}': Cannot specify constraints for overrides or explicit interface implementation methods",
724 TypeManager
.CSharpSignature (builder
));
728 MethodBase mb
= TypeManager
.DropGenericMethodArguments (implementing
);
730 int pos
= type
.GenericParameterPosition
;
731 Type mparam
= mb
.GetGenericArguments () [pos
];
732 GenericConstraints temp_gc
= ReflectionConstraints
.GetConstraints (mparam
);
735 gc
= new InflatedConstraints (temp_gc
, implementing
.DeclaringType
);
736 else if (constraints
!= null)
737 gc
= new InflatedConstraints (constraints
, implementing
.DeclaringType
);
740 if (constraints
!= null) {
743 else if (!constraints
.CheckInterfaceMethod (gc
))
746 if (!is_override
&& (temp_gc
!= null))
751 Report
.SymbolRelatedToPreviousError (implementing
);
754 425, loc
, "The constraints for type " +
755 "parameter `{0}' of method `{1}' must match " +
756 "the constraints for type parameter `{2}' " +
757 "of interface method `{3}'. Consider using " +
758 "an explicit interface implementation instead",
759 Name
, TypeManager
.CSharpSignature (builder
),
760 TypeManager
.CSharpName (mparam
), TypeManager
.CSharpSignature (mb
));
763 } else if (DeclSpace
is CompilerGeneratedClass
) {
764 TypeParameter
[] tparams
= DeclSpace
.TypeParameters
;
765 Type
[] types
= new Type
[tparams
.Length
];
766 for (int i
= 0; i
< tparams
.Length
; i
++)
767 types
[i
] = tparams
[i
].Type
;
769 if (constraints
!= null)
770 gc
= new InflatedConstraints (constraints
, types
);
772 gc
= (GenericConstraints
) constraints
;
778 if (gc
.HasClassConstraint
)
779 type
.SetBaseTypeConstraint (gc
.ClassConstraint
);
781 type
.SetInterfaceConstraints (gc
.InterfaceConstraints
);
782 type
.SetGenericParameterAttributes (gc
.Attributes
);
783 TypeManager
.RegisterBuilder (type
, gc
.InterfaceConstraints
);
789 /// Check whether there are no conflicts in our type parameter constraints.
791 /// This is an example:
795 /// where U : T, struct
797 public bool CheckDependencies ()
799 if (constraints
!= null)
800 return constraints
.CheckDependencies ();
806 /// This is called for each part of a partial generic type definition.
808 /// If `new_constraints' is not null and we don't already have constraints,
809 /// they become our constraints. If we already have constraints, we must
810 /// check that they're the same.
813 public bool UpdateConstraints (IResolveContext ec
, Constraints new_constraints
)
816 throw new InvalidOperationException ();
818 if (new_constraints
== null)
821 if (!new_constraints
.Resolve (ec
))
823 if (!new_constraints
.ResolveTypes (ec
))
826 if (constraints
!= null)
827 return constraints
.CheckInterfaceMethod (new_constraints
);
829 constraints
= new_constraints
;
833 public void EmitAttributes ()
835 if (OptAttributes
!= null)
836 OptAttributes
.Emit ();
839 public override string DocCommentHeader
{
841 throw new InvalidOperationException (
842 "Unexpected attempt to get doc comment from " + this.GetType () + ".");
850 public override bool Define ()
855 public override void ApplyAttributeBuilder (Attribute a
,
856 CustomAttributeBuilder cb
)
858 type
.SetCustomAttribute (cb
);
861 public override AttributeTargets AttributeTargets
{
863 return (AttributeTargets
) AttributeTargets
.GenericParameter
;
867 public override string[] ValidAttributeTargets
{
869 return new string [] { "type parameter" }
;
877 string IMemberContainer
.Name
{
881 MemberCache IMemberContainer
.BaseCache
{
886 if (gc
.EffectiveBaseClass
.BaseType
== null)
889 return TypeManager
.LookupMemberCache (gc
.EffectiveBaseClass
.BaseType
);
893 bool IMemberContainer
.IsInterface
{
894 get { return false; }
897 MemberList IMemberContainer
.GetMembers (MemberTypes mt
, BindingFlags bf
)
899 return FindMembers (mt
, bf
, null, null);
902 public MemberCache MemberCache
{
904 if (member_cache
!= null)
910 Type
[] ifaces
= TypeManager
.ExpandInterfaces (gc
.InterfaceConstraints
);
911 member_cache
= new MemberCache (this, gc
.EffectiveBaseClass
, ifaces
);
917 public MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
918 MemberFilter filter
, object criteria
)
921 return MemberList
.Empty
;
923 ArrayList members
= new ArrayList ();
925 if (gc
.HasClassConstraint
) {
926 MemberList list
= TypeManager
.FindMembers (
927 gc
.ClassConstraint
, mt
, bf
, filter
, criteria
);
929 members
.AddRange (list
);
932 Type
[] ifaces
= TypeManager
.ExpandInterfaces (gc
.InterfaceConstraints
);
933 foreach (Type t
in ifaces
) {
934 MemberList list
= TypeManager
.FindMembers (
935 t
, mt
, bf
, filter
, criteria
);
937 members
.AddRange (list
);
940 return new MemberList (members
);
943 public bool IsSubclassOf (Type t
)
948 if (constraints
!= null)
949 return constraints
.IsSubclassOf (t
);
954 public override string ToString ()
956 return "TypeParameter[" + name
+ "]";
959 public static string GetSignatureForError (TypeParameter
[] tp
)
961 if (tp
== null || tp
.Length
== 0)
964 StringBuilder sb
= new StringBuilder ("<");
965 for (int i
= 0; i
< tp
.Length
; ++i
) {
968 sb
.Append (tp
[i
].GetSignatureForError ());
971 return sb
.ToString ();
974 public void InflateConstraints (Type declaring
)
976 if (constraints
!= null)
977 gc
= new InflatedConstraints (constraints
, declaring
);
980 protected class InflatedConstraints
: GenericConstraints
982 GenericConstraints gc
;
984 Type class_constraint
;
985 Type
[] iface_constraints
;
988 public InflatedConstraints (GenericConstraints gc
, Type declaring
)
989 : this (gc
, TypeManager
.GetTypeArguments (declaring
))
992 public InflatedConstraints (GenericConstraints gc
, Type
[] dargs
)
997 ArrayList list
= new ArrayList ();
998 if (gc
.HasClassConstraint
)
999 list
.Add (inflate (gc
.ClassConstraint
));
1000 foreach (Type iface
in gc
.InterfaceConstraints
)
1001 list
.Add (inflate (iface
));
1003 bool has_class_constr
= false;
1004 if (list
.Count
> 0) {
1005 Type first
= (Type
) list
[0];
1006 has_class_constr
= !first
.IsGenericParameter
&& !first
.IsInterface
;
1009 if ((list
.Count
> 0) && has_class_constr
) {
1010 class_constraint
= (Type
) list
[0];
1011 iface_constraints
= new Type
[list
.Count
- 1];
1012 list
.CopyTo (1, iface_constraints
, 0, list
.Count
- 1);
1014 iface_constraints
= new Type
[list
.Count
];
1015 list
.CopyTo (iface_constraints
, 0);
1018 if (HasValueTypeConstraint
)
1019 base_type
= TypeManager
.value_type
;
1020 else if (class_constraint
!= null)
1021 base_type
= class_constraint
;
1023 base_type
= TypeManager
.object_type
;
1026 Type
inflate (Type t
)
1030 if (t
.IsGenericParameter
)
1031 return dargs
[t
.GenericParameterPosition
];
1032 if (t
.IsGenericType
) {
1033 Type
[] args
= t
.GetGenericArguments ();
1034 Type
[] inflated
= new Type
[args
.Length
];
1036 for (int i
= 0; i
< args
.Length
; i
++)
1037 inflated
[i
] = inflate (args
[i
]);
1039 t
= t
.GetGenericTypeDefinition ();
1040 t
= t
.MakeGenericType (inflated
);
1046 public override string TypeParameter
{
1047 get { return gc.TypeParameter; }
1050 public override GenericParameterAttributes Attributes
{
1051 get { return gc.Attributes; }
1054 public override Type ClassConstraint
{
1055 get { return class_constraint; }
1058 public override Type EffectiveBaseClass
{
1059 get { return base_type; }
1062 public override Type
[] InterfaceConstraints
{
1063 get { return iface_constraints; }
1069 /// A TypeExpr which already resolved to a type parameter.
1071 public class TypeParameterExpr
: TypeExpr
{
1072 TypeParameter type_parameter
;
1074 public override string Name
{
1076 return type_parameter
.Name
;
1080 public override string FullName
{
1082 return type_parameter
.Name
;
1086 public TypeParameter TypeParameter
{
1088 return type_parameter
;
1092 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1094 this.type_parameter
= type_parameter
;
1098 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
1100 type
= type_parameter
.Type
;
1105 public override bool IsInterface
{
1106 get { return false; }
1109 public override bool CheckAccessLevel (DeclSpace ds
)
1114 public void Error_CannotUseAsUnmanagedType (Location loc
)
1116 Report
.Error (-203, loc
, "Can not use type parameter as unmanaged type");
1121 /// Tracks the type arguments when instantiating a generic type. We're used in
1122 /// ConstructedType.
1124 public class TypeArguments
{
1125 public readonly Location Location
;
1132 public TypeArguments (Location loc
)
1134 args
= new ArrayList ();
1135 this.Location
= loc
;
1138 public TypeArguments (int dimension
, Location loc
)
1140 this.dimension
= dimension
;
1141 this.Location
= loc
;
1144 public void Add (Expression type
)
1147 throw new InvalidOperationException ();
1152 public void Add (TypeArguments new_args
)
1155 throw new InvalidOperationException ();
1157 args
.AddRange (new_args
.args
);
1161 /// We're used during the parsing process: the parser can't distinguish
1162 /// between type parameters and type arguments. Because of that, the
1163 /// parser creates a `MemberName' with `TypeArguments' for both cases and
1164 /// in case of a generic type definition, we call GetDeclarations().
1166 public TypeParameterName
[] GetDeclarations ()
1168 TypeParameterName
[] ret
= new TypeParameterName
[args
.Count
];
1169 for (int i
= 0; i
< args
.Count
; i
++) {
1170 TypeParameterName name
= args
[i
] as TypeParameterName
;
1175 SimpleName sn
= args
[i
] as SimpleName
;
1177 ret
[i
] = new TypeParameterName (sn
.Name
, null, sn
.Location
);
1181 Report
.Error (81, Location
, "Type parameter declaration " +
1182 "must be an identifier not a type");
1189 /// We may only be used after Resolve() is called and return the fully
1192 public Type
[] Arguments
{
1198 public bool HasTypeArguments
{
1200 return has_type_args
;
1213 public bool IsUnbound
{
1215 return dimension
> 0;
1219 public override string ToString ()
1221 StringBuilder s
= new StringBuilder ();
1224 for (int i
= 0; i
< count
; i
++){
1226 // FIXME: Use TypeManager.CSharpname once we have the type
1229 s
.Append (args
[i
].ToString ());
1233 return s
.ToString ();
1236 public string GetSignatureForError()
1238 StringBuilder sb
= new StringBuilder();
1239 for (int i
= 0; i
< Count
; ++i
)
1241 Expression expr
= (Expression
)args
[i
];
1242 sb
.Append(expr
.GetSignatureForError());
1246 return sb
.ToString();
1250 /// Resolve the type arguments.
1252 public bool Resolve (IResolveContext ec
)
1254 int count
= args
.Count
;
1257 atypes
= new Type
[count
];
1259 for (int i
= 0; i
< count
; i
++){
1260 TypeExpr te
= ((Expression
) args
[i
]).ResolveAsTypeTerminal (ec
, false);
1266 atypes
[i
] = te
.Type
;
1267 if (te
.Type
.IsGenericParameter
) {
1268 if (te
is TypeParameterExpr
)
1269 has_type_args
= true;
1273 if (te
.Type
.IsSealed
&& te
.Type
.IsAbstract
) {
1274 Report
.Error (718, Location
, "`{0}': static classes cannot be used as generic arguments",
1275 te
.GetSignatureForError ());
1279 if (te
.Type
.IsPointer
) {
1280 Report
.Error (306, Location
, "The type `{0}' may not be used " +
1281 "as a type argument", TypeManager
.CSharpName (te
.Type
));
1285 if (te
.Type
== TypeManager
.void_type
) {
1286 Expression
.Error_VoidInvalidInTheContext (Location
);
1293 public TypeArguments
Clone ()
1295 TypeArguments copy
= new TypeArguments (Location
);
1296 foreach (Expression ta
in args
)
1303 public class TypeParameterName
: SimpleName
1305 Attributes attributes
;
1307 public TypeParameterName (string name
, Attributes attrs
, Location loc
)
1313 public Attributes OptAttributes
{
1321 /// An instantiation of a generic type.
1323 public class ConstructedType
: TypeExpr
{
1325 FullNamedExpression name
;
1327 Type
[] gen_params
, atypes
;
1331 /// Instantiate the generic type `fname' with the type arguments `args'.
1333 public ConstructedType (FullNamedExpression fname
, TypeArguments args
, Location l
)
1339 eclass
= ExprClass
.Type
;
1340 full_name
= name
+ "<" + args
.ToString () + ">";
1343 protected ConstructedType (TypeArguments args
, Location l
)
1348 eclass
= ExprClass
.Type
;
1351 protected ConstructedType (TypeParameter
[] type_params
, Location l
)
1355 args
= new TypeArguments (l
);
1356 foreach (TypeParameter type_param
in type_params
)
1357 args
.Add (new TypeParameterExpr (type_param
, l
));
1359 eclass
= ExprClass
.Type
;
1363 /// This is used to construct the `this' type inside a generic type definition.
1365 public ConstructedType (Type t
, TypeParameter
[] type_params
, Location l
)
1366 : this (type_params
, l
)
1368 gt
= t
.GetGenericTypeDefinition ();
1370 this.name
= new TypeExpression (gt
, l
);
1371 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1375 /// Instantiate the generic type `t' with the type arguments `args'.
1376 /// Use this constructor if you already know the fully resolved
1379 public ConstructedType (Type t
, TypeArguments args
, Location l
)
1382 gt
= t
.GetGenericTypeDefinition ();
1384 this.name
= new TypeExpression (gt
, l
);
1385 full_name
= gt
.FullName
+ "<" + args
.ToString () + ">";
1388 public TypeArguments TypeArguments
{
1389 get { return args; }
1392 public override string GetSignatureForError ()
1394 return TypeManager
.RemoveGenericArity (gt
.FullName
) + "<" + args
.GetSignatureForError () + ">";
1397 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
1399 if (!ResolveConstructedType (ec
))
1406 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1407 /// after fully resolving the constructed type.
1409 public bool CheckConstraints (IResolveContext ec
)
1411 return ConstraintChecker
.CheckConstraints (ec
, gt
, gen_params
, atypes
, loc
);
1415 /// Resolve the constructed type, but don't check the constraints.
1417 public bool ResolveConstructedType (IResolveContext ec
)
1421 // If we already know the fully resolved generic type.
1423 return DoResolveType (ec
);
1429 Report
.Error (246, loc
, "Cannot find type `{0}'<...>", Name
);
1433 num_args
= TypeManager
.GetNumberOfTypeArguments (t
);
1434 if (num_args
== 0) {
1435 Report
.Error (308, loc
,
1436 "The non-generic type `{0}' cannot " +
1437 "be used with type arguments.",
1438 TypeManager
.CSharpName (t
));
1442 gt
= t
.GetGenericTypeDefinition ();
1443 return DoResolveType (ec
);
1446 bool DoResolveType (IResolveContext ec
)
1449 // Resolve the arguments.
1451 if (args
.Resolve (ec
) == false)
1454 gen_params
= gt
.GetGenericArguments ();
1455 atypes
= args
.Arguments
;
1457 if (atypes
.Length
!= gen_params
.Length
) {
1458 Report
.Error (305, loc
,
1459 "Using the generic type `{0}' " +
1460 "requires {1} type arguments",
1461 TypeManager
.CSharpName (gt
),
1462 gen_params
.Length
.ToString ());
1467 // Now bind the parameters.
1469 type
= gt
.MakeGenericType (atypes
);
1473 public Expression
GetSimpleName (EmitContext ec
)
1478 public override bool CheckAccessLevel (DeclSpace ds
)
1480 return ds
.CheckAccessLevel (gt
);
1483 public override bool AsAccessible (DeclSpace ds
, int flags
)
1485 foreach (Type t
in atypes
) {
1486 if (!ds
.AsAccessible (t
, flags
))
1490 return ds
.AsAccessible (gt
, flags
);
1493 public override bool IsClass
{
1494 get { return gt.IsClass; }
1497 public override bool IsValueType
{
1498 get { return gt.IsValueType; }
1501 public override bool IsInterface
{
1502 get { return gt.IsInterface; }
1505 public override bool IsSealed
{
1506 get { return gt.IsSealed; }
1509 public override bool Equals (object obj
)
1511 ConstructedType cobj
= obj
as ConstructedType
;
1515 if ((type
== null) || (cobj
.type
== null))
1518 return type
== cobj
.type
;
1521 public override int GetHashCode ()
1523 return base.GetHashCode ();
1526 public override string Name
{
1532 public override string FullName
{
1539 public abstract class ConstraintChecker
1541 protected readonly Type
[] gen_params
;
1542 protected readonly Type
[] atypes
;
1543 protected readonly Location loc
;
1545 protected ConstraintChecker (Type
[] gen_params
, Type
[] atypes
, Location loc
)
1547 this.gen_params
= gen_params
;
1548 this.atypes
= atypes
;
1553 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1554 /// after fully resolving the constructed type.
1556 public bool CheckConstraints (IResolveContext ec
)
1558 for (int i
= 0; i
< gen_params
.Length
; i
++) {
1559 if (!CheckConstraints (ec
, i
))
1566 protected bool CheckConstraints (IResolveContext ec
, int index
)
1568 Type atype
= atypes
[index
];
1569 Type ptype
= gen_params
[index
];
1574 Expression aexpr
= new EmptyExpression (atype
);
1576 GenericConstraints gc
= TypeManager
.GetTypeParameterConstraints (ptype
);
1580 bool is_class
, is_struct
;
1581 if (atype
.IsGenericParameter
) {
1582 GenericConstraints agc
= TypeManager
.GetTypeParameterConstraints (atype
);
1584 if (agc
is Constraints
)
1585 ((Constraints
) agc
).Resolve (ec
);
1586 is_class
= agc
.IsReferenceType
;
1587 is_struct
= agc
.IsValueType
;
1589 is_class
= is_struct
= false;
1594 if (!atype
.IsGenericType
)
1596 is_class
= atype
.IsClass
|| atype
.IsInterface
;
1597 is_struct
= atype
.IsValueType
&& !TypeManager
.IsNullableType (atype
);
1601 // First, check the `class' and `struct' constraints.
1603 if (gc
.HasReferenceTypeConstraint
&& !is_class
) {
1604 Report
.Error (452, loc
, "The type `{0}' must be " +
1605 "a reference type in order to use it " +
1606 "as type parameter `{1}' in the " +
1607 "generic type or method `{2}'.",
1608 TypeManager
.CSharpName (atype
),
1609 TypeManager
.CSharpName (ptype
),
1610 GetSignatureForError ());
1612 } else if (gc
.HasValueTypeConstraint
&& !is_struct
) {
1613 Report
.Error (453, loc
, "The type `{0}' must be a " +
1614 "non-nullable value type in order to use it " +
1615 "as type parameter `{1}' in the " +
1616 "generic type or method `{2}'.",
1617 TypeManager
.CSharpName (atype
),
1618 TypeManager
.CSharpName (ptype
),
1619 GetSignatureForError ());
1624 // The class constraint comes next.
1626 if (gc
.HasClassConstraint
) {
1627 if (!CheckConstraint (ec
, ptype
, aexpr
, gc
.ClassConstraint
))
1632 // Now, check the interface constraints.
1634 if (gc
.InterfaceConstraints
!= null) {
1635 foreach (Type it
in gc
.InterfaceConstraints
) {
1636 if (!CheckConstraint (ec
, ptype
, aexpr
, it
))
1642 // Finally, check the constructor constraint.
1645 if (!gc
.HasConstructorConstraint
)
1648 if (TypeManager
.IsBuiltinType (atype
) || atype
.IsValueType
)
1651 if (HasDefaultConstructor (atype
))
1654 Report_SymbolRelatedToPreviousError ();
1655 Report
.SymbolRelatedToPreviousError (atype
);
1656 Report
.Error (310, loc
, "The type `{0}' must have a public " +
1657 "parameterless constructor in order to use it " +
1658 "as parameter `{1}' in the generic type or " +
1660 TypeManager
.CSharpName (atype
),
1661 TypeManager
.CSharpName (ptype
),
1662 GetSignatureForError ());
1666 protected bool CheckConstraint (IResolveContext ec
, Type ptype
, Expression expr
,
1669 if (TypeManager
.HasGenericArguments (ctype
)) {
1670 Type
[] types
= TypeManager
.GetTypeArguments (ctype
);
1672 TypeArguments new_args
= new TypeArguments (loc
);
1674 for (int i
= 0; i
< types
.Length
; i
++) {
1677 if (t
.IsGenericParameter
) {
1678 int pos
= t
.GenericParameterPosition
;
1681 new_args
.Add (new TypeExpression (t
, loc
));
1684 TypeExpr ct
= new ConstructedType (ctype
, new_args
, loc
);
1685 if (ct
.ResolveAsTypeStep (ec
, false) == null)
1688 } else if (ctype
.IsGenericParameter
) {
1689 int pos
= ctype
.GenericParameterPosition
;
1690 ctype
= atypes
[pos
];
1693 if (Convert
.ImplicitStandardConversionExists (expr
, ctype
))
1696 Error_TypeMustBeConvertible (expr
.Type
, ctype
, ptype
);
1700 bool HasDefaultConstructor (Type atype
)
1702 if (atype
.IsAbstract
)
1706 atype
= TypeManager
.DropGenericTypeArguments (atype
);
1707 if (atype
is TypeBuilder
) {
1708 TypeContainer tc
= TypeManager
.LookupTypeContainer (atype
);
1709 if (tc
.InstanceConstructors
== null) {
1710 atype
= atype
.BaseType
;
1714 foreach (Constructor c
in tc
.InstanceConstructors
) {
1715 if ((c
.ModFlags
& Modifiers
.PUBLIC
) == 0)
1717 if ((c
.Parameters
.FixedParameters
!= null) &&
1718 (c
.Parameters
.FixedParameters
.Length
!= 0))
1720 if (c
.Parameters
.HasArglist
|| c
.Parameters
.HasParams
)
1727 TypeParameter tparam
= TypeManager
.LookupTypeParameter (atype
);
1728 if (tparam
!= null) {
1729 if (tparam
.GenericConstraints
== null)
1732 return tparam
.GenericConstraints
.HasConstructorConstraint
;
1735 MemberList list
= TypeManager
.FindMembers (
1736 atype
, MemberTypes
.Constructor
,
1737 BindingFlags
.Public
| BindingFlags
.Instance
|
1738 BindingFlags
.DeclaredOnly
, null, null);
1740 if (atype
.IsAbstract
|| (list
== null))
1743 foreach (MethodBase mb
in list
) {
1744 ParameterData pd
= TypeManager
.GetParameterData (mb
);
1745 if ((pd
.Count
== 0) && mb
.IsPublic
&& !mb
.IsStatic
)
1752 protected abstract string GetSignatureForError ();
1753 protected abstract void Report_SymbolRelatedToPreviousError ();
1755 void Error_TypeMustBeConvertible (Type atype
, Type gc
, Type ptype
)
1757 Report_SymbolRelatedToPreviousError ();
1758 Report
.SymbolRelatedToPreviousError (atype
);
1759 Report
.Error (309, loc
,
1760 "The type `{0}' must be convertible to `{1}' in order to " +
1761 "use it as parameter `{2}' in the generic type or method `{3}'",
1762 TypeManager
.CSharpName (atype
), TypeManager
.CSharpName (gc
),
1763 TypeManager
.CSharpName (ptype
), GetSignatureForError ());
1766 public static bool CheckConstraints (EmitContext ec
, MethodBase definition
,
1767 MethodBase instantiated
, Location loc
)
1769 MethodConstraintChecker checker
= new MethodConstraintChecker (
1770 definition
, definition
.GetGenericArguments (),
1771 instantiated
.GetGenericArguments (), loc
);
1773 return checker
.CheckConstraints (ec
);
1776 public static bool CheckConstraints (IResolveContext ec
, Type gt
, Type
[] gen_params
,
1777 Type
[] atypes
, Location loc
)
1779 TypeConstraintChecker checker
= new TypeConstraintChecker (
1780 gt
, gen_params
, atypes
, loc
);
1782 return checker
.CheckConstraints (ec
);
1785 protected class MethodConstraintChecker
: ConstraintChecker
1787 MethodBase definition
;
1789 public MethodConstraintChecker (MethodBase definition
, Type
[] gen_params
,
1790 Type
[] atypes
, Location loc
)
1791 : base (gen_params
, atypes
, loc
)
1793 this.definition
= definition
;
1796 protected override string GetSignatureForError ()
1798 return TypeManager
.CSharpSignature (definition
);
1801 protected override void Report_SymbolRelatedToPreviousError ()
1803 Report
.SymbolRelatedToPreviousError (definition
);
1807 protected class TypeConstraintChecker
: ConstraintChecker
1811 public TypeConstraintChecker (Type gt
, Type
[] gen_params
, Type
[] atypes
,
1813 : base (gen_params
, atypes
, loc
)
1818 protected override string GetSignatureForError ()
1820 return TypeManager
.CSharpName (gt
);
1823 protected override void Report_SymbolRelatedToPreviousError ()
1825 Report
.SymbolRelatedToPreviousError (gt
);
1831 /// A generic method definition.
1833 public class GenericMethod
: DeclSpace
1835 Expression return_type
;
1836 Parameters parameters
;
1838 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1839 Expression return_type
, Parameters parameters
)
1840 : base (ns
, parent
, name
, null)
1842 this.return_type
= return_type
;
1843 this.parameters
= parameters
;
1846 public override TypeBuilder
DefineType ()
1848 throw new Exception ();
1851 public override bool Define ()
1853 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1854 if (!TypeParameters
[i
].Resolve (this))
1861 /// Define and resolve the type parameters.
1862 /// We're called from Method.Define().
1864 public bool Define (MethodBuilder mb
, ToplevelBlock block
)
1866 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1867 string[] snames
= new string [names
.Length
];
1868 for (int i
= 0; i
< names
.Length
; i
++) {
1869 string type_argument_name
= names
[i
].Name
;
1870 Parameter p
= parameters
.GetParameterByName (type_argument_name
);
1872 Error_ParameterNameCollision (p
.Location
, type_argument_name
, "method parameter");
1875 if (block
!= null) {
1876 LocalInfo li
= (LocalInfo
)block
.Variables
[type_argument_name
];
1878 Error_ParameterNameCollision (li
.Location
, type_argument_name
, "local variable");
1882 snames
[i
] = type_argument_name
;
1885 GenericTypeParameterBuilder
[] gen_params
= mb
.DefineGenericParameters (snames
);
1886 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1887 TypeParameters
[i
].Define (gen_params
[i
]);
1892 for (int i
= 0; i
< TypeParameters
.Length
; i
++) {
1893 if (!TypeParameters
[i
].ResolveType (this))
1900 static void Error_ParameterNameCollision (Location loc
, string name
, string collisionWith
)
1902 Report
.Error (412, loc
, "The type parameter name `{0}' is the same as `{1}'",
1903 name
, collisionWith
);
1907 /// We're called from MethodData.Define() after creating the MethodBuilder.
1909 public bool DefineType (EmitContext ec
, MethodBuilder mb
,
1910 MethodInfo implementing
, bool is_override
)
1912 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1913 if (!TypeParameters
[i
].DefineType (
1914 ec
, mb
, implementing
, is_override
))
1918 foreach (Parameter p
in parameters
.FixedParameters
){
1919 if (!p
.Resolve (ec
))
1922 if ((return_type
!= null) && (return_type
.ResolveAsTypeTerminal (ec
, false) == null))
1928 public void EmitAttributes ()
1930 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
1931 TypeParameters
[i
].EmitAttributes ();
1933 if (OptAttributes
!= null)
1934 OptAttributes
.Emit ();
1937 public override bool DefineMembers ()
1942 public override MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
1943 MemberFilter filter
, object criteria
)
1945 throw new Exception ();
1948 public override MemberCache MemberCache
{
1954 public override AttributeTargets AttributeTargets
{
1956 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
1960 public override string DocCommentHeader
{
1961 get { return "M:"; }
1964 public new void VerifyClsCompliance ()
1966 foreach (TypeParameter tp
in TypeParameters
) {
1967 if (tp
.Constraints
== null)
1970 tp
.Constraints
.VerifyClsCompliance ();
1975 public class DefaultValueExpression
: Expression
1979 public DefaultValueExpression (Expression expr
, Location loc
)
1985 public override Expression
DoResolve (EmitContext ec
)
1987 TypeExpr texpr
= expr
.ResolveAsTypeTerminal (ec
, false);
1993 if (type
== TypeManager
.void_type
) {
1994 Error_VoidInvalidInTheContext (loc
);
1998 if (type
.IsGenericParameter
)
2000 GenericConstraints constraints
= TypeManager
.GetTypeParameterConstraints(type
);
2001 if (constraints
!= null && constraints
.IsReferenceType
)
2002 return new NullDefault (new NullLiteral (Location
), type
);
2006 Constant c
= New
.Constantify(type
);
2008 return new NullDefault (c
, type
);
2010 if (!TypeManager
.IsValueType (type
))
2011 return new NullDefault (new NullLiteral (Location
), type
);
2013 eclass
= ExprClass
.Variable
;
2017 public override void Emit (EmitContext ec
)
2019 LocalTemporary temp_storage
= new LocalTemporary(type
);
2021 temp_storage
.AddressOf(ec
, AddressOp
.LoadStore
);
2022 ec
.ig
.Emit(OpCodes
.Initobj
, type
);
2023 temp_storage
.Emit(ec
);
2027 public class NullableType
: TypeExpr
2029 Expression underlying
;
2031 public NullableType (Expression underlying
, Location l
)
2033 this.underlying
= underlying
;
2036 eclass
= ExprClass
.Type
;
2039 public NullableType (Type type
, Location loc
)
2040 : this (new TypeExpression (type
, loc
), loc
)
2043 public override string Name
{
2044 get { return underlying.ToString () + "?"; }
2047 public override string FullName
{
2048 get { return underlying.ToString () + "?"; }
2051 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2053 TypeArguments args
= new TypeArguments (loc
);
2054 args
.Add (underlying
);
2056 ConstructedType ctype
= new ConstructedType (TypeManager
.generic_nullable_type
, args
, loc
);
2057 return ctype
.ResolveAsTypeTerminal (ec
, false);
2061 public partial class TypeManager
2064 // A list of core types that the compiler requires or uses
2066 static public Type activator_type
;
2067 static public Type generic_ilist_type
;
2068 static public Type generic_icollection_type
;
2069 static public Type generic_ienumerator_type
;
2070 static public Type generic_ienumerable_type
;
2071 static public Type generic_nullable_type
;
2074 // These methods are called by code generated by the compiler
2076 static public MethodInfo activator_create_instance
;
2078 static void InitGenericCoreTypes ()
2080 activator_type
= CoreLookupType ("System", "Activator");
2082 generic_ilist_type
= CoreLookupType (
2083 "System.Collections.Generic", "IList", 1);
2084 generic_icollection_type
= CoreLookupType (
2085 "System.Collections.Generic", "ICollection", 1);
2086 generic_ienumerator_type
= CoreLookupType (
2087 "System.Collections.Generic", "IEnumerator", 1);
2088 generic_ienumerable_type
= CoreLookupType (
2089 "System.Collections.Generic", "IEnumerable", 1);
2090 generic_nullable_type
= CoreLookupType (
2091 "System", "Nullable", 1);
2094 static void InitGenericCodeHelpers ()
2097 activator_create_instance
= GetMethod (
2098 activator_type
, "CreateInstance", Type
.EmptyTypes
);
2101 static Type
CoreLookupType (string ns
, string name
, int arity
)
2103 return CoreLookupType (ns
, MemberName
.MakeName (name
, arity
));
2106 public static TypeContainer
LookupGenericTypeContainer (Type t
)
2108 t
= DropGenericTypeArguments (t
);
2109 return LookupTypeContainer (t
);
2112 public static GenericConstraints
GetTypeParameterConstraints (Type t
)
2114 if (!t
.IsGenericParameter
)
2115 throw new InvalidOperationException ();
2117 TypeParameter tparam
= LookupTypeParameter (t
);
2119 return tparam
.GenericConstraints
;
2121 return ReflectionConstraints
.GetConstraints (t
);
2125 /// Check whether `a' and `b' may become equal generic types.
2126 /// The algorithm to do that is a little bit complicated.
2128 public static bool MayBecomeEqualGenericTypes (Type a
, Type b
, Type
[] class_inferred
,
2129 Type
[] method_inferred
)
2131 if (a
.IsGenericParameter
) {
2133 // If a is an array of a's type, they may never
2137 b
= b
.GetElementType ();
2143 // If b is a generic parameter or an actual type,
2144 // they may become equal:
2146 // class X<T,U> : I<T>, I<U>
2147 // class X<T> : I<T>, I<float>
2149 if (b
.IsGenericParameter
|| !b
.IsGenericType
) {
2150 int pos
= a
.GenericParameterPosition
;
2151 Type
[] args
= a
.DeclaringMethod
!= null ? method_inferred
: class_inferred
;
2152 if (args
[pos
] == null) {
2157 return args
[pos
] == a
;
2161 // We're now comparing a type parameter with a
2162 // generic instance. They may become equal unless
2163 // the type parameter appears anywhere in the
2164 // generic instance:
2166 // class X<T,U> : I<T>, I<X<U>>
2167 // -> error because you could instanciate it as
2170 // class X<T> : I<T>, I<X<T>> -> ok
2173 Type
[] bargs
= GetTypeArguments (b
);
2174 for (int i
= 0; i
< bargs
.Length
; i
++) {
2175 if (a
.Equals (bargs
[i
]))
2182 if (b
.IsGenericParameter
)
2183 return MayBecomeEqualGenericTypes (b
, a
, class_inferred
, method_inferred
);
2186 // At this point, neither a nor b are a type parameter.
2188 // If one of them is a generic instance, let
2189 // MayBecomeEqualGenericInstances() compare them (if the
2190 // other one is not a generic instance, they can never
2194 if (a
.IsGenericType
|| b
.IsGenericType
)
2195 return MayBecomeEqualGenericInstances (a
, b
, class_inferred
, method_inferred
);
2198 // If both of them are arrays.
2201 if (a
.IsArray
&& b
.IsArray
) {
2202 if (a
.GetArrayRank () != b
.GetArrayRank ())
2205 a
= a
.GetElementType ();
2206 b
= b
.GetElementType ();
2208 return MayBecomeEqualGenericTypes (a
, b
, class_inferred
, method_inferred
);
2212 // Ok, two ordinary types.
2215 return a
.Equals (b
);
2219 // Checks whether two generic instances may become equal for some
2220 // particular instantiation (26.3.1).
2222 public static bool MayBecomeEqualGenericInstances (Type a
, Type b
,
2223 Type
[] class_inferred
,
2224 Type
[] method_inferred
)
2226 if (!a
.IsGenericType
|| !b
.IsGenericType
)
2228 if (a
.GetGenericTypeDefinition () != b
.GetGenericTypeDefinition ())
2231 return MayBecomeEqualGenericInstances (
2232 GetTypeArguments (a
), GetTypeArguments (b
), class_inferred
, method_inferred
);
2235 public static bool MayBecomeEqualGenericInstances (Type
[] aargs
, Type
[] bargs
,
2236 Type
[] class_inferred
,
2237 Type
[] method_inferred
)
2239 if (aargs
.Length
!= bargs
.Length
)
2242 for (int i
= 0; i
< aargs
.Length
; i
++) {
2243 if (!MayBecomeEqualGenericTypes (aargs
[i
], bargs
[i
], class_inferred
, method_inferred
))
2250 static bool UnifyType (Type pt
, Type at
, Type
[] inferred
)
2252 if (pt
.IsGenericParameter
) {
2253 if (pt
.DeclaringMethod
== null)
2256 int pos
= pt
.GenericParameterPosition
;
2258 if (inferred
[pos
] == null)
2259 inferred
[pos
] = at
;
2261 return inferred
[pos
] == at
;
2264 if (!pt
.ContainsGenericParameters
) {
2265 if (at
.ContainsGenericParameters
)
2266 return UnifyType (at
, pt
, inferred
);
2273 if (at
.GetArrayRank () != pt
.GetArrayRank ())
2276 return UnifyType (pt
.GetElementType (), at
.GetElementType (), inferred
);
2279 if (!pt
.IsGenericType
)
2282 Type gt
= pt
.GetGenericTypeDefinition ();
2283 if ((gt
!= generic_ilist_type
) && (gt
!= generic_icollection_type
) &&
2284 (gt
!= generic_ienumerable_type
))
2287 Type
[] args
= GetTypeArguments (pt
);
2288 return UnifyType (args
[0], at
.GetElementType (), inferred
);
2293 (pt
.GetArrayRank () != at
.GetArrayRank ()))
2296 return UnifyType (pt
.GetElementType (), at
.GetElementType (), inferred
);
2299 if (pt
.IsByRef
&& at
.IsByRef
)
2300 return UnifyType (pt
.GetElementType (), at
.GetElementType (), inferred
);
2301 ArrayList list
= new ArrayList ();
2302 if (at
.IsGenericType
)
2304 for (Type bt
= at
.BaseType
; bt
!= null; bt
= bt
.BaseType
)
2307 list
.AddRange (TypeManager
.GetInterfaces (at
));
2309 foreach (Type type
in list
) {
2310 if (!type
.IsGenericType
)
2313 if (DropGenericTypeArguments (pt
) != DropGenericTypeArguments (type
))
2316 if (!UnifyTypes (pt
.GetGenericArguments (), type
.GetGenericArguments (), inferred
))
2323 static bool UnifyTypes (Type
[] pts
, Type
[] ats
, Type
[] inferred
)
2325 for (int i
= 0; i
< ats
.Length
; i
++) {
2326 if (!UnifyType (pts
[i
], ats
[i
], inferred
))
2333 /// Type inference. Try to infer the type arguments from the params method
2334 /// `method', which is invoked with the arguments `arguments'. This is used
2335 /// when resolving an Invocation or a DelegateInvocation and the user
2336 /// did not explicitly specify type arguments.
2338 public static bool InferParamsTypeArguments (EmitContext ec
, ArrayList arguments
,
2339 ref MethodBase method
)
2341 if (!TypeManager
.IsGenericMethod (method
))
2344 // if there are no arguments, there's no way to infer the type-arguments
2345 if (arguments
== null || arguments
.Count
== 0)
2348 ParameterData pd
= TypeManager
.GetParameterData (method
);
2349 int pd_count
= pd
.Count
;
2350 int arg_count
= arguments
.Count
;
2355 if (pd
.ParameterModifier (pd_count
- 1) != Parameter
.Modifier
.PARAMS
)
2358 if (pd_count
- 1 > arg_count
)
2361 Type
[] method_args
= method
.GetGenericArguments ();
2362 Type
[] inferred_types
= new Type
[method_args
.Length
];
2365 // If we have come this far, the case which
2366 // remains is when the number of parameters is
2367 // less than or equal to the argument count.
2369 for (int i
= 0; i
< pd_count
- 1; ++i
) {
2370 Argument a
= (Argument
) arguments
[i
];
2372 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2375 Type pt
= pd
.ParameterType (i
);
2378 if (!UnifyType (pt
, at
, inferred_types
))
2382 Type element_type
= TypeManager
.GetElementType (pd
.ParameterType (pd_count
- 1));
2384 for (int i
= pd_count
- 1; i
< arg_count
; i
++) {
2385 Argument a
= (Argument
) arguments
[i
];
2387 if ((a
.Expr
is NullLiteral
) || (a
.Expr
is MethodGroupExpr
))
2390 if (!UnifyType (element_type
, a
.Type
, inferred_types
))
2394 for (int i
= 0; i
< inferred_types
.Length
; i
++)
2395 if (inferred_types
[i
] == null)
2398 method
= ((MethodInfo
)method
).MakeGenericMethod (inferred_types
);
2402 static bool InferTypeArguments (Type
[] param_types
, Type
[] arg_types
,
2403 Type
[] inferred_types
)
2405 for (int i
= 0; i
< arg_types
.Length
; i
++) {
2406 if (arg_types
[i
] == null)
2409 if (!UnifyType (param_types
[i
], arg_types
[i
], inferred_types
))
2413 for (int i
= 0; i
< inferred_types
.Length
; ++i
)
2414 if (inferred_types
[i
] == null)
2421 // Infers the type of a single LambdaExpression in the invocation call and
2422 // stores the infered type in the inferred_types array.
2424 // The index of the arguments that contain lambdas is passed in
2426 // @lambdas. Merely to avoid rescanning the list.
2428 // The method being called:
2429 // @method_generic_args: The generic type arguments for the method being called
2430 // @method_pd: The ParameterData for the method being called.
2433 // @arguments: Arraylist of Argument()s. The arguments being passed.
2436 // @inferred_types: the array that is populated with our results.
2438 // true if the code was able to do one inference.
2440 static bool LambdaInfer (EmitContext ec
,
2441 Type
[] method_generic_args
,
2442 ParameterData method_pd
,
2443 ArrayList arguments
,
2444 Type
[] inferred_types
,
2447 int last_count
= lambdas
.Count
;
2449 for (int i
= 0; i
< last_count
; i
++){
2450 int argn
= (int) lambdas
[i
];
2452 Argument a
= (Argument
) arguments
[argn
];
2454 LambdaExpression le
= a
.Expr
as LambdaExpression
;
2457 throw new Exception (
2458 String
.Format ("Internal Compiler error: argument {0} should be a Lambda Expression",
2462 // "The corresponding parameter’s type, in the
2463 // following called P, is a delegate type with a
2464 // return type that involves one or more method type
2468 if (!TypeManager
.IsDelegateType (method_pd
.ParameterType (argn
)))
2469 goto useless_lambda
;
2471 Type p_type
= method_pd
.ParameterType (argn
);
2472 MethodGroupExpr method_group
= Expression
.MemberLookup (
2473 ec
.ContainerType
, p_type
, "Invoke", MemberTypes
.Method
,
2474 Expression
.AllBindingFlags
, Location
.Null
) as MethodGroupExpr
;
2476 if (method_group
== null){
2477 // This we report elsewhere as -200, but here we can ignore
2478 goto useless_lambda
;
2480 MethodInfo p_delegate_method
= method_group
.Methods
[0] as MethodInfo
;
2481 if (p_delegate_method
== null){
2482 // This should not happen.
2483 goto useless_lambda
;
2486 Type p_return_type
= p_delegate_method
.ReturnType
;
2487 if (!p_return_type
.IsGenericParameter
)
2488 goto useless_lambda
;
2491 // P and L have the same number of parameters, and
2492 // each parameter in P has the same modifiers as the
2493 // corresponding parameter in L, or no modifiers if
2494 // L has an implicitly typed parameter list.
2496 ParameterData p_delegate_parameters
= TypeManager
.GetParameterData (p_delegate_method
);
2497 int p_delegate_parameter_count
= p_delegate_parameters
.Count
;
2498 if (p_delegate_parameter_count
!= le
.Parameters
.Count
)
2499 goto useless_lambda
;
2501 if (le
.HasExplicitParameters
){
2502 for (int j
= 0; j
< p_delegate_parameter_count
; j
++){
2503 if (p_delegate_parameters
.ParameterModifier (j
) !=
2504 le
.Parameters
.ParameterModifier (j
))
2505 goto useless_lambda
;
2508 for (int j
= 0; j
< p_delegate_parameter_count
; j
++)
2509 if (le
.Parameters
.ParameterModifier (j
) != Parameter
.Modifier
.NONE
)
2510 goto useless_lambda
;
2514 // TODO: P’s parameter types involve no method type
2515 // parameters or involve only method type parameters
2516 // for which a consistent set of inferences have
2517 // already been made.
2519 //Console.WriteLine ("Method: {0}", p_delegate_method);
2520 //for (int j = 0; j < p_delegate_parameter_count; j++){
2521 //Console.WriteLine ("PType [{2}, {0}] = {1}", j, p_delegate_parameters.ParameterType (j), argn);
2525 // At this point we know that P has method type parameters
2526 // that involve only type parameters that have a consistent
2527 // set of inferences made.
2529 if (le
.HasExplicitParameters
){
2531 // TODO: If L has an explicitly typed parameter
2532 // list, when inferred types are substituted for
2533 // method type parameters in P, each parameter in P
2534 // has the same type as the corresponding parameter
2539 // TODO: If L has an implicitly typed parameter
2540 // list, when inferred types are substituted for
2541 // method type parameters in P and the resulting
2542 // parameter types are given to the parameters of L,
2543 // the body of L is a valid expression or statement
2546 Type
[] types
= new Type
[p_delegate_parameter_count
];
2548 bool failure
= false;
2549 for (int j
= 0; j
< p_delegate_parameter_count
; j
++){
2550 Type p_pt
= p_delegate_parameters
.ParameterType (j
);
2552 if (!p_pt
.IsGenericParameter
){
2558 for (int k
= 0; k
< method_generic_args
.Length
; k
++){
2559 if (method_generic_args
[k
] == p_pt
){
2560 types
[j
] = inferred_types
[k
];
2565 // If we could not infer just yet, continue
2567 if (types
[j
] == null)
2572 // If it results in a valid expression or statement block
2574 Type lambda_inferred_type
= le
.TryBuild (ec
, types
);
2576 if (lambda_inferred_type
!= null){
2578 // Success, set the proper inferred_type value to the new type.
2581 for (int k
= 0; k
< method_generic_args
.Length
; k
++){
2582 if (method_generic_args
[k
] == p_return_type
){
2583 inferred_types
[k
] = lambda_inferred_type
;
2585 lambdas
.RemoveAt (i
);
2593 lambdas
.RemoveAt (i
);
2600 Console
.WriteLine ("Inferred types");
2601 foreach (Type it
in inferred_types
){
2602 Console
.WriteLine (" IT: {0}", it
);
2608 // No inference was made in any of the elements.
2613 /// Type inference. Try to infer the type arguments from `method',
2614 /// which is invoked with the arguments `arguments'. This is used
2615 /// when resolving an Invocation or a DelegateInvocation and the user
2616 /// did not explicitly specify type arguments.
2618 public static bool InferTypeArguments (EmitContext ec
,
2619 ArrayList arguments
,
2620 ref MethodBase method
)
2622 if (!TypeManager
.IsGenericMethod (method
))
2626 if (arguments
!= null)
2627 arg_count
= arguments
.Count
;
2631 ParameterData pd
= TypeManager
.GetParameterData (method
);
2632 if (arg_count
!= pd
.Count
)
2635 Type
[] method_generic_args
= method
.GetGenericArguments ();
2637 bool is_open
= false;
2639 for (int i
= 0; i
< method_generic_args
.Length
; i
++) {
2640 if (method_generic_args
[i
].IsGenericParameter
) {
2646 // If none of the method parameters mention a generic parameter, we can't infer the generic parameters
2648 return !TypeManager
.IsGenericMethodDefinition (method
);
2650 Type
[] inferred_types
= new Type
[method_generic_args
.Length
];
2652 Type
[] param_types
= new Type
[pd
.Count
];
2653 Type
[] arg_types
= new Type
[pd
.Count
];
2654 ArrayList lambdas
= null;
2656 for (int i
= 0; i
< arg_count
; i
++) {
2657 param_types
[i
] = pd
.ParameterType (i
);
2659 Argument a
= (Argument
) arguments
[i
];
2660 if (a
.Expr
is NullLiteral
|| a
.Expr
is MethodGroupExpr
)
2663 if (a
.Expr
is LambdaExpression
){
2664 if (lambdas
== null)
2665 lambdas
= new ArrayList ();
2668 else if (a
.Expr
is AnonymousMethodExpression
) {
2669 if (RootContext
.Version
!= LanguageVersion
.LINQ
)
2672 Type dtype
= param_types
[i
];
2673 if (!TypeManager
.IsDelegateType (dtype
))
2676 AnonymousMethodExpression am
= (AnonymousMethodExpression
)a
.Expr
;
2678 Expression e
= am
.Compatible (ec
, dtype
);
2682 arg_types
[i
] = e
.Type
;
2686 arg_types
[i
] = a
.Type
;
2689 if (!InferTypeArguments (param_types
, arg_types
, inferred_types
)){
2690 //Console.WriteLine ("InferTypeArgument found {0} lambdas ", lambdas);
2691 if (lambdas
== null)
2695 // While the lambda expressions lead to a valid inference
2699 lambda_count
= lambdas
.Count
;
2700 if (!LambdaInfer (ec
, method_generic_args
, pd
, arguments
, inferred_types
, lambdas
))
2702 } while (lambdas
.Count
!= 0 && lambdas
.Count
!= lambda_count
);
2705 method
= ((MethodInfo
)method
).MakeGenericMethod (inferred_types
);
2708 // MS implementation throws NotSupportedException for GetParameters
2709 // on unbaked generic method
2710 ParameterData p
= TypeManager
.GetParameterData (method
);
2711 p
.InflateTypes (param_types
, inferred_types
);
2720 public static bool InferTypeArguments (ParameterData apd
,
2721 ref MethodBase method
)
2723 if (!TypeManager
.IsGenericMethod (method
))
2726 ParameterData pd
= TypeManager
.GetParameterData (method
);
2727 if (apd
.Count
!= pd
.Count
)
2730 Type
[] method_args
= method
.GetGenericArguments ();
2731 Type
[] inferred_types
= new Type
[method_args
.Length
];
2733 Type
[] param_types
= new Type
[pd
.Count
];
2734 Type
[] arg_types
= new Type
[pd
.Count
];
2736 for (int i
= 0; i
< apd
.Count
; i
++) {
2737 param_types
[i
] = pd
.ParameterType (i
);
2738 arg_types
[i
] = apd
.ParameterType (i
);
2741 if (!InferTypeArguments (param_types
, arg_types
, inferred_types
))
2744 method
= ((MethodInfo
)method
).MakeGenericMethod (inferred_types
);
2749 public abstract class Nullable
2751 public sealed class NullableInfo
2753 public readonly Type Type
;
2754 public readonly Type UnderlyingType
;
2755 public readonly MethodInfo HasValue
;
2756 public readonly MethodInfo Value
;
2757 public readonly ConstructorInfo Constructor
;
2759 public NullableInfo (Type type
)
2762 UnderlyingType
= TypeManager
.GetTypeArguments (type
) [0];
2764 PropertyInfo has_value_pi
= TypeManager
.GetProperty (type
, "HasValue");
2765 PropertyInfo value_pi
= TypeManager
.GetProperty (type
, "Value");
2767 HasValue
= has_value_pi
.GetGetMethod (false);
2768 Value
= value_pi
.GetGetMethod (false);
2769 Constructor
= type
.GetConstructor (new Type
[] { UnderlyingType }
);
2773 public class Unwrap
: Expression
, IMemoryLocation
, IAssignMethod
2778 LocalTemporary temp
;
2781 protected Unwrap (Expression expr
)
2784 this.loc
= expr
.Location
;
2787 public static Unwrap
Create (Expression expr
, EmitContext ec
)
2789 return new Unwrap (expr
).Resolve (ec
) as Unwrap
;
2792 public override Expression
DoResolve (EmitContext ec
)
2794 expr
= expr
.Resolve (ec
);
2798 temp
= new LocalTemporary (expr
.Type
);
2800 info
= new NullableInfo (expr
.Type
);
2801 type
= info
.UnderlyingType
;
2802 eclass
= expr
.eclass
;
2806 public override void Emit (EmitContext ec
)
2808 AddressOf (ec
, AddressOp
.LoadStore
);
2809 ec
.ig
.EmitCall (OpCodes
.Call
, info
.Value
, null);
2812 public void EmitCheck (EmitContext ec
)
2814 AddressOf (ec
, AddressOp
.LoadStore
);
2815 ec
.ig
.EmitCall (OpCodes
.Call
, info
.HasValue
, null);
2818 public void Store (EmitContext ec
)
2823 void create_temp (EmitContext ec
)
2825 if ((temp
!= null) && !has_temp
) {
2832 public void AddressOf (EmitContext ec
, AddressOp mode
)
2836 temp
.AddressOf (ec
, AddressOp
.LoadStore
);
2838 ((IMemoryLocation
) expr
).AddressOf (ec
, AddressOp
.LoadStore
);
2841 public void Emit (EmitContext ec
, bool leave_copy
)
2854 public void EmitAssign (EmitContext ec
, Expression source
,
2855 bool leave_copy
, bool prepare_for_load
)
2857 InternalWrap wrap
= new InternalWrap (source
, info
, loc
);
2858 ((IAssignMethod
) expr
).EmitAssign (ec
, wrap
, leave_copy
, false);
2861 protected class InternalWrap
: Expression
2863 public Expression expr
;
2864 public NullableInfo info
;
2866 public InternalWrap (Expression expr
, NullableInfo info
, Location loc
)
2873 eclass
= ExprClass
.Value
;
2876 public override Expression
DoResolve (EmitContext ec
)
2881 public override void Emit (EmitContext ec
)
2884 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2889 public class Wrap
: Expression
2894 protected Wrap (Expression expr
)
2897 this.loc
= expr
.Location
;
2900 public static Wrap
Create (Expression expr
, EmitContext ec
)
2902 return new Wrap (expr
).Resolve (ec
) as Wrap
;
2905 public override Expression
DoResolve (EmitContext ec
)
2907 expr
= expr
.Resolve (ec
);
2911 TypeExpr target_type
= new NullableType (expr
.Type
, loc
);
2912 target_type
= target_type
.ResolveAsTypeTerminal (ec
, false);
2913 if (target_type
== null)
2916 type
= target_type
.Type
;
2917 info
= new NullableInfo (type
);
2918 eclass
= ExprClass
.Value
;
2922 public override void Emit (EmitContext ec
)
2925 ec
.ig
.Emit (OpCodes
.Newobj
, info
.Constructor
);
2929 public class NullableLiteral
: NullLiteral
, IMemoryLocation
{
2930 public NullableLiteral (Type target_type
, Location loc
)
2933 this.type
= target_type
;
2935 eclass
= ExprClass
.Value
;
2938 public override Expression
DoResolve (EmitContext ec
)
2943 public override void Emit (EmitContext ec
)
2945 LocalTemporary value_target
= new LocalTemporary (type
);
2947 value_target
.AddressOf (ec
, AddressOp
.Store
);
2948 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2949 value_target
.Emit (ec
);
2952 public void AddressOf (EmitContext ec
, AddressOp Mode
)
2954 LocalTemporary value_target
= new LocalTemporary (type
);
2956 value_target
.AddressOf (ec
, AddressOp
.Store
);
2957 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
2958 ((IMemoryLocation
) value_target
).AddressOf (ec
, Mode
);
2962 public abstract class Lifted
: Expression
, IMemoryLocation
2964 Expression expr
, underlying
, wrap
, null_value
;
2967 protected Lifted (Expression expr
, Location loc
)
2973 public override Expression
DoResolve (EmitContext ec
)
2975 expr
= expr
.Resolve (ec
);
2979 unwrap
= Unwrap
.Create (expr
, ec
);
2983 underlying
= ResolveUnderlying (unwrap
, ec
);
2984 if (underlying
== null)
2987 wrap
= Wrap
.Create (underlying
, ec
);
2991 null_value
= new NullableLiteral (wrap
.Type
, loc
).Resolve (ec
);
2992 if (null_value
== null)
2996 eclass
= ExprClass
.Value
;
3000 protected abstract Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
);
3002 public override void Emit (EmitContext ec
)
3004 ILGenerator ig
= ec
.ig
;
3005 Label is_null_label
= ig
.DefineLabel ();
3006 Label end_label
= ig
.DefineLabel ();
3008 unwrap
.EmitCheck (ec
);
3009 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3012 ig
.Emit (OpCodes
.Br
, end_label
);
3014 ig
.MarkLabel (is_null_label
);
3015 null_value
.Emit (ec
);
3017 ig
.MarkLabel (end_label
);
3020 public void AddressOf (EmitContext ec
, AddressOp mode
)
3022 unwrap
.AddressOf (ec
, mode
);
3026 public class LiftedConversion
: Lifted
3028 public readonly bool IsUser
;
3029 public readonly bool IsExplicit
;
3030 public readonly Type TargetType
;
3032 public LiftedConversion (Expression expr
, Type target_type
, bool is_user
,
3033 bool is_explicit
, Location loc
)
3036 this.IsUser
= is_user
;
3037 this.IsExplicit
= is_explicit
;
3038 this.TargetType
= target_type
;
3041 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
3043 Type type
= TypeManager
.GetTypeArguments (TargetType
) [0];
3046 return Convert
.UserDefinedConversion (ec
, unwrap
, type
, loc
, IsExplicit
);
3049 return Convert
.ExplicitConversion (ec
, unwrap
, type
, loc
);
3051 return Convert
.ImplicitConversion (ec
, unwrap
, type
, loc
);
3056 public class LiftedUnaryOperator
: Lifted
3058 public readonly Unary
.Operator Oper
;
3060 public LiftedUnaryOperator (Unary
.Operator op
, Expression expr
, Location loc
)
3066 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
3068 return new Unary (Oper
, unwrap
, loc
);
3072 public class LiftedConditional
: Lifted
3074 Expression true_expr
, false_expr
;
3076 public LiftedConditional (Expression expr
, Expression true_expr
, Expression false_expr
,
3080 this.true_expr
= true_expr
;
3081 this.false_expr
= false_expr
;
3084 protected override Expression
ResolveUnderlying (Expression unwrap
, EmitContext ec
)
3086 return new Conditional (unwrap
, true_expr
, false_expr
);
3090 public class LiftedBinaryOperator
: Expression
3092 public readonly Binary
.Operator Oper
;
3094 Expression left
, right
, original_left
, original_right
;
3095 Expression underlying
, null_value
, bool_wrap
;
3096 Unwrap left_unwrap
, right_unwrap
;
3097 bool is_equality
, is_comparision
, is_boolean
;
3099 public LiftedBinaryOperator (Binary
.Operator op
, Expression left
, Expression right
,
3103 this.left
= original_left
= left
;
3104 this.right
= original_right
= right
;
3108 public override Expression
DoResolve (EmitContext ec
)
3110 if (TypeManager
.IsNullableType (left
.Type
)) {
3111 left
= left_unwrap
= Unwrap
.Create (left
, ec
);
3116 if (TypeManager
.IsNullableType (right
.Type
)) {
3117 right
= right_unwrap
= Unwrap
.Create (right
, ec
);
3122 if ((Oper
== Binary
.Operator
.LogicalAnd
) ||
3123 (Oper
== Binary
.Operator
.LogicalOr
)) {
3124 Binary
.Error_OperatorCannotBeApplied (
3125 loc
, Binary
.OperName (Oper
),
3126 original_left
.GetSignatureForError (),
3127 original_right
.GetSignatureForError ());
3131 if (((Oper
== Binary
.Operator
.BitwiseAnd
) || (Oper
== Binary
.Operator
.BitwiseOr
)) &&
3132 ((left
.Type
== TypeManager
.bool_type
) && (right
.Type
== TypeManager
.bool_type
))) {
3133 Expression empty
= new EmptyExpression (TypeManager
.bool_type
);
3134 bool_wrap
= Wrap
.Create (empty
, ec
);
3135 null_value
= new NullableLiteral (bool_wrap
.Type
, loc
).Resolve (ec
);
3137 type
= bool_wrap
.Type
;
3139 } else if ((Oper
== Binary
.Operator
.Equality
) || (Oper
== Binary
.Operator
.Inequality
)) {
3140 if (!(left
is NullLiteral
) && !(right
is NullLiteral
)) {
3141 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3142 if (underlying
== null)
3146 type
= TypeManager
.bool_type
;
3148 } else if ((Oper
== Binary
.Operator
.LessThan
) ||
3149 (Oper
== Binary
.Operator
.GreaterThan
) ||
3150 (Oper
== Binary
.Operator
.LessThanOrEqual
) ||
3151 (Oper
== Binary
.Operator
.GreaterThanOrEqual
)) {
3152 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3153 if (underlying
== null)
3156 type
= TypeManager
.bool_type
;
3157 is_comparision
= true;
3159 underlying
= new Binary (Oper
, left
, right
).Resolve (ec
);
3160 if (underlying
== null)
3163 underlying
= Wrap
.Create (underlying
, ec
);
3164 if (underlying
== null)
3167 type
= underlying
.Type
;
3168 null_value
= new NullableLiteral (type
, loc
).Resolve (ec
);
3171 eclass
= ExprClass
.Value
;
3175 void EmitBoolean (EmitContext ec
)
3177 ILGenerator ig
= ec
.ig
;
3179 Label left_is_null_label
= ig
.DefineLabel ();
3180 Label right_is_null_label
= ig
.DefineLabel ();
3181 Label is_null_label
= ig
.DefineLabel ();
3182 Label wrap_label
= ig
.DefineLabel ();
3183 Label end_label
= ig
.DefineLabel ();
3185 if (left_unwrap
!= null) {
3186 left_unwrap
.EmitCheck (ec
);
3187 ig
.Emit (OpCodes
.Brfalse
, left_is_null_label
);
3191 ig
.Emit (OpCodes
.Dup
);
3192 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOr
))
3193 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
3195 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
3197 if (right_unwrap
!= null) {
3198 right_unwrap
.EmitCheck (ec
);
3199 ig
.Emit (OpCodes
.Brfalse
, right_is_null_label
);
3202 if ((Oper
== Binary
.Operator
.LogicalAnd
) || (Oper
== Binary
.Operator
.LogicalOr
))
3203 ig
.Emit (OpCodes
.Pop
);
3206 if (Oper
== Binary
.Operator
.BitwiseOr
)
3207 ig
.Emit (OpCodes
.Or
);
3208 else if (Oper
== Binary
.Operator
.BitwiseAnd
)
3209 ig
.Emit (OpCodes
.And
);
3210 ig
.Emit (OpCodes
.Br
, wrap_label
);
3212 ig
.MarkLabel (left_is_null_label
);
3213 if (right_unwrap
!= null) {
3214 right_unwrap
.EmitCheck (ec
);
3215 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3219 ig
.Emit (OpCodes
.Dup
);
3220 if ((Oper
== Binary
.Operator
.BitwiseOr
) || (Oper
== Binary
.Operator
.LogicalOr
))
3221 ig
.Emit (OpCodes
.Brtrue
, wrap_label
);
3223 ig
.Emit (OpCodes
.Brfalse
, wrap_label
);
3225 ig
.MarkLabel (right_is_null_label
);
3226 ig
.Emit (OpCodes
.Pop
);
3227 ig
.MarkLabel (is_null_label
);
3228 null_value
.Emit (ec
);
3229 ig
.Emit (OpCodes
.Br
, end_label
);
3231 ig
.MarkLabel (wrap_label
);
3232 ig
.Emit (OpCodes
.Nop
);
3233 bool_wrap
.Emit (ec
);
3234 ig
.Emit (OpCodes
.Nop
);
3236 ig
.MarkLabel (end_label
);
3239 void EmitEquality (EmitContext ec
)
3241 ILGenerator ig
= ec
.ig
;
3243 // Given 'X? x;' for any value type X: 'x != null' is the same as 'x.HasValue'
3244 if (left
is NullLiteral
) {
3245 if (right_unwrap
== null)
3246 throw new InternalErrorException ();
3247 right_unwrap
.EmitCheck (ec
);
3248 if (Oper
== Binary
.Operator
.Equality
) {
3249 ig
.Emit (OpCodes
.Ldc_I4_0
);
3250 ig
.Emit (OpCodes
.Ceq
);
3255 if (right
is NullLiteral
) {
3256 if (left_unwrap
== null)
3257 throw new InternalErrorException ();
3258 left_unwrap
.EmitCheck (ec
);
3259 if (Oper
== Binary
.Operator
.Equality
) {
3260 ig
.Emit (OpCodes
.Ldc_I4_0
);
3261 ig
.Emit (OpCodes
.Ceq
);
3266 Label both_have_value_label
= ig
.DefineLabel ();
3267 Label end_label
= ig
.DefineLabel ();
3269 if (left_unwrap
!= null && right_unwrap
!= null) {
3270 Label dissimilar_label
= ig
.DefineLabel ();
3272 left_unwrap
.EmitCheck (ec
);
3273 ig
.Emit (OpCodes
.Dup
);
3274 right_unwrap
.EmitCheck (ec
);
3275 ig
.Emit (OpCodes
.Bne_Un
, dissimilar_label
);
3277 ig
.Emit (OpCodes
.Brtrue
, both_have_value_label
);
3280 if (Oper
== Binary
.Operator
.Equality
)
3281 ig
.Emit (OpCodes
.Ldc_I4_1
);
3283 ig
.Emit (OpCodes
.Ldc_I4_0
);
3284 ig
.Emit (OpCodes
.Br
, end_label
);
3286 ig
.MarkLabel (dissimilar_label
);
3287 ig
.Emit (OpCodes
.Pop
);
3288 } else if (left_unwrap
!= null) {
3289 left_unwrap
.EmitCheck (ec
);
3290 ig
.Emit (OpCodes
.Brtrue
, both_have_value_label
);
3291 } else if (right_unwrap
!= null) {
3292 right_unwrap
.EmitCheck (ec
);
3293 ig
.Emit (OpCodes
.Brtrue
, both_have_value_label
);
3295 throw new InternalErrorException ("shouldn't get here");
3298 // one is null while the other isn't
3299 if (Oper
== Binary
.Operator
.Equality
)
3300 ig
.Emit (OpCodes
.Ldc_I4_0
);
3302 ig
.Emit (OpCodes
.Ldc_I4_1
);
3303 ig
.Emit (OpCodes
.Br
, end_label
);
3305 ig
.MarkLabel (both_have_value_label
);
3306 underlying
.Emit (ec
);
3308 ig
.MarkLabel (end_label
);
3311 void EmitComparision (EmitContext ec
)
3313 ILGenerator ig
= ec
.ig
;
3315 Label is_null_label
= ig
.DefineLabel ();
3316 Label end_label
= ig
.DefineLabel ();
3318 if (left_unwrap
!= null) {
3319 left_unwrap
.EmitCheck (ec
);
3320 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3323 if (right_unwrap
!= null) {
3324 right_unwrap
.EmitCheck (ec
);
3325 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3328 underlying
.Emit (ec
);
3329 ig
.Emit (OpCodes
.Br
, end_label
);
3331 ig
.MarkLabel (is_null_label
);
3332 ig
.Emit (OpCodes
.Ldc_I4_0
);
3334 ig
.MarkLabel (end_label
);
3337 public override void Emit (EmitContext ec
)
3339 if (left_unwrap
!= null)
3340 left_unwrap
.Store (ec
);
3341 if (right_unwrap
!= null)
3342 right_unwrap
.Store (ec
);
3347 } else if (is_equality
) {
3350 } else if (is_comparision
) {
3351 EmitComparision (ec
);
3355 ILGenerator ig
= ec
.ig
;
3357 Label is_null_label
= ig
.DefineLabel ();
3358 Label end_label
= ig
.DefineLabel ();
3360 if (left_unwrap
!= null) {
3361 left_unwrap
.EmitCheck (ec
);
3362 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3365 if (right_unwrap
!= null) {
3366 right_unwrap
.EmitCheck (ec
);
3367 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3370 underlying
.Emit (ec
);
3371 ig
.Emit (OpCodes
.Br
, end_label
);
3373 ig
.MarkLabel (is_null_label
);
3374 null_value
.Emit (ec
);
3376 ig
.MarkLabel (end_label
);
3380 public class OperatorTrueOrFalse
: Expression
3382 public readonly bool IsTrue
;
3387 public OperatorTrueOrFalse (Expression expr
, bool is_true
, Location loc
)
3389 this.IsTrue
= is_true
;
3394 public override Expression
DoResolve (EmitContext ec
)
3396 unwrap
= Unwrap
.Create (expr
, ec
);
3400 if (unwrap
.Type
!= TypeManager
.bool_type
)
3403 type
= TypeManager
.bool_type
;
3404 eclass
= ExprClass
.Value
;
3408 public override void Emit (EmitContext ec
)
3410 ILGenerator ig
= ec
.ig
;
3412 Label is_null_label
= ig
.DefineLabel ();
3413 Label end_label
= ig
.DefineLabel ();
3415 unwrap
.EmitCheck (ec
);
3416 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3420 ig
.Emit (OpCodes
.Ldc_I4_0
);
3421 ig
.Emit (OpCodes
.Ceq
);
3423 ig
.Emit (OpCodes
.Br
, end_label
);
3425 ig
.MarkLabel (is_null_label
);
3426 ig
.Emit (OpCodes
.Ldc_I4_0
);
3428 ig
.MarkLabel (end_label
);
3432 public class NullCoalescingOperator
: Expression
3434 Expression left
, right
;
3438 public NullCoalescingOperator (Expression left
, Expression right
, Location loc
)
3444 eclass
= ExprClass
.Value
;
3447 public override Expression
DoResolve (EmitContext ec
)
3452 left
= left
.Resolve (ec
);
3456 right
= right
.Resolve (ec
);
3460 Type ltype
= left
.Type
, rtype
= right
.Type
;
3462 if (!TypeManager
.IsNullableType (ltype
) && ltype
.IsValueType
) {
3463 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
3467 if (TypeManager
.IsNullableType (ltype
)) {
3468 NullableInfo info
= new NullableInfo (ltype
);
3470 unwrap
= Unwrap
.Create (left
, ec
);
3474 expr
= Convert
.ImplicitConversion (ec
, right
, info
.UnderlyingType
, loc
);
3482 expr
= Convert
.ImplicitConversion (ec
, right
, ltype
, loc
);
3488 Expression left_null
= unwrap
!= null ? unwrap
: left
;
3489 expr
= Convert
.ImplicitConversion (ec
, left_null
, rtype
, loc
);
3497 Binary
.Error_OperatorCannotBeApplied (loc
, "??", ltype
, rtype
);
3501 public override void Emit (EmitContext ec
)
3503 ILGenerator ig
= ec
.ig
;
3505 Label is_null_label
= ig
.DefineLabel ();
3506 Label end_label
= ig
.DefineLabel ();
3508 if (unwrap
!= null) {
3509 unwrap
.EmitCheck (ec
);
3510 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3513 ig
.Emit (OpCodes
.Br
, end_label
);
3515 ig
.MarkLabel (is_null_label
);
3518 ig
.MarkLabel (end_label
);
3521 ig
.Emit (OpCodes
.Dup
);
3522 ig
.Emit (OpCodes
.Brtrue
, end_label
);
3524 ig
.MarkLabel (is_null_label
);
3526 ig
.Emit (OpCodes
.Pop
);
3529 ig
.MarkLabel (end_label
);
3534 public class LiftedUnaryMutator
: ExpressionStatement
3536 public readonly UnaryMutator
.Mode Mode
;
3537 Expression expr
, null_value
;
3538 UnaryMutator underlying
;
3541 public LiftedUnaryMutator (UnaryMutator
.Mode mode
, Expression expr
, Location loc
)
3547 eclass
= ExprClass
.Value
;
3550 public override Expression
DoResolve (EmitContext ec
)
3552 expr
= expr
.Resolve (ec
);
3556 unwrap
= Unwrap
.Create (expr
, ec
);
3560 underlying
= (UnaryMutator
) new UnaryMutator (Mode
, unwrap
, loc
).Resolve (ec
);
3561 if (underlying
== null)
3564 null_value
= new NullableLiteral (expr
.Type
, loc
).Resolve (ec
);
3565 if (null_value
== null)
3572 void DoEmit (EmitContext ec
, bool is_expr
)
3574 ILGenerator ig
= ec
.ig
;
3575 Label is_null_label
= ig
.DefineLabel ();
3576 Label end_label
= ig
.DefineLabel ();
3578 unwrap
.EmitCheck (ec
);
3579 ig
.Emit (OpCodes
.Brfalse
, is_null_label
);
3582 underlying
.Emit (ec
);
3584 underlying
.EmitStatement (ec
);
3585 ig
.Emit (OpCodes
.Br
, end_label
);
3587 ig
.MarkLabel (is_null_label
);
3589 null_value
.Emit (ec
);
3591 ig
.MarkLabel (end_label
);
3594 public override void Emit (EmitContext ec
)
3599 public override void EmitStatement (EmitContext ec
)