2 // generic.cs: Generics support
4 // Authors: Martin Baulig (martin@ximian.com)
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
14 using System
.Reflection
;
15 using System
.Reflection
.Emit
;
16 using System
.Globalization
;
17 using System
.Collections
.Generic
;
21 namespace Mono
.CSharp
{
25 // Don't add or modify internal values, they are used as -/+ calculation signs
33 public enum SpecialConstraint
41 public class SpecialContraintExpr
: FullNamedExpression
43 public SpecialContraintExpr (SpecialConstraint constraint
, Location loc
)
46 this.Constraint
= constraint
;
49 public SpecialConstraint Constraint { get; private set; }
51 protected override Expression
DoResolve (ResolveContext rc
)
53 throw new NotImplementedException ();
58 // A set of parsed constraints for a type parameter
60 public class Constraints
62 SimpleMemberName tparam
;
63 List
<FullNamedExpression
> constraints
;
68 public Constraints (SimpleMemberName tparam
, List
<FullNamedExpression
> constraints
, Location loc
)
71 this.constraints
= constraints
;
77 public Location Location
{
83 public SimpleMemberName TypeParameter
{
91 bool CheckConflictingInheritedConstraint (TypeSpec ba
, TypeSpec bb
, IMemberContext context
, Location loc
)
93 if (!TypeManager
.IsSubclassOf (ba
, bb
) && !TypeManager
.IsSubclassOf (bb
, ba
)) {
94 context
.Compiler
.Report
.Error (455, loc
,
95 "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
97 ba
.GetSignatureForError (), bb
.GetSignatureForError ());
104 public void CheckGenericConstraints (IMemberContext context
)
106 foreach (var c
in constraints
) {
107 var ge
= c
as GenericTypeExpr
;
109 ge
.CheckConstraints (context
);
114 // Resolve the constraints types with only possible early checks, return
115 // value `false' is reserved for recursive failure
117 public bool Resolve (IMemberContext context
, TypeParameter tp
)
127 List
<TypeParameterSpec
> tparam_types
= null;
128 bool iface_found
= false;
130 spec
.BaseType
= TypeManager
.object_type
;
132 for (int i
= 0; i
< constraints
.Count
; ++i
) {
133 var constraint
= constraints
[i
];
135 if (constraint
is SpecialContraintExpr
) {
136 spec
.SpecialConstraint
|= ((SpecialContraintExpr
) constraint
).Constraint
;
137 if (spec
.HasSpecialStruct
)
138 spec
.BaseType
= TypeManager
.value_type
;
140 // Set to null as it does not have a type
141 constraints
[i
] = null;
145 var type_expr
= constraints
[i
] = constraint
.ResolveAsTypeTerminal (context
, false);
146 if (type_expr
== null)
149 var gexpr
= type_expr
as GenericTypeExpr
;
150 if (gexpr
!= null && gexpr
.HasDynamicArguments ()) {
151 context
.Compiler
.Report
.Error (1968, constraint
.Location
,
152 "A constraint cannot be the dynamic type `{0}'", gexpr
.GetSignatureForError ());
156 var type
= type_expr
.Type
;
158 if (!context
.CurrentMemberDefinition
.IsAccessibleAs (type
)) {
159 context
.Compiler
.Report
.SymbolRelatedToPreviousError (type
);
160 context
.Compiler
.Report
.Error (703, loc
,
161 "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
162 type
.GetSignatureForError (), context
.GetSignatureForError ());
165 if (type
.IsInterface
) {
166 if (!spec
.AddInterface (type
)) {
167 context
.Compiler
.Report
.Error (405, constraint
.Location
,
168 "Duplicate constraint `{0}' for type parameter `{1}'", type
.GetSignatureForError (), tparam
.Value
);
176 var constraint_tp
= type
as TypeParameterSpec
;
177 if (constraint_tp
!= null) {
178 if (tparam_types
== null) {
179 tparam_types
= new List
<TypeParameterSpec
> (2);
180 } else if (tparam_types
.Contains (constraint_tp
)) {
181 context
.Compiler
.Report
.Error (405, constraint
.Location
,
182 "Duplicate constraint `{0}' for type parameter `{1}'", type
.GetSignatureForError (), tparam
.Value
);
187 // Checks whether each generic method parameter constraint type
188 // is valid with respect to T
190 if (tp
.IsMethodTypeParameter
) {
191 TypeManager
.CheckTypeVariance (type
, Variance
.Contravariant
, context
);
194 var tp_def
= constraint_tp
.MemberDefinition
as TypeParameter
;
195 if (tp_def
!= null && !tp_def
.ResolveConstraints (context
)) {
196 context
.Compiler
.Report
.Error (454, constraint
.Location
,
197 "Circular constraint dependency involving `{0}' and `{1}'",
198 constraint_tp
.GetSignatureForError (), tp
.GetSignatureForError ());
203 // Checks whether there are no conflicts between type parameter constraints
209 // A and B are not convertible and only 1 class constraint is allowed
211 if (constraint_tp
.HasTypeConstraint
) {
212 if (spec
.HasTypeConstraint
|| spec
.HasSpecialStruct
) {
213 if (!CheckConflictingInheritedConstraint (spec
.BaseType
, constraint_tp
.BaseType
, context
, constraint
.Location
))
216 for (int ii
= 0; ii
< tparam_types
.Count
; ++ii
) {
217 if (!tparam_types
[ii
].HasTypeConstraint
)
220 if (!CheckConflictingInheritedConstraint (tparam_types
[ii
].BaseType
, constraint_tp
.BaseType
, context
, constraint
.Location
))
226 if (constraint_tp
.HasSpecialStruct
) {
227 context
.Compiler
.Report
.Error (456, constraint
.Location
,
228 "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
229 constraint_tp
.GetSignatureForError (), tp
.GetSignatureForError ());
233 tparam_types
.Add (constraint_tp
);
237 if (iface_found
|| spec
.HasTypeConstraint
) {
238 context
.Compiler
.Report
.Error (406, constraint
.Location
,
239 "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
240 type
.GetSignatureForError ());
243 if (spec
.HasSpecialStruct
|| spec
.HasSpecialClass
) {
244 context
.Compiler
.Report
.Error (450, type_expr
.Location
,
245 "`{0}': cannot specify both a constraint class and the `class' or `struct' constraint",
246 type
.GetSignatureForError ());
249 if (type
== InternalType
.Dynamic
) {
250 context
.Compiler
.Report
.Error (1967, constraint
.Location
, "A constraint cannot be the dynamic type");
254 if (type
.IsSealed
|| !type
.IsClass
) {
255 context
.Compiler
.Report
.Error (701, loc
,
256 "`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter",
257 TypeManager
.CSharpName (type
));
262 context
.Compiler
.Report
.Error (717, constraint
.Location
,
263 "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
264 type
.GetSignatureForError ());
265 } else if (type
== TypeManager
.array_type
|| type
== TypeManager
.delegate_type
||
266 type
== TypeManager
.enum_type
|| type
== TypeManager
.value_type
||
267 type
== TypeManager
.object_type
|| type
== TypeManager
.multicast_delegate_type
) {
268 context
.Compiler
.Report
.Error (702, constraint
.Location
,
269 "A constraint cannot be special class `{0}'", type
.GetSignatureForError ());
273 spec
.BaseType
= type
;
276 if (tparam_types
!= null)
277 spec
.TypeArguments
= tparam_types
.ToArray ();
284 public void VerifyClsCompliance (Report report
)
286 foreach (var c
in constraints
)
291 if (!c
.Type
.IsCLSCompliant ()) {
292 report
.SymbolRelatedToPreviousError (c
.Type
);
293 report
.Warning (3024, 1, loc
, "Constraint type `{0}' is not CLS-compliant",
294 c
.Type
.GetSignatureForError ());
301 // A type parameter for a generic type or generic method definition
303 public class TypeParameter
: MemberCore
, ITypeDefinition
305 static readonly string[] attribute_target
= new string [] { "type parameter" }
;
307 Constraints constraints
;
308 GenericTypeParameterBuilder builder
;
309 // Variance variance;
310 TypeParameterSpec spec
;
312 public TypeParameter (DeclSpace parent
, int index
, MemberName name
, Constraints constraints
, Attributes attrs
, Variance variance
)
313 : base (parent
, name
, attrs
)
315 this.constraints
= constraints
;
316 // this.variance = variance;
317 this.spec
= new TypeParameterSpec (null, index
, this, SpecialConstraint
.None
, variance
, null);
322 public override AttributeTargets AttributeTargets
{
324 return AttributeTargets
.GenericParameter
;
328 public override string DocCommentHeader
{
330 throw new InvalidOperationException (
331 "Unexpected attempt to get doc comment from " + this.GetType ());
335 public bool IsMethodTypeParameter
{
337 return spec
.IsMethodOwned
;
341 public string Namespace
{
347 public TypeParameterSpec Type
{
353 public int TypeParametersCount
{
359 public TypeParameterSpec
[] TypeParameters
{
365 public override string[] ValidAttributeTargets
{
367 return attribute_target
;
371 public Variance Variance
{
373 return spec
.Variance
;
380 // This is called for each part of a partial generic type definition.
382 // If partial type parameters constraints are not null and we don't
383 // already have constraints they become our constraints. If we already
384 // have constraints, we must check that they're the same.
386 public bool AddPartialConstraints (TypeContainer part
, TypeParameter tp
)
389 throw new InvalidOperationException ();
391 var new_constraints
= tp
.constraints
;
392 if (new_constraints
== null)
395 // TODO: could create spec only
396 //tp.Define (null, -1, part.Definition);
397 tp
.spec
.DeclaringType
= part
.Definition
;
398 if (!tp
.ResolveConstraints (part
))
401 if (constraints
!= null)
402 return spec
.HasSameConstraintsDefinition (tp
.Type
);
404 // Copy constraint from resolved part to partial container
405 spec
.SpecialConstraint
= tp
.spec
.SpecialConstraint
;
406 spec
.InterfacesDefined
= tp
.spec
.InterfacesDefined
;
407 spec
.TypeArguments
= tp
.spec
.TypeArguments
;
408 spec
.BaseType
= tp
.spec
.BaseType
;
413 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
415 builder
.SetCustomAttribute ((ConstructorInfo
) ctor
.GetMetaInfo (), cdata
);
418 public void CheckGenericConstraints ()
420 if (constraints
!= null)
421 constraints
.CheckGenericConstraints (this);
424 public TypeParameter
CreateHoistedCopy (TypeSpec declaringType
)
426 return new TypeParameter (Parent
, spec
.DeclaredPosition
, MemberName
, constraints
, null, spec
.Variance
) {
427 spec
= new TypeParameterSpec (declaringType
, spec
.DeclaredPosition
, spec
.MemberDefinition
, spec
.SpecialConstraint
, spec
.Variance
, null) {
428 BaseType
= spec
.BaseType
,
429 InterfacesDefined
= spec
.InterfacesDefined
,
430 TypeArguments
= spec
.TypeArguments
435 public override bool Define ()
441 // This is the first method which is called during the resolving
442 // process; we're called immediately after creating the type parameters
443 // with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
446 public void Define (GenericTypeParameterBuilder type
, TypeSpec declaringType
)
449 throw new InternalErrorException ();
452 spec
.DeclaringType
= declaringType
;
453 spec
.SetMetaInfo (type
);
456 public void EmitConstraints (GenericTypeParameterBuilder builder
)
458 var attr
= GenericParameterAttributes
.None
;
459 if (spec
.Variance
== Variance
.Contravariant
)
460 attr
|= GenericParameterAttributes
.Contravariant
;
461 else if (spec
.Variance
== Variance
.Covariant
)
462 attr
|= GenericParameterAttributes
.Covariant
;
464 if (spec
.HasSpecialClass
)
465 attr
|= GenericParameterAttributes
.ReferenceTypeConstraint
;
466 else if (spec
.HasSpecialStruct
)
467 attr
|= GenericParameterAttributes
.NotNullableValueTypeConstraint
| GenericParameterAttributes
.DefaultConstructorConstraint
;
469 if (spec
.HasSpecialConstructor
)
470 attr
|= GenericParameterAttributes
.DefaultConstructorConstraint
;
472 if (spec
.BaseType
!= TypeManager
.object_type
)
473 builder
.SetBaseTypeConstraint (spec
.BaseType
.GetMetaInfo ());
475 if (spec
.InterfacesDefined
!= null)
476 builder
.SetInterfaceConstraints (spec
.InterfacesDefined
.Select (l
=> l
.GetMetaInfo ()).ToArray ());
478 if (spec
.TypeArguments
!= null)
479 builder
.SetInterfaceConstraints (spec
.TypeArguments
.Select (l
=> l
.GetMetaInfo ()).ToArray ());
481 builder
.SetGenericParameterAttributes (attr
);
484 public override void Emit ()
486 EmitConstraints (builder
);
488 if (OptAttributes
!= null)
489 OptAttributes
.Emit ();
494 public void ErrorInvalidVariance (IMemberContext mc
, Variance expected
)
496 Report
.SymbolRelatedToPreviousError (mc
.CurrentMemberDefinition
);
497 string input_variance
= Variance
== Variance
.Contravariant
? "contravariant" : "covariant";
498 string gtype_variance
;
500 case Variance
.Contravariant
: gtype_variance
= "contravariantly"; break;
501 case Variance
.Covariant
: gtype_variance
= "covariantly"; break;
502 default: gtype_variance
= "invariantly"; break;
505 Delegate d
= mc
as Delegate
;
506 string parameters
= d
!= null ? d
.Parameters
.GetSignatureForError () : "";
508 Report
.Error (1961, Location
,
509 "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'",
510 GetSignatureForError (), mc
.GetSignatureForError (), input_variance
, gtype_variance
, parameters
);
513 public TypeSpec
GetAttributeCoClass ()
518 public string GetAttributeDefaultMember ()
520 throw new NotSupportedException ();
523 public AttributeUsageAttribute
GetAttributeUsage (PredefinedAttribute pa
)
525 throw new NotSupportedException ();
528 public override string GetSignatureForError ()
530 return MemberName
.Name
;
533 public MemberCache
LoadMembers (TypeSpec declaringType
)
535 throw new NotSupportedException ("Not supported for compiled definition");
539 // Resolves all type parameter constraints
541 public bool ResolveConstraints (IMemberContext context
)
543 if (constraints
!= null)
544 return constraints
.Resolve (context
, this);
546 spec
.BaseType
= TypeManager
.object_type
;
550 public static TypeParameter
FindTypeParameter (TypeParameter
[] tparams
, string name
)
552 foreach (var tp
in tparams
) {
560 public override bool IsClsComplianceRequired ()
565 public new void VerifyClsCompliance ()
567 if (constraints
!= null)
568 constraints
.VerifyClsCompliance (Report
);
572 [System
.Diagnostics
.DebuggerDisplay ("{DisplayDebugInfo()}")]
573 public class TypeParameterSpec
: TypeSpec
575 public static readonly new TypeParameterSpec
[] EmptyTypes
= new TypeParameterSpec
[0];
578 SpecialConstraint spec
;
581 TypeSpec
[] ifaces_defined
;
584 // Creates type owned type parameter
586 public TypeParameterSpec (TypeSpec declaringType
, int index
, ITypeDefinition definition
, SpecialConstraint spec
, Variance variance
, Type info
)
587 : base (MemberKind
.TypeParameter
, declaringType
, definition
, info
, Modifiers
.PUBLIC
)
589 this.variance
= variance
;
591 state
&= ~StateFlags
.Obsolete_Undetected
;
596 // Creates method owned type parameter
598 public TypeParameterSpec (int index
, ITypeDefinition definition
, SpecialConstraint spec
, Variance variance
, Type info
)
599 : this (null, index
, definition
, spec
, variance
, info
)
605 public int DeclaredPosition
{
611 public bool HasSpecialConstructor
{
613 return (spec
& SpecialConstraint
.Constructor
) != 0;
617 public bool HasSpecialClass
{
619 return (spec
& SpecialConstraint
.Class
) != 0;
623 public bool HasSpecialStruct
{
625 return (spec
& SpecialConstraint
.Struct
) != 0;
629 public bool HasTypeConstraint
{
631 return BaseType
!= TypeManager
.object_type
&& BaseType
!= TypeManager
.value_type
;
635 public override IList
<TypeSpec
> Interfaces
{
637 if ((state
& StateFlags
.InterfacesExpanded
) == 0) {
638 if (ifaces
!= null) {
639 for (int i
= 0; i
< ifaces
.Count
; ++i
) {
640 var iface_type
= ifaces
[i
];
641 if (iface_type
.Interfaces
!= null) {
642 if (ifaces_defined
== null)
643 ifaces_defined
= ifaces
.ToArray ();
645 for (int ii
= 0; ii
< iface_type
.Interfaces
.Count
; ++ii
) {
646 var ii_iface_type
= iface_type
.Interfaces
[ii
];
648 AddInterface (ii_iface_type
);
654 if (ifaces_defined
== null && ifaces
!= null)
655 ifaces_defined
= ifaces
.ToArray ();
657 state
|= StateFlags
.InterfacesExpanded
;
665 // Unexpanded interfaces list
667 public TypeSpec
[] InterfacesDefined
{
669 if (ifaces_defined
== null && ifaces
!= null)
670 ifaces_defined
= ifaces
.ToArray ();
672 return ifaces_defined
;
675 ifaces_defined
= value;
679 public bool IsConstrained
{
681 return spec
!= SpecialConstraint
.None
|| ifaces
!= null || targs
!= null || HasTypeConstraint
;
686 // Returns whether the type parameter is "known to be a reference type"
688 public bool IsReferenceType
{
690 return (spec
& SpecialConstraint
.Class
) != 0 || HasTypeConstraint
;
694 public bool IsValueType
{ // TODO: Do I need this ?
696 // TODO MemberCache: probably wrong
697 return HasSpecialStruct
;
701 public override string Name
{
703 return definition
.Name
;
707 public bool IsMethodOwned
{
709 return DeclaringType
== null;
713 public SpecialConstraint SpecialConstraint
{
723 // Types used to inflate the generic type
725 public new TypeSpec
[] TypeArguments
{
734 public Variance Variance
{
742 public string DisplayDebugInfo ()
744 var s
= GetSignatureForError ();
745 return IsMethodOwned
? s
+ "!!" : s
+ "!";
749 // Finds effective base class
751 public TypeSpec
GetEffectiveBase ()
753 if (HasSpecialStruct
) {
754 return TypeManager
.value_type
;
757 if (BaseType
!= null && targs
== null)
761 if (HasTypeConstraint
) {
762 Array
.Resize (ref types
, types
.Length
+ 1);
763 types
[types
.Length
- 1] = BaseType
;
767 return Convert
.FindMostEncompassedType (types
.Select (l
=> l
.BaseType
));
769 return TypeManager
.object_type
;
772 public override string GetSignatureForError ()
778 // Constraints have to match by definition but not position, used by
779 // partial classes or methods
781 public bool HasSameConstraintsDefinition (TypeParameterSpec other
)
783 if (spec
!= other
.spec
)
786 if (BaseType
!= other
.BaseType
)
789 if (!TypeSpecComparer
.Override
.IsSame (InterfacesDefined
, other
.InterfacesDefined
))
792 if (!TypeSpecComparer
.Override
.IsSame (targs
, other
.targs
))
799 // Constraints have to match by using same set of types, used by
800 // implicit interface implementation
802 public bool HasSameConstraintsImplementation (TypeParameterSpec other
)
804 if (spec
!= other
.spec
)
808 // It can be same base type or inflated type parameter
810 // interface I<T> { void Foo<U> where U : T; }
811 // class A : I<int> { void Foo<X> where X : int {} }
814 if (BaseType
!= other
.BaseType
) {
815 if (other
.targs
== null)
819 foreach (var otarg
in other
.targs
) {
820 if (TypeSpecComparer
.Override
.IsEqual (BaseType
, otarg
)) {
830 // Check interfaces implementation -> definition
831 if (InterfacesDefined
!= null) {
832 foreach (var iface
in InterfacesDefined
) {
834 if (other
.InterfacesDefined
!= null) {
835 foreach (var oiface
in other
.InterfacesDefined
) {
836 if (TypeSpecComparer
.Override
.IsEqual (iface
, oiface
)) {
846 if (other
.targs
!= null) {
847 foreach (var otarg
in other
.targs
) {
848 if (TypeSpecComparer
.Override
.IsEqual (BaseType
, otarg
)) {
860 // Check interfaces implementation <- definition
861 if (other
.InterfacesDefined
!= null) {
862 if (InterfacesDefined
== null)
865 foreach (var oiface
in other
.InterfacesDefined
) {
867 foreach (var iface
in InterfacesDefined
) {
868 if (TypeSpecComparer
.Override
.IsEqual (iface
, oiface
)) {
879 // Check type parameters implementation -> definition
881 if (other
.targs
== null)
884 foreach (var targ
in targs
) {
886 foreach (var otarg
in other
.targs
) {
887 if (TypeSpecComparer
.Override
.IsEqual (targ
, otarg
)) {
898 // Check type parameters implementation <- definition
899 if (other
.targs
!= null) {
900 foreach (var otarg
in other
.targs
) {
901 // Ignore inflated type arguments, were checked above
902 if (!otarg
.IsGenericParameter
)
909 foreach (var targ
in targs
) {
910 if (TypeSpecComparer
.Override
.IsEqual (targ
, otarg
)) {
924 public static TypeParameterSpec
[] InflateConstraints (TypeParameterInflator inflator
, TypeParameterSpec
[] tparams
)
926 TypeParameterSpec
[] constraints
= null;
928 for (int i
= 0; i
< tparams
.Length
; ++i
) {
930 if (tp
.HasTypeConstraint
|| tp
.Interfaces
!= null || tp
.TypeArguments
!= null) {
931 if (constraints
== null) {
932 constraints
= new TypeParameterSpec
[tparams
.Length
];
933 Array
.Copy (tparams
, constraints
, constraints
.Length
);
936 constraints
[i
] = (TypeParameterSpec
) constraints
[i
].InflateMember (inflator
);
940 if (constraints
== null)
941 constraints
= tparams
;
946 public override MemberSpec
InflateMember (TypeParameterInflator inflator
)
948 var tps
= (TypeParameterSpec
) MemberwiseClone ();
949 tps
.BaseType
= inflator
.Inflate (BaseType
);
950 if (ifaces
!= null) {
951 tps
.ifaces
= new TypeSpec
[ifaces
.Count
];
952 for (int i
= 0; i
< ifaces
.Count
; ++i
)
953 tps
.ifaces
[i
] = inflator
.Inflate (ifaces
[i
]);
956 tps
.targs
= new TypeSpec
[targs
.Length
];
957 for (int i
= 0; i
< targs
.Length
; ++i
)
958 tps
.targs
[i
] = inflator
.Inflate (targs
[i
]);
965 // Populates type parameter members using type parameter constraints
966 // The trick here is to be called late enough but not too late to
967 // populate member cache with all members from other types
969 protected override void InitializeMemberCache (bool onlyTypes
)
971 cache
= new MemberCache ();
972 if (ifaces
!= null) {
973 foreach (var iface_type
in Interfaces
) {
974 cache
.AddInterface (iface_type
);
979 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
981 return mutator
.Mutate (this);
985 public struct TypeParameterInflator
987 readonly TypeSpec type
;
988 readonly TypeParameterSpec
[] tparams
;
989 readonly TypeSpec
[] targs
;
991 public TypeParameterInflator (TypeParameterInflator nested
, TypeSpec type
)
992 : this (type
, nested
.tparams
, nested
.targs
)
996 public TypeParameterInflator (TypeSpec type
, TypeParameterSpec
[] tparams
, TypeSpec
[] targs
)
998 if (tparams
.Length
!= targs
.Length
)
999 throw new ArgumentException ("Invalid arguments");
1001 this.tparams
= tparams
;
1007 // Type parameters to inflate
1009 public TypeParameterSpec
[] TypeParameters
{
1015 public TypeSpec
Inflate (TypeSpec ts
)
1017 var tp
= ts
as TypeParameterSpec
;
1019 return Inflate (tp
);
1021 var ac
= ts
as ArrayContainer
;
1023 var et
= Inflate (ac
.Element
);
1024 if (et
!= ac
.Element
)
1025 return ArrayContainer
.MakeType (et
, ac
.Rank
);
1031 // When inflating a nested type, inflate its parent first
1032 // in case it's using same type parameters (was inflated within the type)
1035 var parent
= Inflate (ts
.DeclaringType
);
1036 if (ts
.DeclaringType
!= parent
) {
1038 // Keep the inflated type arguments
1040 var targs
= ts
.TypeArguments
;
1043 // Parent was inflated, find the same type on inflated type
1044 // to use same cache for nested types on same generic parent
1046 // TODO: Should use BindingRestriction.DeclaredOnly or GetMember
1047 ts
= MemberCache
.FindNestedType (parent
, ts
.Name
, targs
.Length
);
1050 // Handle the tricky case where parent shares local type arguments
1051 // which means inflating inflated type
1054 // public static Nested<T> Foo () { return null; }
1056 // public class Nested<U> {}
1059 // return type of Test<string>.Foo() has to be Test<string>.Nested<string>
1061 if (targs
.Length
> 0) {
1062 var inflated_targs
= new TypeSpec
[targs
.Length
];
1063 for (var i
= 0; i
< targs
.Length
; ++i
)
1064 inflated_targs
[i
] = Inflate (targs
[i
]);
1066 ts
= ts
.MakeGenericType (inflated_targs
);
1073 // Inflate generic type
1075 return InflateTypeParameters (ts
);
1080 public TypeSpec
Inflate (TypeParameterSpec tp
)
1082 for (int i
= 0; i
< tparams
.Length
; ++i
)
1083 if (tparams
[i
] == tp
)
1086 // CECIL: This can happen when inflating nested types
1087 // without type arguments specified
1092 // Inflates generic types
1094 TypeSpec
InflateTypeParameters (TypeSpec type
)
1096 var targs
= new TypeSpec
[type
.Arity
];
1099 var gti
= type
as InflatedTypeSpec
;
1102 // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {}
1105 for (; i
< targs
.Length
; ++i
)
1106 targs
[i
] = Inflate (gti
.TypeArguments
[i
]);
1108 return gti
.GetDefinition ().MakeGenericType (targs
);
1112 // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; }
1114 var args
= type
.MemberDefinition
.TypeParameters
;
1115 foreach (var ds_tp
in args
)
1116 targs
[i
++] = Inflate (ds_tp
);
1118 return type
.MakeGenericType (targs
);
1121 public TypeSpec TypeInstance
{
1122 get { return type; }
1127 // Before emitting any code we have to change all MVAR references to VAR
1128 // when the method is of generic type and has hoisted variables
1130 public class TypeParameterMutator
1132 TypeParameter
[] mvar
;
1133 TypeParameter
[] var;
1134 Dictionary
<TypeSpec
, TypeSpec
> mutated_typespec
= new Dictionary
<TypeSpec
, TypeSpec
> ();
1136 public TypeParameterMutator (TypeParameter
[] mvar
, TypeParameter
[] var)
1138 if (mvar
.Length
!= var.Length
)
1139 throw new ArgumentException ();
1145 public TypeSpec
Mutate (TypeSpec ts
)
1148 if (mutated_typespec
.TryGetValue (ts
, out value))
1151 value = ts
.Mutate (this);
1152 mutated_typespec
.Add (ts
, value);
1156 public FieldInfo
Mutate (FieldSpec fs
)
1159 return fs
.GetMetaInfo ();
1162 public TypeParameterSpec
Mutate (TypeParameterSpec tp
)
1164 for (int i
= 0; i
< mvar
.Length
; ++i
) {
1165 if (mvar
[i
].Type
== tp
)
1172 public TypeSpec
[] Mutate (TypeSpec
[] targs
)
1174 TypeSpec
[] mutated
= new TypeSpec
[targs
.Length
];
1175 bool changed
= false;
1176 for (int i
= 0; i
< targs
.Length
; ++i
) {
1177 mutated
[i
] = Mutate (targs
[i
]);
1178 changed
|= targs
[i
] != mutated
[i
];
1181 return changed
? mutated
: targs
;
1186 /// A TypeExpr which already resolved to a type parameter.
1188 public class TypeParameterExpr
: TypeExpr
{
1190 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1192 this.type
= type_parameter
.Type
;
1193 this.eclass
= ExprClass
.TypeParameter
;
1197 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1199 throw new NotSupportedException ();
1202 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
1207 public override bool CheckAccessLevel (IMemberContext ds
)
1213 public class InflatedTypeSpec
: TypeSpec
1216 TypeParameterSpec
[] constraints
;
1217 readonly TypeSpec open_type
;
1219 public InflatedTypeSpec (TypeSpec openType
, TypeSpec declaringType
, TypeSpec
[] targs
)
1220 : base (openType
.Kind
, declaringType
, openType
.MemberDefinition
, null, openType
.Modifiers
)
1223 throw new ArgumentNullException ("targs");
1225 // this.state = openType.state;
1226 this.open_type
= openType
;
1232 public override TypeSpec BaseType
{
1234 if (cache
== null || (state
& StateFlags
.PendingBaseTypeInflate
) != 0)
1235 InitializeMemberCache (true);
1237 return base.BaseType
;
1242 // Inflated type parameters with constraints array, mapping with type arguments is based on index
1244 public TypeParameterSpec
[] Constraints
{
1246 if (constraints
== null) {
1247 var inflator
= new TypeParameterInflator (this, MemberDefinition
.TypeParameters
, targs
);
1248 constraints
= TypeParameterSpec
.InflateConstraints (inflator
, MemberDefinition
.TypeParameters
);
1255 public override IList
<TypeSpec
> Interfaces
{
1258 InitializeMemberCache (true);
1260 return base.Interfaces
;
1264 public override MemberCache MemberCacheTypes
{
1267 InitializeMemberCache (true);
1274 // Types used to inflate the generic type
1276 public override TypeSpec
[] TypeArguments
{
1284 Type
CreateMetaInfo (TypeParameterMutator mutator
)
1287 // Converts nested type arguments into right order
1288 // Foo<string, bool>.Bar<int> => string, bool, int
1290 var all
= new List
<Type
> ();
1291 TypeSpec type
= this;
1292 TypeSpec definition
= type
;
1294 if (type
.GetDefinition().IsGeneric
) {
1296 type
.TypeArguments
!= TypeSpec
.EmptyTypes
?
1297 type
.TypeArguments
.Select (l
=> l
.GetMetaInfo ()) :
1298 type
.MemberDefinition
.TypeParameters
.Select (l
=> l
.GetMetaInfo ()));
1301 definition
= definition
.GetDefinition ();
1302 type
= type
.DeclaringType
;
1303 } while (type
!= null);
1305 return definition
.GetMetaInfo ().MakeGenericType (all
.ToArray ());
1308 public override ObsoleteAttribute
GetAttributeObsolete ()
1310 return open_type
.GetAttributeObsolete ();
1313 protected override bool IsNotCLSCompliant ()
1315 if (base.IsNotCLSCompliant ())
1318 foreach (var ta
in TypeArguments
) {
1319 if (ta
.MemberDefinition
.IsNotCLSCompliant ())
1326 public override TypeSpec
GetDefinition ()
1331 public override Type
GetMetaInfo ()
1334 info
= CreateMetaInfo (null);
1339 public override string GetSignatureForError ()
1341 if (TypeManager
.IsNullableType (open_type
))
1342 return targs
[0].GetSignatureForError () + "?";
1344 if (MemberDefinition
is AnonymousTypeClass
)
1345 return ((AnonymousTypeClass
) MemberDefinition
).GetSignatureForError ();
1347 return base.GetSignatureForError ();
1350 protected override string GetTypeNameSignature ()
1352 if (targs
.Length
== 0 || MemberDefinition
is AnonymousTypeClass
)
1355 return "<" + TypeManager
.CSharpName (targs
) + ">";
1358 protected override void InitializeMemberCache (bool onlyTypes
)
1361 cache
= new MemberCache (open_type
.MemberCache
);
1363 TypeParameterSpec
[] tparams_full
;
1364 TypeSpec
[] targs_full
= targs
;
1367 // Special case is needed when we are inflating an open type (nested type definition)
1368 // on inflated parent. Consider following case
1370 // Foo<T>.Bar<U> => Foo<string>.Bar<U>
1372 // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U>
1374 List
<TypeSpec
> merged_targs
= null;
1375 List
<TypeParameterSpec
> merged_tparams
= null;
1377 var type
= DeclaringType
;
1380 if (type
.TypeArguments
.Length
> 0) {
1381 if (merged_targs
== null) {
1382 merged_targs
= new List
<TypeSpec
> ();
1383 merged_tparams
= new List
<TypeParameterSpec
> ();
1384 if (targs
.Length
> 0) {
1385 merged_targs
.AddRange (targs
);
1386 merged_tparams
.AddRange (open_type
.MemberDefinition
.TypeParameters
);
1389 merged_tparams
.AddRange (type
.MemberDefinition
.TypeParameters
);
1390 merged_targs
.AddRange (type
.TypeArguments
);
1392 type
= type
.DeclaringType
;
1393 } while (type
!= null);
1395 if (merged_targs
!= null) {
1396 // Type arguments are not in the right order but it should not matter in this case
1397 targs_full
= merged_targs
.ToArray ();
1398 tparams_full
= merged_tparams
.ToArray ();
1399 } else if (targs
.Length
== 0) {
1400 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1402 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1404 } else if (targs
.Length
== 0) {
1405 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1407 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1410 var inflator
= new TypeParameterInflator (this, tparams_full
, targs_full
);
1413 // Two stage inflate due to possible nested types recursive
1423 // When resolving type of `b' members of `B' cannot be
1424 // inflated because are not yet available in membercache
1426 if ((state
& StateFlags
.PendingMemberCacheMembers
) == 0) {
1427 open_type
.MemberCache
.InflateTypes (cache
, inflator
);
1430 // Inflate any implemented interfaces
1432 if (open_type
.Interfaces
!= null) {
1433 ifaces
= new List
<TypeSpec
> (open_type
.Interfaces
.Count
);
1434 foreach (var iface
in open_type
.Interfaces
) {
1435 var iface_inflated
= inflator
.Inflate (iface
);
1436 AddInterface (iface_inflated
);
1441 // Handles the tricky case of recursive nested base generic type
1443 // class A<T> : Base<A<T>.Nested> {
1447 // When inflating A<T>. base type is not yet known, secondary
1448 // inflation is required (not common case) once base scope
1451 if (open_type
.BaseType
== null) {
1453 state
|= StateFlags
.PendingBaseTypeInflate
;
1455 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1457 } else if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1458 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1459 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1463 state
|= StateFlags
.PendingMemberCacheMembers
;
1467 var tc
= open_type
.MemberDefinition
as TypeContainer
;
1468 if (tc
!= null && !tc
.HasMembersDefined
)
1469 throw new InternalErrorException ("Inflating MemberCache with undefined members");
1471 if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1472 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1473 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1476 state
&= ~StateFlags
.PendingMemberCacheMembers
;
1477 open_type
.MemberCache
.InflateMembers (cache
, open_type
, inflator
);
1480 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1482 var targs
= TypeArguments
;
1484 targs
= mutator
.Mutate (targs
);
1486 var decl
= DeclaringType
;
1487 if (IsNested
&& DeclaringType
.IsGenericOrParentIsGeneric
)
1488 decl
= mutator
.Mutate (decl
);
1490 if (targs
== TypeArguments
&& decl
== DeclaringType
)
1493 var mutated
= (InflatedTypeSpec
) MemberwiseClone ();
1494 if (decl
!= DeclaringType
) {
1495 // Gets back MethodInfo in case of metaInfo was inflated
1496 //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
1498 mutated
.declaringType
= decl
;
1499 mutated
.state
|= StateFlags
.PendingMetaInflate
;
1502 if (targs
!= null) {
1503 mutated
.targs
= targs
;
1504 mutated
.info
= null;
1513 // Tracks the type arguments when instantiating a generic type. It's used
1514 // by both type arguments and type parameters
1516 public class TypeArguments
1518 List
<FullNamedExpression
> args
;
1521 public TypeArguments (params FullNamedExpression
[] types
)
1523 this.args
= new List
<FullNamedExpression
> (types
);
1526 public void Add (FullNamedExpression type
)
1531 // TODO: Kill this monster
1532 public TypeParameterName
[] GetDeclarations ()
1534 return args
.ConvertAll (i
=> (TypeParameterName
) i
).ToArray ();
1538 /// We may only be used after Resolve() is called and return the fully
1541 // TODO: Not needed, just return type from resolve
1542 public TypeSpec
[] Arguments
{
1554 public virtual bool IsEmpty
{
1560 public string GetSignatureForError()
1562 StringBuilder sb
= new StringBuilder ();
1563 for (int i
= 0; i
< Count
; ++i
) {
1566 sb
.Append (expr
.GetSignatureForError ());
1572 return sb
.ToString ();
1576 /// Resolve the type arguments.
1578 public virtual bool Resolve (IMemberContext ec
)
1581 return atypes
.Length
!= 0;
1583 int count
= args
.Count
;
1586 atypes
= new TypeSpec
[count
];
1588 for (int i
= 0; i
< count
; i
++){
1589 TypeExpr te
= args
[i
].ResolveAsTypeTerminal (ec
, false);
1595 atypes
[i
] = te
.Type
;
1597 if (te
.Type
.IsStatic
) {
1598 ec
.Compiler
.Report
.Error (718, te
.Location
, "`{0}': static classes cannot be used as generic arguments",
1599 te
.GetSignatureForError ());
1603 if (te
.Type
.IsPointer
|| TypeManager
.IsSpecialType (te
.Type
)) {
1604 ec
.Compiler
.Report
.Error (306, te
.Location
,
1605 "The type `{0}' may not be used as a type argument",
1606 te
.GetSignatureForError ());
1612 atypes
= TypeSpec
.EmptyTypes
;
1617 public TypeArguments
Clone ()
1619 TypeArguments copy
= new TypeArguments ();
1620 foreach (var ta
in args
)
1627 public class UnboundTypeArguments
: TypeArguments
1629 public UnboundTypeArguments (int arity
)
1630 : base (new FullNamedExpression
[arity
])
1634 public override bool IsEmpty
{
1640 public override bool Resolve (IMemberContext ec
)
1642 // should not be called
1643 throw new NotSupportedException ();
1647 public class TypeParameterName
: SimpleName
1649 Attributes attributes
;
1652 public TypeParameterName (string name
, Attributes attrs
, Location loc
)
1653 : this (name
, attrs
, Variance
.None
, loc
)
1657 public TypeParameterName (string name
, Attributes attrs
, Variance variance
, Location loc
)
1661 this.variance
= variance
;
1664 public Attributes OptAttributes
{
1670 public Variance Variance
{
1678 // A type expression of generic type with type arguments
1680 class GenericTypeExpr
: TypeExpr
1684 bool constraints_checked
;
1687 /// Instantiate the generic type `t' with the type arguments `args'.
1688 /// Use this constructor if you already know the fully resolved
1691 public GenericTypeExpr (TypeSpec open_type
, TypeArguments args
, Location l
)
1693 this.open_type
= open_type
;
1698 public TypeArguments TypeArguments
{
1699 get { return args; }
1702 public override string GetSignatureForError ()
1704 return TypeManager
.CSharpName (type
);
1707 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1709 if (!args
.Resolve (ec
))
1712 TypeSpec
[] atypes
= args
.Arguments
;
1715 // Now bind the parameters
1717 type
= open_type
.MakeGenericType (atypes
);
1720 // Check constraints when context is not method/base type
1722 if (!ec
.HasUnresolvedConstraints
)
1723 CheckConstraints (ec
);
1729 // Checks the constraints of open generic type against type
1730 // arguments. Has to be called onafter all members are defined
1732 public bool CheckConstraints (IMemberContext ec
)
1734 if (constraints_checked
)
1737 constraints_checked
= true;
1739 var gtype
= (InflatedTypeSpec
) type
;
1740 var constraints
= gtype
.Constraints
;
1741 if (constraints
== null)
1744 return ConstraintChecker
.CheckAll (open_type
, args
.Arguments
, constraints
, loc
, ec
.Compiler
.Report
);
1747 public override bool CheckAccessLevel (IMemberContext mc
)
1749 DeclSpace c
= mc
.CurrentMemberDefinition
as DeclSpace
;
1751 c
= mc
.CurrentMemberDefinition
.Parent
;
1753 return c
.CheckAccessLevel (open_type
);
1756 public bool HasDynamicArguments ()
1758 return HasDynamicArguments (args
.Arguments
);
1761 static bool HasDynamicArguments (TypeSpec
[] args
)
1763 foreach (var item
in args
) {
1764 if (item
== InternalType
.Dynamic
)
1767 if (TypeManager
.IsGenericType (item
))
1768 return HasDynamicArguments (TypeManager
.GetTypeArguments (item
));
1774 public override bool Equals (object obj
)
1776 GenericTypeExpr cobj
= obj
as GenericTypeExpr
;
1780 if ((type
== null) || (cobj
.type
== null))
1783 return type
== cobj
.type
;
1786 public override int GetHashCode ()
1788 return base.GetHashCode ();
1792 static class ConstraintChecker
1795 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1796 /// after fully resolving the constructed type.
1798 public static bool CheckAll (MemberSpec context
, TypeSpec
[] targs
, TypeParameterSpec
[] tparams
, Location loc
, Report report
)
1800 for (int i
= 0; i
< tparams
.Length
; i
++) {
1801 if (!CheckConstraint (context
, targs
[i
], tparams
[i
], loc
, report
))
1808 static bool CheckConstraint (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, Location loc
, Report report
)
1811 // First, check the `class' and `struct' constraints.
1813 if (tparam
.HasSpecialClass
&& !TypeManager
.IsReferenceType (atype
)) {
1814 report
.Error (452, loc
,
1815 "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
1816 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1820 if (tparam
.HasSpecialStruct
&& (!TypeManager
.IsValueType (atype
) || TypeManager
.IsNullableType (atype
))) {
1821 report
.Error (453, loc
,
1822 "The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
1823 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1828 // The class constraint comes next.
1830 if (tparam
.HasTypeConstraint
) {
1831 CheckConversion (context
, atype
, tparam
, tparam
.BaseType
, loc
, report
);
1835 // Now, check the interfaces and type parameters constraints
1837 if (tparam
.Interfaces
!= null) {
1838 if (TypeManager
.IsNullableType (atype
)) {
1839 report
.Error (313, loc
,
1840 "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint",
1841 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1843 foreach (TypeSpec iface
in tparam
.Interfaces
) {
1844 CheckConversion (context
, atype
, tparam
, iface
, loc
, report
);
1850 // Finally, check the constructor constraint.
1852 if (!tparam
.HasSpecialConstructor
)
1855 if (!HasDefaultConstructor (atype
)) {
1856 report
.SymbolRelatedToPreviousError (atype
);
1857 report
.Error (310, loc
,
1858 "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
1859 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1866 static void CheckConversion (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, TypeSpec ttype
, Location loc
, Report report
)
1868 var expr
= new EmptyExpression (atype
);
1869 if (!Convert
.ImplicitStandardConversionExists (expr
, ttype
)) {
1870 report
.SymbolRelatedToPreviousError (tparam
);
1871 if (TypeManager
.IsValueType (atype
)) {
1872 report
.Error (315, loc
, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'",
1873 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1874 } else if (atype
.IsGenericParameter
) {
1875 report
.Error (314, loc
, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'",
1876 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1878 report
.Error (311, loc
, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'",
1879 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1884 static bool HasDefaultConstructor (TypeSpec atype
)
1886 var tp
= atype
as TypeParameterSpec
;
1888 return tp
.HasSpecialConstructor
|| tp
.HasSpecialStruct
;
1891 if (atype
.IsStruct
|| atype
.IsEnum
)
1894 if (atype
.IsAbstract
)
1897 var tdef
= atype
.GetDefinition ();
1900 // In some circumstances MemberCache is not yet populated and members
1901 // cannot be defined yet (recursive type new constraints)
1903 // class A<T> where T : B<T>, new () {}
1904 // class B<T> where T : A<T>, new () {}
1906 var tc
= tdef
.MemberDefinition
as Class
;
1908 if (tc
.InstanceConstructors
== null) {
1909 // Default ctor will be generated later
1913 foreach (var c
in tc
.InstanceConstructors
) {
1914 if (c
.ParameterInfo
.IsEmpty
) {
1915 if ((c
.ModFlags
& Modifiers
.PUBLIC
) != 0)
1923 var found
= MemberCache
.FindMember (tdef
,
1924 MemberFilter
.Constructor (ParametersCompiled
.EmptyReadOnlyParameters
),
1925 BindingRestriction
.DeclaredOnly
| BindingRestriction
.InstanceOnly
);
1927 return found
!= null && (found
.Modifiers
& Modifiers
.PUBLIC
) != 0;
1932 /// A generic method definition.
1934 public class GenericMethod
: DeclSpace
1936 ParametersCompiled parameters
;
1938 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1939 FullNamedExpression return_type
, ParametersCompiled parameters
)
1940 : base (ns
, parent
, name
, null)
1942 this.parameters
= parameters
;
1945 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
, TypeParameter
[] tparams
,
1946 FullNamedExpression return_type
, ParametersCompiled parameters
)
1947 : this (ns
, parent
, name
, return_type
, parameters
)
1949 this.type_params
= tparams
;
1952 public override TypeParameter
[] CurrentTypeParameters
{
1954 return base.type_params
;
1958 public override TypeBuilder
DefineType ()
1960 throw new Exception ();
1963 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
1965 throw new NotSupportedException ();
1968 public override bool Define ()
1970 throw new NotSupportedException ();
1974 /// Define and resolve the type parameters.
1975 /// We're called from Method.Define().
1977 public bool Define (MethodOrOperator m
)
1979 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1980 string[] snames
= new string [names
.Length
];
1981 for (int i
= 0; i
< names
.Length
; i
++) {
1982 string type_argument_name
= names
[i
].Name
;
1983 int idx
= parameters
.GetParameterIndexByName (type_argument_name
);
1988 b
= new ToplevelBlock (Compiler
, Location
);
1990 b
.Error_AlreadyDeclaredTypeParameter (parameters
[i
].Location
,
1991 type_argument_name
, "method parameter");
1994 if (m
.Block
!= null) {
1995 var ikv
= m
.Block
.GetKnownVariable (type_argument_name
);
1997 ikv
.Block
.Error_AlreadyDeclaredTypeParameter (ikv
.Location
, type_argument_name
, "local variable");
2000 snames
[i
] = type_argument_name
;
2003 GenericTypeParameterBuilder
[] gen_params
= m
.MethodBuilder
.DefineGenericParameters (snames
);
2004 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
2005 TypeParameters
[i
].Define (gen_params
[i
], null);
2010 public void EmitAttributes ()
2012 if (OptAttributes
!= null)
2013 OptAttributes
.Emit ();
2016 public override string GetSignatureForError ()
2018 return base.GetSignatureForError () + parameters
.GetSignatureForError ();
2021 public override AttributeTargets AttributeTargets
{
2023 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
2027 public override string DocCommentHeader
{
2028 get { return "M:"; }
2031 public new void VerifyClsCompliance ()
2033 foreach (TypeParameter tp
in TypeParameters
) {
2034 tp
.VerifyClsCompliance ();
2039 public partial class TypeManager
2041 public static Variance
CheckTypeVariance (TypeSpec t
, Variance expected
, IMemberContext member
)
2043 var tp
= t
as TypeParameterSpec
;
2045 Variance v
= tp
.Variance
;
2046 if (expected
== Variance
.None
&& v
!= expected
||
2047 expected
== Variance
.Covariant
&& v
== Variance
.Contravariant
||
2048 expected
== Variance
.Contravariant
&& v
== Variance
.Covariant
) {
2049 ((TypeParameter
)tp
.MemberDefinition
).ErrorInvalidVariance (member
, expected
);
2055 if (t
.TypeArguments
.Length
> 0) {
2056 var targs_definition
= t
.MemberDefinition
.TypeParameters
;
2057 TypeSpec
[] targs
= GetTypeArguments (t
);
2058 for (int i
= 0; i
< targs
.Length
; ++i
) {
2059 Variance v
= targs_definition
[i
].Variance
;
2060 CheckTypeVariance (targs
[i
], (Variance
) ((int)v
* (int)expected
), member
);
2067 return CheckTypeVariance (GetElementType (t
), expected
, member
);
2069 return Variance
.None
;
2073 /// Type inference. Try to infer the type arguments from `method',
2074 /// which is invoked with the arguments `arguments'. This is used
2075 /// when resolving an Invocation or a DelegateInvocation and the user
2076 /// did not explicitly specify type arguments.
2078 public static int InferTypeArguments (ResolveContext ec
, Arguments arguments
, ref MethodSpec method
)
2080 ATypeInference ti
= ATypeInference
.CreateInstance (arguments
);
2081 TypeSpec
[] i_args
= ti
.InferMethodArguments (ec
, method
);
2083 return ti
.InferenceScore
;
2085 if (i_args
.Length
== 0)
2088 method
= method
.MakeGenericMethod (i_args
);
2093 abstract class ATypeInference
2095 protected readonly Arguments arguments
;
2096 protected readonly int arg_count
;
2098 protected ATypeInference (Arguments arguments
)
2100 this.arguments
= arguments
;
2101 if (arguments
!= null)
2102 arg_count
= arguments
.Count
;
2105 public static ATypeInference
CreateInstance (Arguments arguments
)
2107 return new TypeInference (arguments
);
2110 public virtual int InferenceScore
{
2112 return int.MaxValue
;
2116 public abstract TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
);
2120 // Implements C# type inference
2122 class TypeInference
: ATypeInference
2125 // Tracks successful rate of type inference
2127 int score
= int.MaxValue
;
2129 public TypeInference (Arguments arguments
)
2134 public override int InferenceScore
{
2140 public override TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
)
2142 var method_generic_args
= method
.GenericDefinition
.TypeParameters
;
2143 TypeInferenceContext context
= new TypeInferenceContext (method_generic_args
);
2144 if (!context
.UnfixedVariableExists
)
2145 return TypeSpec
.EmptyTypes
;
2147 AParametersCollection pd
= method
.Parameters
;
2148 if (!InferInPhases (ec
, context
, pd
))
2151 return context
.InferredTypeArguments
;
2155 // Implements method type arguments inference
2157 bool InferInPhases (ResolveContext ec
, TypeInferenceContext tic
, AParametersCollection methodParameters
)
2159 int params_arguments_start
;
2160 if (methodParameters
.HasParams
) {
2161 params_arguments_start
= methodParameters
.Count
- 1;
2163 params_arguments_start
= arg_count
;
2166 TypeSpec
[] ptypes
= methodParameters
.Types
;
2169 // The first inference phase
2171 TypeSpec method_parameter
= null;
2172 for (int i
= 0; i
< arg_count
; i
++) {
2173 Argument a
= arguments
[i
];
2177 if (i
< params_arguments_start
) {
2178 method_parameter
= methodParameters
.Types
[i
];
2179 } else if (i
== params_arguments_start
) {
2180 if (arg_count
== params_arguments_start
+ 1 && TypeManager
.HasElementType (a
.Type
))
2181 method_parameter
= methodParameters
.Types
[params_arguments_start
];
2183 method_parameter
= TypeManager
.GetElementType (methodParameters
.Types
[params_arguments_start
]);
2185 ptypes
= (TypeSpec
[]) ptypes
.Clone ();
2186 ptypes
[i
] = method_parameter
;
2190 // When a lambda expression, an anonymous method
2191 // is used an explicit argument type inference takes a place
2193 AnonymousMethodExpression am
= a
.Expr
as AnonymousMethodExpression
;
2195 if (am
.ExplicitTypeInference (ec
, tic
, method_parameter
))
2201 score
-= tic
.ExactInference (a
.Type
, method_parameter
);
2205 if (a
.Expr
.Type
== InternalType
.Null
)
2208 if (TypeManager
.IsValueType (method_parameter
)) {
2209 score
-= tic
.LowerBoundInference (a
.Type
, method_parameter
);
2214 // Otherwise an output type inference is made
2216 score
-= tic
.OutputTypeInference (ec
, a
.Expr
, method_parameter
);
2220 // Part of the second phase but because it happens only once
2221 // we don't need to call it in cycle
2223 bool fixed_any
= false;
2224 if (!tic
.FixIndependentTypeArguments (ec
, ptypes
, ref fixed_any
))
2227 return DoSecondPhase (ec
, tic
, ptypes
, !fixed_any
);
2230 bool DoSecondPhase (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec
[] methodParameters
, bool fixDependent
)
2232 bool fixed_any
= false;
2233 if (fixDependent
&& !tic
.FixDependentTypes (ec
, ref fixed_any
))
2236 // If no further unfixed type variables exist, type inference succeeds
2237 if (!tic
.UnfixedVariableExists
)
2240 if (!fixed_any
&& fixDependent
)
2243 // For all arguments where the corresponding argument output types
2244 // contain unfixed type variables but the input types do not,
2245 // an output type inference is made
2246 for (int i
= 0; i
< arg_count
; i
++) {
2248 // Align params arguments
2249 TypeSpec t_i
= methodParameters
[i
>= methodParameters
.Length
? methodParameters
.Length
- 1: i
];
2251 if (!TypeManager
.IsDelegateType (t_i
)) {
2252 if (t_i
.GetDefinition () != TypeManager
.expression_type
)
2255 t_i
= TypeManager
.GetTypeArguments (t_i
) [0];
2258 var mi
= Delegate
.GetInvokeMethod (ec
.Compiler
, t_i
);
2259 TypeSpec rtype
= mi
.ReturnType
;
2261 if (tic
.IsReturnTypeNonDependent (ec
, mi
, rtype
))
2262 score
-= tic
.OutputTypeInference (ec
, arguments
[i
].Expr
, t_i
);
2266 return DoSecondPhase (ec
, tic
, methodParameters
, true);
2270 public class TypeInferenceContext
2281 public readonly TypeSpec Type
;
2282 public readonly BoundKind Kind
;
2284 public BoundInfo (TypeSpec type
, BoundKind kind
)
2290 public override int GetHashCode ()
2292 return Type
.GetHashCode ();
2295 public override bool Equals (object obj
)
2297 BoundInfo a
= (BoundInfo
) obj
;
2298 return Type
== a
.Type
&& Kind
== a
.Kind
;
2302 readonly TypeSpec
[] unfixed_types
;
2303 readonly TypeSpec
[] fixed_types
;
2304 readonly List
<BoundInfo
>[] bounds
;
2307 // TODO MemberCache: Could it be TypeParameterSpec[] ??
2308 public TypeInferenceContext (TypeSpec
[] typeArguments
)
2310 if (typeArguments
.Length
== 0)
2311 throw new ArgumentException ("Empty generic arguments");
2313 fixed_types
= new TypeSpec
[typeArguments
.Length
];
2314 for (int i
= 0; i
< typeArguments
.Length
; ++i
) {
2315 if (typeArguments
[i
].IsGenericParameter
) {
2316 if (bounds
== null) {
2317 bounds
= new List
<BoundInfo
> [typeArguments
.Length
];
2318 unfixed_types
= new TypeSpec
[typeArguments
.Length
];
2320 unfixed_types
[i
] = typeArguments
[i
];
2322 fixed_types
[i
] = typeArguments
[i
];
2328 // Used together with AddCommonTypeBound fo implement
2329 // 7.4.2.13 Finding the best common type of a set of expressions
2331 public TypeInferenceContext ()
2333 fixed_types
= new TypeSpec
[1];
2334 unfixed_types
= new TypeSpec
[1];
2335 unfixed_types
[0] = InternalType
.Arglist
; // it can be any internal type
2336 bounds
= new List
<BoundInfo
> [1];
2339 public TypeSpec
[] InferredTypeArguments
{
2345 public void AddCommonTypeBound (TypeSpec type
)
2347 AddToBounds (new BoundInfo (type
, BoundKind
.Lower
), 0);
2350 void AddToBounds (BoundInfo bound
, int index
)
2353 // Some types cannot be used as type arguments
2355 if (bound
.Type
== TypeManager
.void_type
|| bound
.Type
.IsPointer
)
2358 var a
= bounds
[index
];
2360 a
= new List
<BoundInfo
> ();
2363 if (a
.Contains (bound
))
2368 // SPEC: does not cover type inference using constraints
2370 //if (TypeManager.IsGenericParameter (t)) {
2371 // GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
2372 // if (constraints != null) {
2373 // //if (constraints.EffectiveBaseClass != null)
2374 // // t = constraints.EffectiveBaseClass;
2380 bool AllTypesAreFixed (TypeSpec
[] types
)
2382 foreach (TypeSpec t
in types
) {
2383 if (t
.IsGenericParameter
) {
2389 if (TypeManager
.IsGenericType (t
))
2390 return AllTypesAreFixed (TypeManager
.GetTypeArguments (t
));
2397 // 26.3.3.8 Exact Inference
2399 public int ExactInference (TypeSpec u
, TypeSpec v
)
2401 // If V is an array type
2406 // TODO MemberCache: GetMetaInfo ()
2407 if (u
.GetMetaInfo ().GetArrayRank () != v
.GetMetaInfo ().GetArrayRank ())
2410 return ExactInference (TypeManager
.GetElementType (u
), TypeManager
.GetElementType (v
));
2413 // If V is constructed type and U is constructed type
2414 if (TypeManager
.IsGenericType (v
)) {
2415 if (!TypeManager
.IsGenericType (u
))
2418 TypeSpec
[] ga_u
= TypeManager
.GetTypeArguments (u
);
2419 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2420 if (ga_u
.Length
!= ga_v
.Length
)
2424 for (int i
= 0; i
< ga_u
.Length
; ++i
)
2425 score
+= ExactInference (ga_u
[i
], ga_v
[i
]);
2427 return score
> 0 ? 1 : 0;
2430 // If V is one of the unfixed type arguments
2431 int pos
= IsUnfixed (v
);
2435 AddToBounds (new BoundInfo (u
, BoundKind
.Exact
), pos
);
2439 public bool FixAllTypes (ResolveContext ec
)
2441 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2442 if (!FixType (ec
, i
))
2449 // All unfixed type variables Xi are fixed for which all of the following hold:
2450 // a, There is at least one type variable Xj that depends on Xi
2451 // b, Xi has a non-empty set of bounds
2453 public bool FixDependentTypes (ResolveContext ec
, ref bool fixed_any
)
2455 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2456 if (unfixed_types
[i
] == null)
2459 if (bounds
[i
] == null)
2462 if (!FixType (ec
, i
))
2472 // All unfixed type variables Xi which depend on no Xj are fixed
2474 public bool FixIndependentTypeArguments (ResolveContext ec
, TypeSpec
[] methodParameters
, ref bool fixed_any
)
2476 var types_to_fix
= new List
<TypeSpec
> (unfixed_types
);
2477 for (int i
= 0; i
< methodParameters
.Length
; ++i
) {
2478 TypeSpec t
= methodParameters
[i
];
2480 if (!TypeManager
.IsDelegateType (t
)) {
2481 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2484 t
= TypeManager
.GetTypeArguments (t
) [0];
2487 if (t
.IsGenericParameter
)
2490 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2491 TypeSpec rtype
= invoke
.ReturnType
;
2492 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2495 // Remove dependent types, they cannot be fixed yet
2496 RemoveDependentTypes (types_to_fix
, rtype
);
2499 foreach (TypeSpec t
in types_to_fix
) {
2503 int idx
= IsUnfixed (t
);
2504 if (idx
>= 0 && !FixType (ec
, idx
)) {
2509 fixed_any
= types_to_fix
.Count
> 0;
2516 public bool FixType (ResolveContext ec
, int i
)
2518 // It's already fixed
2519 if (unfixed_types
[i
] == null)
2520 throw new InternalErrorException ("Type argument has been already fixed");
2525 var candidates
= bounds
[i
];
2526 if (candidates
== null)
2529 if (candidates
.Count
== 1) {
2530 unfixed_types
[i
] = null;
2531 TypeSpec t
= candidates
[0].Type
;
2532 if (t
== InternalType
.Null
)
2535 fixed_types
[i
] = t
;
2540 // Determines a unique type from which there is
2541 // a standard implicit conversion to all the other
2544 TypeSpec best_candidate
= null;
2546 int candidates_count
= candidates
.Count
;
2547 for (int ci
= 0; ci
< candidates_count
; ++ci
) {
2548 BoundInfo bound
= candidates
[ci
];
2549 for (cii
= 0; cii
< candidates_count
; ++cii
) {
2553 BoundInfo cbound
= candidates
[cii
];
2555 // Same type parameters with different bounds
2556 if (cbound
.Type
== bound
.Type
) {
2557 if (bound
.Kind
!= BoundKind
.Exact
)
2563 if (bound
.Kind
== BoundKind
.Exact
|| cbound
.Kind
== BoundKind
.Exact
) {
2564 if (cbound
.Kind
!= BoundKind
.Exact
) {
2565 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2572 if (bound
.Kind
!= BoundKind
.Exact
) {
2573 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2584 if (bound
.Kind
== BoundKind
.Lower
) {
2585 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2589 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2595 if (cii
!= candidates_count
)
2598 if (best_candidate
!= null && best_candidate
!= bound
.Type
)
2601 best_candidate
= bound
.Type
;
2604 if (best_candidate
== null)
2607 unfixed_types
[i
] = null;
2608 fixed_types
[i
] = best_candidate
;
2613 // Uses inferred or partially infered types to inflate delegate type argument. Returns
2614 // null when type parameter was not yet inferres
2616 public TypeSpec
InflateGenericArgument (TypeSpec parameter
)
2618 var tp
= parameter
as TypeParameterSpec
;
2621 // Type inference work on generic arguments (MVAR) only
2623 if (!tp
.IsMethodOwned
)
2626 return fixed_types
[tp
.DeclaredPosition
] ?? parameter
;
2629 var gt
= parameter
as InflatedTypeSpec
;
2631 var inflated_targs
= new TypeSpec
[gt
.TypeArguments
.Length
];
2632 for (int ii
= 0; ii
< inflated_targs
.Length
; ++ii
) {
2633 var inflated
= InflateGenericArgument (gt
.TypeArguments
[ii
]);
2634 if (inflated
== null)
2637 inflated_targs
[ii
] = inflated
;
2640 return gt
.GetDefinition ().MakeGenericType (inflated_targs
);
2647 // Tests whether all delegate input arguments are fixed and generic output type
2648 // requires output type inference
2650 public bool IsReturnTypeNonDependent (ResolveContext ec
, MethodSpec invoke
, TypeSpec returnType
)
2652 if (returnType
.IsGenericParameter
) {
2653 if (IsFixed (returnType
))
2655 } else if (TypeManager
.IsGenericType (returnType
)) {
2656 if (TypeManager
.IsDelegateType (returnType
)) {
2657 invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, returnType
);
2658 return IsReturnTypeNonDependent (ec
, invoke
, invoke
.ReturnType
);
2661 TypeSpec
[] g_args
= TypeManager
.GetTypeArguments (returnType
);
2663 // At least one unfixed return type has to exist
2664 if (AllTypesAreFixed (g_args
))
2670 // All generic input arguments have to be fixed
2671 AParametersCollection d_parameters
= invoke
.Parameters
;
2672 return AllTypesAreFixed (d_parameters
.Types
);
2675 bool IsFixed (TypeSpec type
)
2677 return IsUnfixed (type
) == -1;
2680 int IsUnfixed (TypeSpec type
)
2682 if (!type
.IsGenericParameter
)
2685 //return unfixed_types[type.GenericParameterPosition] != null;
2686 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2687 if (unfixed_types
[i
] == type
)
2695 // 26.3.3.9 Lower-bound Inference
2697 public int LowerBoundInference (TypeSpec u
, TypeSpec v
)
2699 return LowerBoundInference (u
, v
, false);
2703 // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
2705 int LowerBoundInference (TypeSpec u
, TypeSpec v
, bool inversed
)
2707 // If V is one of the unfixed type arguments
2708 int pos
= IsUnfixed (v
);
2710 AddToBounds (new BoundInfo (u
, inversed
? BoundKind
.Upper
: BoundKind
.Lower
), pos
);
2714 // If U is an array type
2715 var u_ac
= u
as ArrayContainer
;
2717 var v_ac
= v
as ArrayContainer
;
2719 if (u_ac
.Rank
!= v_ac
.Rank
)
2722 if (TypeManager
.IsValueType (u_ac
.Element
))
2723 return ExactInference (u_ac
.Element
, v_ac
.Element
);
2725 return LowerBoundInference (u_ac
.Element
, v_ac
.Element
, inversed
);
2731 if (TypeManager
.IsGenericType (v
)) {
2732 TypeSpec g_v
= v
.GetDefinition ();
2733 if (g_v
!= TypeManager
.generic_ilist_type
&&
2734 g_v
!= TypeManager
.generic_icollection_type
&&
2735 g_v
!= TypeManager
.generic_ienumerable_type
)
2738 var v_i
= TypeManager
.GetTypeArguments (v
) [0];
2739 if (TypeManager
.IsValueType (u_ac
.Element
))
2740 return ExactInference (u_ac
.Element
, v_i
);
2742 return LowerBoundInference (u_ac
.Element
, v_i
);
2744 } else if (TypeManager
.IsGenericType (v
)) {
2746 // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
2747 // such that U is identical to, inherits from (directly or indirectly),
2748 // or implements (directly or indirectly) C<U1..Uk>
2750 var u_candidates
= new List
<TypeSpec
> ();
2751 var open_v
= v
.MemberDefinition
;
2753 for (TypeSpec t
= u
; t
!= null; t
= t
.BaseType
) {
2754 if (open_v
== t
.MemberDefinition
)
2755 u_candidates
.Add (t
);
2757 if (t
.Interfaces
!= null) {
2758 foreach (var iface
in t
.Interfaces
) {
2759 if (open_v
== iface
.MemberDefinition
)
2760 u_candidates
.Add (iface
);
2765 TypeSpec
[] unique_candidate_targs
= null;
2766 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2767 foreach (TypeSpec u_candidate
in u_candidates
) {
2769 // The unique set of types U1..Uk means that if we have an interface I<T>,
2770 // class U : I<int>, I<long> then no type inference is made when inferring
2771 // type I<T> by applying type U because T could be int or long
2773 if (unique_candidate_targs
!= null) {
2774 TypeSpec
[] second_unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2775 if (TypeSpecComparer
.Default
.Equals (unique_candidate_targs
, second_unique_candidate_targs
)) {
2776 unique_candidate_targs
= second_unique_candidate_targs
;
2781 // This should always cause type inference failure
2787 unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2790 if (unique_candidate_targs
!= null) {
2791 var ga_open_v
= open_v
.TypeParameters
;
2793 for (int i
= 0; i
< unique_candidate_targs
.Length
; ++i
) {
2794 Variance variance
= ga_open_v
[i
].Variance
;
2796 TypeSpec u_i
= unique_candidate_targs
[i
];
2797 if (variance
== Variance
.None
|| TypeManager
.IsValueType (u_i
)) {
2798 if (ExactInference (u_i
, ga_v
[i
]) == 0)
2801 bool upper_bound
= (variance
== Variance
.Contravariant
&& !inversed
) ||
2802 (variance
== Variance
.Covariant
&& inversed
);
2804 if (LowerBoundInference (u_i
, ga_v
[i
], upper_bound
) == 0)
2816 // 26.3.3.6 Output Type Inference
2818 public int OutputTypeInference (ResolveContext ec
, Expression e
, TypeSpec t
)
2820 // If e is a lambda or anonymous method with inferred return type
2821 AnonymousMethodExpression ame
= e
as AnonymousMethodExpression
;
2823 TypeSpec rt
= ame
.InferReturnType (ec
, this, t
);
2824 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2827 AParametersCollection pd
= invoke
.Parameters
;
2828 return ame
.Parameters
.Count
== pd
.Count
? 1 : 0;
2831 TypeSpec rtype
= invoke
.ReturnType
;
2832 return LowerBoundInference (rt
, rtype
) + 1;
2836 // if E is a method group and T is a delegate type or expression tree type
2837 // return type Tb with parameter types T1..Tk and return type Tb, and overload
2838 // resolution of E with the types T1..Tk yields a single method with return type U,
2839 // then a lower-bound inference is made from U for Tb.
2841 if (e
is MethodGroupExpr
) {
2842 if (!TypeManager
.IsDelegateType (t
)) {
2843 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2846 t
= TypeManager
.GetTypeArguments (t
)[0];
2849 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2850 TypeSpec rtype
= invoke
.ReturnType
;
2852 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2855 // LAMESPEC: Standard does not specify that all methodgroup arguments
2856 // has to be fixed but it does not specify how to do recursive type inference
2857 // either. We choose the simple option and infer return type only
2858 // if all delegate generic arguments are fixed.
2859 TypeSpec
[] param_types
= new TypeSpec
[invoke
.Parameters
.Count
];
2860 for (int i
= 0; i
< param_types
.Length
; ++i
) {
2861 var inflated
= InflateGenericArgument (invoke
.Parameters
.Types
[i
]);
2862 if (inflated
== null)
2865 param_types
[i
] = inflated
;
2868 MethodGroupExpr mg
= (MethodGroupExpr
) e
;
2869 Arguments args
= DelegateCreation
.CreateDelegateMethodArguments (invoke
.Parameters
, param_types
, e
.Location
);
2870 mg
= mg
.OverloadResolve (ec
, ref args
, true, e
.Location
);
2874 return LowerBoundInference (mg
.BestCandidate
.ReturnType
, rtype
) + 1;
2878 // if e is an expression with type U, then
2879 // a lower-bound inference is made from U for T
2881 return LowerBoundInference (e
.Type
, t
) * 2;
2884 void RemoveDependentTypes (List
<TypeSpec
> types
, TypeSpec returnType
)
2886 int idx
= IsUnfixed (returnType
);
2892 if (TypeManager
.IsGenericType (returnType
)) {
2893 foreach (TypeSpec t
in TypeManager
.GetTypeArguments (returnType
)) {
2894 RemoveDependentTypes (types
, t
);
2899 public bool UnfixedVariableExists
{
2901 if (unfixed_types
== null)
2904 foreach (TypeSpec ut
in unfixed_types
)