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 (!TypeSpecComparer
.Override
.IsEqual (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 void InflateConstraints (TypeParameterInflator inflator
, TypeParameterSpec tps
)
948 tps
.BaseType
= inflator
.Inflate (BaseType
);
949 if (ifaces
!= null) {
950 tps
.ifaces
= new List
<TypeSpec
> (ifaces
.Count
);
951 for (int i
= 0; i
< ifaces
.Count
; ++i
)
952 tps
.ifaces
.Add (inflator
.Inflate (ifaces
[i
]));
955 tps
.targs
= new TypeSpec
[targs
.Length
];
956 for (int i
= 0; i
< targs
.Length
; ++i
)
957 tps
.targs
[i
] = inflator
.Inflate (targs
[i
]);
961 public override MemberSpec
InflateMember (TypeParameterInflator inflator
)
963 var tps
= (TypeParameterSpec
) MemberwiseClone ();
964 InflateConstraints (inflator
, tps
);
969 // Populates type parameter members using type parameter constraints
970 // The trick here is to be called late enough but not too late to
971 // populate member cache with all members from other types
973 protected override void InitializeMemberCache (bool onlyTypes
)
975 cache
= new MemberCache ();
976 if (ifaces
!= null) {
977 foreach (var iface_type
in Interfaces
) {
978 cache
.AddInterface (iface_type
);
983 public bool IsConvertibleToInterface (TypeSpec iface
)
985 if (Interfaces
!= null) {
986 foreach (var t
in Interfaces
) {
992 if (TypeArguments
!= null) {
993 foreach (var t
in TypeArguments
) {
994 if (((TypeParameterSpec
) t
).IsConvertibleToInterface (iface
))
1002 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1004 return mutator
.Mutate (this);
1008 public struct TypeParameterInflator
1010 readonly TypeSpec type
;
1011 readonly TypeParameterSpec
[] tparams
;
1012 readonly TypeSpec
[] targs
;
1014 public TypeParameterInflator (TypeParameterInflator nested
, TypeSpec type
)
1015 : this (type
, nested
.tparams
, nested
.targs
)
1019 public TypeParameterInflator (TypeSpec type
, TypeParameterSpec
[] tparams
, TypeSpec
[] targs
)
1021 if (tparams
.Length
!= targs
.Length
)
1022 throw new ArgumentException ("Invalid arguments");
1024 this.tparams
= tparams
;
1030 // Type parameters to inflate
1032 public TypeParameterSpec
[] TypeParameters
{
1038 public TypeSpec
Inflate (TypeSpec ts
)
1040 var tp
= ts
as TypeParameterSpec
;
1042 return Inflate (tp
);
1044 var ac
= ts
as ArrayContainer
;
1046 var et
= Inflate (ac
.Element
);
1047 if (et
!= ac
.Element
)
1048 return ArrayContainer
.MakeType (et
, ac
.Rank
);
1054 // When inflating a nested type, inflate its parent first
1055 // in case it's using same type parameters (was inflated within the type)
1058 var parent
= Inflate (ts
.DeclaringType
);
1059 if (ts
.DeclaringType
!= parent
) {
1061 // Keep the inflated type arguments
1063 var targs
= ts
.TypeArguments
;
1066 // Parent was inflated, find the same type on inflated type
1067 // to use same cache for nested types on same generic parent
1069 // TODO: Should use BindingRestriction.DeclaredOnly or GetMember
1070 ts
= MemberCache
.FindNestedType (parent
, ts
.Name
, targs
.Length
);
1073 // Handle the tricky case where parent shares local type arguments
1074 // which means inflating inflated type
1077 // public static Nested<T> Foo () { return null; }
1079 // public class Nested<U> {}
1082 // return type of Test<string>.Foo() has to be Test<string>.Nested<string>
1084 if (targs
.Length
> 0) {
1085 var inflated_targs
= new TypeSpec
[targs
.Length
];
1086 for (var i
= 0; i
< targs
.Length
; ++i
)
1087 inflated_targs
[i
] = Inflate (targs
[i
]);
1089 ts
= ts
.MakeGenericType (inflated_targs
);
1096 // Inflate generic type
1098 return InflateTypeParameters (ts
);
1103 public TypeSpec
Inflate (TypeParameterSpec tp
)
1105 for (int i
= 0; i
< tparams
.Length
; ++i
)
1106 if (tparams
[i
] == tp
)
1109 // This can happen when inflating nested types
1110 // without type arguments specified
1115 // Inflates generic types
1117 TypeSpec
InflateTypeParameters (TypeSpec type
)
1119 var targs
= new TypeSpec
[type
.Arity
];
1122 var gti
= type
as InflatedTypeSpec
;
1125 // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {}
1128 for (; i
< targs
.Length
; ++i
)
1129 targs
[i
] = Inflate (gti
.TypeArguments
[i
]);
1131 return gti
.GetDefinition ().MakeGenericType (targs
);
1135 // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; }
1137 var args
= type
.MemberDefinition
.TypeParameters
;
1138 foreach (var ds_tp
in args
)
1139 targs
[i
++] = Inflate (ds_tp
);
1141 return type
.MakeGenericType (targs
);
1144 public TypeSpec TypeInstance
{
1145 get { return type; }
1150 // Before emitting any code we have to change all MVAR references to VAR
1151 // when the method is of generic type and has hoisted variables
1153 public class TypeParameterMutator
1155 TypeParameter
[] mvar
;
1156 TypeParameter
[] var;
1157 Dictionary
<TypeSpec
, TypeSpec
> mutated_typespec
= new Dictionary
<TypeSpec
, TypeSpec
> ();
1159 public TypeParameterMutator (TypeParameter
[] mvar
, TypeParameter
[] var)
1161 if (mvar
.Length
!= var.Length
)
1162 throw new ArgumentException ();
1168 public TypeSpec
Mutate (TypeSpec ts
)
1171 if (mutated_typespec
.TryGetValue (ts
, out value))
1174 value = ts
.Mutate (this);
1175 mutated_typespec
.Add (ts
, value);
1179 public FieldInfo
Mutate (FieldSpec fs
)
1182 return fs
.GetMetaInfo ();
1185 public TypeParameterSpec
Mutate (TypeParameterSpec tp
)
1187 for (int i
= 0; i
< mvar
.Length
; ++i
) {
1188 if (mvar
[i
].Type
== tp
)
1195 public TypeSpec
[] Mutate (TypeSpec
[] targs
)
1197 TypeSpec
[] mutated
= new TypeSpec
[targs
.Length
];
1198 bool changed
= false;
1199 for (int i
= 0; i
< targs
.Length
; ++i
) {
1200 mutated
[i
] = Mutate (targs
[i
]);
1201 changed
|= targs
[i
] != mutated
[i
];
1204 return changed
? mutated
: targs
;
1209 /// A TypeExpr which already resolved to a type parameter.
1211 public class TypeParameterExpr
: TypeExpr
{
1213 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1215 this.type
= type_parameter
.Type
;
1216 this.eclass
= ExprClass
.TypeParameter
;
1220 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1222 throw new NotSupportedException ();
1225 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
1230 public override bool CheckAccessLevel (IMemberContext ds
)
1236 public class InflatedTypeSpec
: TypeSpec
1239 TypeParameterSpec
[] constraints
;
1240 readonly TypeSpec open_type
;
1242 public InflatedTypeSpec (TypeSpec openType
, TypeSpec declaringType
, TypeSpec
[] targs
)
1243 : base (openType
.Kind
, declaringType
, openType
.MemberDefinition
, null, openType
.Modifiers
)
1246 throw new ArgumentNullException ("targs");
1248 // this.state = openType.state;
1249 this.open_type
= openType
;
1255 public override TypeSpec BaseType
{
1257 if (cache
== null || (state
& StateFlags
.PendingBaseTypeInflate
) != 0)
1258 InitializeMemberCache (true);
1260 return base.BaseType
;
1265 // Inflated type parameters with constraints array, mapping with type arguments is based on index
1267 public TypeParameterSpec
[] Constraints
{
1269 if (constraints
== null) {
1270 var inflator
= new TypeParameterInflator (this, MemberDefinition
.TypeParameters
, targs
);
1271 constraints
= TypeParameterSpec
.InflateConstraints (inflator
, MemberDefinition
.TypeParameters
);
1278 public override IList
<TypeSpec
> Interfaces
{
1281 InitializeMemberCache (true);
1283 return base.Interfaces
;
1287 public override MemberCache MemberCacheTypes
{
1290 InitializeMemberCache (true);
1297 // Types used to inflate the generic type
1299 public override TypeSpec
[] TypeArguments
{
1307 Type
CreateMetaInfo (TypeParameterMutator mutator
)
1310 // Converts nested type arguments into right order
1311 // Foo<string, bool>.Bar<int> => string, bool, int
1313 var all
= new List
<Type
> ();
1314 TypeSpec type
= this;
1315 TypeSpec definition
= type
;
1317 if (type
.GetDefinition().IsGeneric
) {
1319 type
.TypeArguments
!= TypeSpec
.EmptyTypes
?
1320 type
.TypeArguments
.Select (l
=> l
.GetMetaInfo ()) :
1321 type
.MemberDefinition
.TypeParameters
.Select (l
=> l
.GetMetaInfo ()));
1324 definition
= definition
.GetDefinition ();
1325 type
= type
.DeclaringType
;
1326 } while (type
!= null);
1328 return definition
.GetMetaInfo ().MakeGenericType (all
.ToArray ());
1331 public override ObsoleteAttribute
GetAttributeObsolete ()
1333 return open_type
.GetAttributeObsolete ();
1336 protected override bool IsNotCLSCompliant ()
1338 if (base.IsNotCLSCompliant ())
1341 foreach (var ta
in TypeArguments
) {
1342 if (ta
.MemberDefinition
.IsNotCLSCompliant ())
1349 public override TypeSpec
GetDefinition ()
1354 public override Type
GetMetaInfo ()
1357 info
= CreateMetaInfo (null);
1362 public override string GetSignatureForError ()
1364 if (TypeManager
.IsNullableType (open_type
))
1365 return targs
[0].GetSignatureForError () + "?";
1367 if (MemberDefinition
is AnonymousTypeClass
)
1368 return ((AnonymousTypeClass
) MemberDefinition
).GetSignatureForError ();
1370 return base.GetSignatureForError ();
1373 protected override string GetTypeNameSignature ()
1375 if (targs
.Length
== 0 || MemberDefinition
is AnonymousTypeClass
)
1378 return "<" + TypeManager
.CSharpName (targs
) + ">";
1381 protected override void InitializeMemberCache (bool onlyTypes
)
1384 cache
= new MemberCache (onlyTypes
? open_type
.MemberCacheTypes
: open_type
.MemberCache
);
1386 TypeParameterSpec
[] tparams_full
;
1387 TypeSpec
[] targs_full
= targs
;
1390 // Special case is needed when we are inflating an open type (nested type definition)
1391 // on inflated parent. Consider following case
1393 // Foo<T>.Bar<U> => Foo<string>.Bar<U>
1395 // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U>
1397 List
<TypeSpec
> merged_targs
= null;
1398 List
<TypeParameterSpec
> merged_tparams
= null;
1400 var type
= DeclaringType
;
1403 if (type
.TypeArguments
.Length
> 0) {
1404 if (merged_targs
== null) {
1405 merged_targs
= new List
<TypeSpec
> ();
1406 merged_tparams
= new List
<TypeParameterSpec
> ();
1407 if (targs
.Length
> 0) {
1408 merged_targs
.AddRange (targs
);
1409 merged_tparams
.AddRange (open_type
.MemberDefinition
.TypeParameters
);
1412 merged_tparams
.AddRange (type
.MemberDefinition
.TypeParameters
);
1413 merged_targs
.AddRange (type
.TypeArguments
);
1415 type
= type
.DeclaringType
;
1416 } while (type
!= null);
1418 if (merged_targs
!= null) {
1419 // Type arguments are not in the right order but it should not matter in this case
1420 targs_full
= merged_targs
.ToArray ();
1421 tparams_full
= merged_tparams
.ToArray ();
1422 } else if (targs
.Length
== 0) {
1423 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1425 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1427 } else if (targs
.Length
== 0) {
1428 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1430 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1433 var inflator
= new TypeParameterInflator (this, tparams_full
, targs_full
);
1436 // Two stage inflate due to possible nested types recursive
1446 // When resolving type of `b' members of `B' cannot be
1447 // inflated because are not yet available in membercache
1449 if ((state
& StateFlags
.PendingMemberCacheMembers
) == 0) {
1450 open_type
.MemberCacheTypes
.InflateTypes (cache
, inflator
);
1453 // Inflate any implemented interfaces
1455 if (open_type
.Interfaces
!= null) {
1456 ifaces
= new List
<TypeSpec
> (open_type
.Interfaces
.Count
);
1457 foreach (var iface
in open_type
.Interfaces
) {
1458 var iface_inflated
= inflator
.Inflate (iface
);
1459 AddInterface (iface_inflated
);
1464 // Handles the tricky case of recursive nested base generic type
1466 // class A<T> : Base<A<T>.Nested> {
1470 // When inflating A<T>. base type is not yet known, secondary
1471 // inflation is required (not common case) once base scope
1474 if (open_type
.BaseType
== null) {
1476 state
|= StateFlags
.PendingBaseTypeInflate
;
1478 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1480 } else if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1481 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1482 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1486 state
|= StateFlags
.PendingMemberCacheMembers
;
1490 var tc
= open_type
.MemberDefinition
as TypeContainer
;
1491 if (tc
!= null && !tc
.HasMembersDefined
)
1492 throw new InternalErrorException ("Inflating MemberCache with undefined members");
1494 if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1495 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1496 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1499 state
&= ~StateFlags
.PendingMemberCacheMembers
;
1500 open_type
.MemberCache
.InflateMembers (cache
, open_type
, inflator
);
1503 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1505 var targs
= TypeArguments
;
1507 targs
= mutator
.Mutate (targs
);
1509 var decl
= DeclaringType
;
1510 if (IsNested
&& DeclaringType
.IsGenericOrParentIsGeneric
)
1511 decl
= mutator
.Mutate (decl
);
1513 if (targs
== TypeArguments
&& decl
== DeclaringType
)
1516 var mutated
= (InflatedTypeSpec
) MemberwiseClone ();
1517 if (decl
!= DeclaringType
) {
1518 // Gets back MethodInfo in case of metaInfo was inflated
1519 //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
1521 mutated
.declaringType
= decl
;
1522 mutated
.state
|= StateFlags
.PendingMetaInflate
;
1525 if (targs
!= null) {
1526 mutated
.targs
= targs
;
1527 mutated
.info
= null;
1536 // Tracks the type arguments when instantiating a generic type. It's used
1537 // by both type arguments and type parameters
1539 public class TypeArguments
1541 List
<FullNamedExpression
> args
;
1544 public TypeArguments (params FullNamedExpression
[] types
)
1546 this.args
= new List
<FullNamedExpression
> (types
);
1549 public void Add (FullNamedExpression type
)
1554 // TODO: Kill this monster
1555 public TypeParameterName
[] GetDeclarations ()
1557 return args
.ConvertAll (i
=> (TypeParameterName
) i
).ToArray ();
1561 /// We may only be used after Resolve() is called and return the fully
1564 // TODO: Not needed, just return type from resolve
1565 public TypeSpec
[] Arguments
{
1577 public virtual bool IsEmpty
{
1583 public string GetSignatureForError()
1585 StringBuilder sb
= new StringBuilder ();
1586 for (int i
= 0; i
< Count
; ++i
) {
1589 sb
.Append (expr
.GetSignatureForError ());
1595 return sb
.ToString ();
1599 /// Resolve the type arguments.
1601 public virtual bool Resolve (IMemberContext ec
)
1604 return atypes
.Length
!= 0;
1606 int count
= args
.Count
;
1609 atypes
= new TypeSpec
[count
];
1611 for (int i
= 0; i
< count
; i
++){
1612 TypeExpr te
= args
[i
].ResolveAsTypeTerminal (ec
, false);
1618 atypes
[i
] = te
.Type
;
1620 if (te
.Type
.IsStatic
) {
1621 ec
.Compiler
.Report
.Error (718, te
.Location
, "`{0}': static classes cannot be used as generic arguments",
1622 te
.GetSignatureForError ());
1626 if (te
.Type
.IsPointer
|| TypeManager
.IsSpecialType (te
.Type
)) {
1627 ec
.Compiler
.Report
.Error (306, te
.Location
,
1628 "The type `{0}' may not be used as a type argument",
1629 te
.GetSignatureForError ());
1635 atypes
= TypeSpec
.EmptyTypes
;
1640 public TypeArguments
Clone ()
1642 TypeArguments copy
= new TypeArguments ();
1643 foreach (var ta
in args
)
1650 public class UnboundTypeArguments
: TypeArguments
1652 public UnboundTypeArguments (int arity
)
1653 : base (new FullNamedExpression
[arity
])
1657 public override bool IsEmpty
{
1663 public override bool Resolve (IMemberContext ec
)
1665 // should not be called
1666 throw new NotSupportedException ();
1670 public class TypeParameterName
: SimpleName
1672 Attributes attributes
;
1675 public TypeParameterName (string name
, Attributes attrs
, Location loc
)
1676 : this (name
, attrs
, Variance
.None
, loc
)
1680 public TypeParameterName (string name
, Attributes attrs
, Variance variance
, Location loc
)
1684 this.variance
= variance
;
1687 public Attributes OptAttributes
{
1693 public Variance Variance
{
1701 // A type expression of generic type with type arguments
1703 class GenericTypeExpr
: TypeExpr
1707 bool constraints_checked
;
1710 /// Instantiate the generic type `t' with the type arguments `args'.
1711 /// Use this constructor if you already know the fully resolved
1714 public GenericTypeExpr (TypeSpec open_type
, TypeArguments args
, Location l
)
1716 this.open_type
= open_type
;
1721 public TypeArguments TypeArguments
{
1722 get { return args; }
1725 public override string GetSignatureForError ()
1727 return TypeManager
.CSharpName (type
);
1730 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1732 if (!args
.Resolve (ec
))
1735 TypeSpec
[] atypes
= args
.Arguments
;
1738 // Now bind the parameters
1740 type
= open_type
.MakeGenericType (atypes
);
1743 // Check constraints when context is not method/base type
1745 if (!ec
.HasUnresolvedConstraints
)
1746 CheckConstraints (ec
);
1752 // Checks the constraints of open generic type against type
1753 // arguments. Has to be called onafter all members are defined
1755 public bool CheckConstraints (IMemberContext ec
)
1757 if (constraints_checked
)
1760 constraints_checked
= true;
1762 var gtype
= (InflatedTypeSpec
) type
;
1763 var constraints
= gtype
.Constraints
;
1764 if (constraints
== null)
1767 return ConstraintChecker
.CheckAll (open_type
, args
.Arguments
, constraints
, loc
, ec
.Compiler
.Report
);
1770 public override bool CheckAccessLevel (IMemberContext mc
)
1772 DeclSpace c
= mc
.CurrentMemberDefinition
as DeclSpace
;
1774 c
= mc
.CurrentMemberDefinition
.Parent
;
1776 return c
.CheckAccessLevel (open_type
);
1779 public bool HasDynamicArguments ()
1781 return HasDynamicArguments (args
.Arguments
);
1784 static bool HasDynamicArguments (TypeSpec
[] args
)
1786 foreach (var item
in args
) {
1787 if (item
== InternalType
.Dynamic
)
1790 if (TypeManager
.IsGenericType (item
))
1791 return HasDynamicArguments (TypeManager
.GetTypeArguments (item
));
1797 public override bool Equals (object obj
)
1799 GenericTypeExpr cobj
= obj
as GenericTypeExpr
;
1803 if ((type
== null) || (cobj
.type
== null))
1806 return type
== cobj
.type
;
1809 public override int GetHashCode ()
1811 return base.GetHashCode ();
1815 static class ConstraintChecker
1818 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1819 /// after fully resolving the constructed type.
1821 public static bool CheckAll (MemberSpec context
, TypeSpec
[] targs
, TypeParameterSpec
[] tparams
, Location loc
, Report report
)
1823 for (int i
= 0; i
< tparams
.Length
; i
++) {
1824 if (!CheckConstraint (context
, targs
[i
], tparams
[i
], loc
, report
))
1831 static bool CheckConstraint (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, Location loc
, Report report
)
1834 // First, check the `class' and `struct' constraints.
1836 if (tparam
.HasSpecialClass
&& !TypeManager
.IsReferenceType (atype
)) {
1837 report
.Error (452, loc
,
1838 "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
1839 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1843 if (tparam
.HasSpecialStruct
&& (!TypeManager
.IsValueType (atype
) || TypeManager
.IsNullableType (atype
))) {
1844 report
.Error (453, loc
,
1845 "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}'",
1846 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1851 // The class constraint comes next.
1853 if (tparam
.HasTypeConstraint
) {
1854 CheckConversion (context
, atype
, tparam
, tparam
.BaseType
, loc
, report
);
1858 // Now, check the interfaces and type parameters constraints
1860 if (tparam
.Interfaces
!= null) {
1861 if (TypeManager
.IsNullableType (atype
)) {
1862 report
.Error (313, loc
,
1863 "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",
1864 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1866 foreach (TypeSpec iface
in tparam
.Interfaces
) {
1867 CheckConversion (context
, atype
, tparam
, iface
, loc
, report
);
1873 // Finally, check the constructor constraint.
1875 if (!tparam
.HasSpecialConstructor
)
1878 if (!HasDefaultConstructor (atype
)) {
1879 report
.SymbolRelatedToPreviousError (atype
);
1880 report
.Error (310, loc
,
1881 "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
1882 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1889 static void CheckConversion (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, TypeSpec ttype
, Location loc
, Report report
)
1891 var expr
= new EmptyExpression (atype
);
1892 if (!Convert
.ImplicitStandardConversionExists (expr
, ttype
)) {
1893 report
.SymbolRelatedToPreviousError (tparam
);
1894 if (TypeManager
.IsValueType (atype
)) {
1895 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}'",
1896 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1897 } else if (atype
.IsGenericParameter
) {
1898 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}'",
1899 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1901 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}'",
1902 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1907 static bool HasDefaultConstructor (TypeSpec atype
)
1909 var tp
= atype
as TypeParameterSpec
;
1911 return tp
.HasSpecialConstructor
|| tp
.HasSpecialStruct
;
1914 if (atype
.IsStruct
|| atype
.IsEnum
)
1917 if (atype
.IsAbstract
)
1920 var tdef
= atype
.GetDefinition ();
1923 // In some circumstances MemberCache is not yet populated and members
1924 // cannot be defined yet (recursive type new constraints)
1926 // class A<T> where T : B<T>, new () {}
1927 // class B<T> where T : A<T>, new () {}
1929 var tc
= tdef
.MemberDefinition
as Class
;
1931 if (tc
.InstanceConstructors
== null) {
1932 // Default ctor will be generated later
1936 foreach (var c
in tc
.InstanceConstructors
) {
1937 if (c
.ParameterInfo
.IsEmpty
) {
1938 if ((c
.ModFlags
& Modifiers
.PUBLIC
) != 0)
1946 var found
= MemberCache
.FindMember (tdef
,
1947 MemberFilter
.Constructor (ParametersCompiled
.EmptyReadOnlyParameters
),
1948 BindingRestriction
.DeclaredOnly
| BindingRestriction
.InstanceOnly
);
1950 return found
!= null && (found
.Modifiers
& Modifiers
.PUBLIC
) != 0;
1955 /// A generic method definition.
1957 public class GenericMethod
: DeclSpace
1959 ParametersCompiled parameters
;
1961 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1962 FullNamedExpression return_type
, ParametersCompiled parameters
)
1963 : base (ns
, parent
, name
, null)
1965 this.parameters
= parameters
;
1968 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
, TypeParameter
[] tparams
,
1969 FullNamedExpression return_type
, ParametersCompiled parameters
)
1970 : this (ns
, parent
, name
, return_type
, parameters
)
1972 this.type_params
= tparams
;
1975 public override TypeParameter
[] CurrentTypeParameters
{
1977 return base.type_params
;
1981 public override TypeBuilder
DefineType ()
1983 throw new Exception ();
1986 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
1988 throw new NotSupportedException ();
1991 public override bool Define ()
1993 throw new NotSupportedException ();
1997 /// Define and resolve the type parameters.
1998 /// We're called from Method.Define().
2000 public bool Define (MethodOrOperator m
)
2002 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
2003 string[] snames
= new string [names
.Length
];
2004 for (int i
= 0; i
< names
.Length
; i
++) {
2005 string type_argument_name
= names
[i
].Name
;
2006 int idx
= parameters
.GetParameterIndexByName (type_argument_name
);
2011 b
= new ToplevelBlock (Compiler
, Location
);
2013 b
.Error_AlreadyDeclaredTypeParameter (parameters
[i
].Location
,
2014 type_argument_name
, "method parameter");
2017 if (m
.Block
!= null) {
2018 var ikv
= m
.Block
.GetKnownVariable (type_argument_name
);
2020 ikv
.Block
.Error_AlreadyDeclaredTypeParameter (ikv
.Location
, type_argument_name
, "local variable");
2023 snames
[i
] = type_argument_name
;
2026 GenericTypeParameterBuilder
[] gen_params
= m
.MethodBuilder
.DefineGenericParameters (snames
);
2027 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
2028 TypeParameters
[i
].Define (gen_params
[i
], null);
2033 public void EmitAttributes ()
2035 if (OptAttributes
!= null)
2036 OptAttributes
.Emit ();
2039 public override string GetSignatureForError ()
2041 return base.GetSignatureForError () + parameters
.GetSignatureForError ();
2044 public override AttributeTargets AttributeTargets
{
2046 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
2050 public override string DocCommentHeader
{
2051 get { return "M:"; }
2054 public new void VerifyClsCompliance ()
2056 foreach (TypeParameter tp
in TypeParameters
) {
2057 tp
.VerifyClsCompliance ();
2062 public partial class TypeManager
2064 public static Variance
CheckTypeVariance (TypeSpec t
, Variance expected
, IMemberContext member
)
2066 var tp
= t
as TypeParameterSpec
;
2068 Variance v
= tp
.Variance
;
2069 if (expected
== Variance
.None
&& v
!= expected
||
2070 expected
== Variance
.Covariant
&& v
== Variance
.Contravariant
||
2071 expected
== Variance
.Contravariant
&& v
== Variance
.Covariant
) {
2072 ((TypeParameter
)tp
.MemberDefinition
).ErrorInvalidVariance (member
, expected
);
2078 if (t
.TypeArguments
.Length
> 0) {
2079 var targs_definition
= t
.MemberDefinition
.TypeParameters
;
2080 TypeSpec
[] targs
= GetTypeArguments (t
);
2081 for (int i
= 0; i
< targs
.Length
; ++i
) {
2082 Variance v
= targs_definition
[i
].Variance
;
2083 CheckTypeVariance (targs
[i
], (Variance
) ((int)v
* (int)expected
), member
);
2090 return CheckTypeVariance (GetElementType (t
), expected
, member
);
2092 return Variance
.None
;
2096 /// Type inference. Try to infer the type arguments from `method',
2097 /// which is invoked with the arguments `arguments'. This is used
2098 /// when resolving an Invocation or a DelegateInvocation and the user
2099 /// did not explicitly specify type arguments.
2101 public static int InferTypeArguments (ResolveContext ec
, Arguments arguments
, ref MethodSpec method
)
2103 ATypeInference ti
= ATypeInference
.CreateInstance (arguments
);
2104 TypeSpec
[] i_args
= ti
.InferMethodArguments (ec
, method
);
2106 return ti
.InferenceScore
;
2108 if (i_args
.Length
== 0)
2111 method
= method
.MakeGenericMethod (i_args
);
2116 abstract class ATypeInference
2118 protected readonly Arguments arguments
;
2119 protected readonly int arg_count
;
2121 protected ATypeInference (Arguments arguments
)
2123 this.arguments
= arguments
;
2124 if (arguments
!= null)
2125 arg_count
= arguments
.Count
;
2128 public static ATypeInference
CreateInstance (Arguments arguments
)
2130 return new TypeInference (arguments
);
2133 public virtual int InferenceScore
{
2135 return int.MaxValue
;
2139 public abstract TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
);
2143 // Implements C# type inference
2145 class TypeInference
: ATypeInference
2148 // Tracks successful rate of type inference
2150 int score
= int.MaxValue
;
2152 public TypeInference (Arguments arguments
)
2157 public override int InferenceScore
{
2163 public override TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
)
2165 var method_generic_args
= method
.GenericDefinition
.TypeParameters
;
2166 TypeInferenceContext context
= new TypeInferenceContext (method_generic_args
);
2167 if (!context
.UnfixedVariableExists
)
2168 return TypeSpec
.EmptyTypes
;
2170 AParametersCollection pd
= method
.Parameters
;
2171 if (!InferInPhases (ec
, context
, pd
))
2174 return context
.InferredTypeArguments
;
2178 // Implements method type arguments inference
2180 bool InferInPhases (ResolveContext ec
, TypeInferenceContext tic
, AParametersCollection methodParameters
)
2182 int params_arguments_start
;
2183 if (methodParameters
.HasParams
) {
2184 params_arguments_start
= methodParameters
.Count
- 1;
2186 params_arguments_start
= arg_count
;
2189 TypeSpec
[] ptypes
= methodParameters
.Types
;
2192 // The first inference phase
2194 TypeSpec method_parameter
= null;
2195 for (int i
= 0; i
< arg_count
; i
++) {
2196 Argument a
= arguments
[i
];
2200 if (i
< params_arguments_start
) {
2201 method_parameter
= methodParameters
.Types
[i
];
2202 } else if (i
== params_arguments_start
) {
2203 if (arg_count
== params_arguments_start
+ 1 && TypeManager
.HasElementType (a
.Type
))
2204 method_parameter
= methodParameters
.Types
[params_arguments_start
];
2206 method_parameter
= TypeManager
.GetElementType (methodParameters
.Types
[params_arguments_start
]);
2208 ptypes
= (TypeSpec
[]) ptypes
.Clone ();
2209 ptypes
[i
] = method_parameter
;
2213 // When a lambda expression, an anonymous method
2214 // is used an explicit argument type inference takes a place
2216 AnonymousMethodExpression am
= a
.Expr
as AnonymousMethodExpression
;
2218 if (am
.ExplicitTypeInference (ec
, tic
, method_parameter
))
2224 score
-= tic
.ExactInference (a
.Type
, method_parameter
);
2228 if (a
.Expr
.Type
== InternalType
.Null
)
2231 if (TypeManager
.IsValueType (method_parameter
)) {
2232 score
-= tic
.LowerBoundInference (a
.Type
, method_parameter
);
2237 // Otherwise an output type inference is made
2239 score
-= tic
.OutputTypeInference (ec
, a
.Expr
, method_parameter
);
2243 // Part of the second phase but because it happens only once
2244 // we don't need to call it in cycle
2246 bool fixed_any
= false;
2247 if (!tic
.FixIndependentTypeArguments (ec
, ptypes
, ref fixed_any
))
2250 return DoSecondPhase (ec
, tic
, ptypes
, !fixed_any
);
2253 bool DoSecondPhase (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec
[] methodParameters
, bool fixDependent
)
2255 bool fixed_any
= false;
2256 if (fixDependent
&& !tic
.FixDependentTypes (ec
, ref fixed_any
))
2259 // If no further unfixed type variables exist, type inference succeeds
2260 if (!tic
.UnfixedVariableExists
)
2263 if (!fixed_any
&& fixDependent
)
2266 // For all arguments where the corresponding argument output types
2267 // contain unfixed type variables but the input types do not,
2268 // an output type inference is made
2269 for (int i
= 0; i
< arg_count
; i
++) {
2271 // Align params arguments
2272 TypeSpec t_i
= methodParameters
[i
>= methodParameters
.Length
? methodParameters
.Length
- 1: i
];
2274 if (!TypeManager
.IsDelegateType (t_i
)) {
2275 if (t_i
.GetDefinition () != TypeManager
.expression_type
)
2278 t_i
= TypeManager
.GetTypeArguments (t_i
) [0];
2281 var mi
= Delegate
.GetInvokeMethod (ec
.Compiler
, t_i
);
2282 TypeSpec rtype
= mi
.ReturnType
;
2284 if (tic
.IsReturnTypeNonDependent (ec
, mi
, rtype
))
2285 score
-= tic
.OutputTypeInference (ec
, arguments
[i
].Expr
, t_i
);
2289 return DoSecondPhase (ec
, tic
, methodParameters
, true);
2293 public class TypeInferenceContext
2304 public readonly TypeSpec Type
;
2305 public readonly BoundKind Kind
;
2307 public BoundInfo (TypeSpec type
, BoundKind kind
)
2313 public override int GetHashCode ()
2315 return Type
.GetHashCode ();
2318 public override bool Equals (object obj
)
2320 BoundInfo a
= (BoundInfo
) obj
;
2321 return Type
== a
.Type
&& Kind
== a
.Kind
;
2325 readonly TypeSpec
[] unfixed_types
;
2326 readonly TypeSpec
[] fixed_types
;
2327 readonly List
<BoundInfo
>[] bounds
;
2330 // TODO MemberCache: Could it be TypeParameterSpec[] ??
2331 public TypeInferenceContext (TypeSpec
[] typeArguments
)
2333 if (typeArguments
.Length
== 0)
2334 throw new ArgumentException ("Empty generic arguments");
2336 fixed_types
= new TypeSpec
[typeArguments
.Length
];
2337 for (int i
= 0; i
< typeArguments
.Length
; ++i
) {
2338 if (typeArguments
[i
].IsGenericParameter
) {
2339 if (bounds
== null) {
2340 bounds
= new List
<BoundInfo
> [typeArguments
.Length
];
2341 unfixed_types
= new TypeSpec
[typeArguments
.Length
];
2343 unfixed_types
[i
] = typeArguments
[i
];
2345 fixed_types
[i
] = typeArguments
[i
];
2351 // Used together with AddCommonTypeBound fo implement
2352 // 7.4.2.13 Finding the best common type of a set of expressions
2354 public TypeInferenceContext ()
2356 fixed_types
= new TypeSpec
[1];
2357 unfixed_types
= new TypeSpec
[1];
2358 unfixed_types
[0] = InternalType
.Arglist
; // it can be any internal type
2359 bounds
= new List
<BoundInfo
> [1];
2362 public TypeSpec
[] InferredTypeArguments
{
2368 public void AddCommonTypeBound (TypeSpec type
)
2370 AddToBounds (new BoundInfo (type
, BoundKind
.Lower
), 0);
2373 void AddToBounds (BoundInfo bound
, int index
)
2376 // Some types cannot be used as type arguments
2378 if (bound
.Type
== TypeManager
.void_type
|| bound
.Type
.IsPointer
)
2381 var a
= bounds
[index
];
2383 a
= new List
<BoundInfo
> ();
2386 if (a
.Contains (bound
))
2391 // SPEC: does not cover type inference using constraints
2393 //if (TypeManager.IsGenericParameter (t)) {
2394 // GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
2395 // if (constraints != null) {
2396 // //if (constraints.EffectiveBaseClass != null)
2397 // // t = constraints.EffectiveBaseClass;
2403 bool AllTypesAreFixed (TypeSpec
[] types
)
2405 foreach (TypeSpec t
in types
) {
2406 if (t
.IsGenericParameter
) {
2412 if (TypeManager
.IsGenericType (t
))
2413 return AllTypesAreFixed (TypeManager
.GetTypeArguments (t
));
2420 // 26.3.3.8 Exact Inference
2422 public int ExactInference (TypeSpec u
, TypeSpec v
)
2424 // If V is an array type
2429 // TODO MemberCache: GetMetaInfo ()
2430 if (u
.GetMetaInfo ().GetArrayRank () != v
.GetMetaInfo ().GetArrayRank ())
2433 return ExactInference (TypeManager
.GetElementType (u
), TypeManager
.GetElementType (v
));
2436 // If V is constructed type and U is constructed type
2437 if (TypeManager
.IsGenericType (v
)) {
2438 if (!TypeManager
.IsGenericType (u
))
2441 TypeSpec
[] ga_u
= TypeManager
.GetTypeArguments (u
);
2442 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2443 if (ga_u
.Length
!= ga_v
.Length
)
2447 for (int i
= 0; i
< ga_u
.Length
; ++i
)
2448 score
+= ExactInference (ga_u
[i
], ga_v
[i
]);
2450 return score
> 0 ? 1 : 0;
2453 // If V is one of the unfixed type arguments
2454 int pos
= IsUnfixed (v
);
2458 AddToBounds (new BoundInfo (u
, BoundKind
.Exact
), pos
);
2462 public bool FixAllTypes (ResolveContext ec
)
2464 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2465 if (!FixType (ec
, i
))
2472 // All unfixed type variables Xi are fixed for which all of the following hold:
2473 // a, There is at least one type variable Xj that depends on Xi
2474 // b, Xi has a non-empty set of bounds
2476 public bool FixDependentTypes (ResolveContext ec
, ref bool fixed_any
)
2478 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2479 if (unfixed_types
[i
] == null)
2482 if (bounds
[i
] == null)
2485 if (!FixType (ec
, i
))
2495 // All unfixed type variables Xi which depend on no Xj are fixed
2497 public bool FixIndependentTypeArguments (ResolveContext ec
, TypeSpec
[] methodParameters
, ref bool fixed_any
)
2499 var types_to_fix
= new List
<TypeSpec
> (unfixed_types
);
2500 for (int i
= 0; i
< methodParameters
.Length
; ++i
) {
2501 TypeSpec t
= methodParameters
[i
];
2503 if (!TypeManager
.IsDelegateType (t
)) {
2504 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2507 t
= TypeManager
.GetTypeArguments (t
) [0];
2510 if (t
.IsGenericParameter
)
2513 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2514 TypeSpec rtype
= invoke
.ReturnType
;
2515 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2518 // Remove dependent types, they cannot be fixed yet
2519 RemoveDependentTypes (types_to_fix
, rtype
);
2522 foreach (TypeSpec t
in types_to_fix
) {
2526 int idx
= IsUnfixed (t
);
2527 if (idx
>= 0 && !FixType (ec
, idx
)) {
2532 fixed_any
= types_to_fix
.Count
> 0;
2539 public bool FixType (ResolveContext ec
, int i
)
2541 // It's already fixed
2542 if (unfixed_types
[i
] == null)
2543 throw new InternalErrorException ("Type argument has been already fixed");
2548 var candidates
= bounds
[i
];
2549 if (candidates
== null)
2552 if (candidates
.Count
== 1) {
2553 unfixed_types
[i
] = null;
2554 TypeSpec t
= candidates
[0].Type
;
2555 if (t
== InternalType
.Null
)
2558 fixed_types
[i
] = t
;
2563 // Determines a unique type from which there is
2564 // a standard implicit conversion to all the other
2567 TypeSpec best_candidate
= null;
2569 int candidates_count
= candidates
.Count
;
2570 for (int ci
= 0; ci
< candidates_count
; ++ci
) {
2571 BoundInfo bound
= candidates
[ci
];
2572 for (cii
= 0; cii
< candidates_count
; ++cii
) {
2576 BoundInfo cbound
= candidates
[cii
];
2578 // Same type parameters with different bounds
2579 if (cbound
.Type
== bound
.Type
) {
2580 if (bound
.Kind
!= BoundKind
.Exact
)
2586 if (bound
.Kind
== BoundKind
.Exact
|| cbound
.Kind
== BoundKind
.Exact
) {
2587 if (cbound
.Kind
!= BoundKind
.Exact
) {
2588 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2595 if (bound
.Kind
!= BoundKind
.Exact
) {
2596 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2607 if (bound
.Kind
== BoundKind
.Lower
) {
2608 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2612 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2618 if (cii
!= candidates_count
)
2621 if (best_candidate
!= null && best_candidate
!= bound
.Type
)
2624 best_candidate
= bound
.Type
;
2627 if (best_candidate
== null)
2630 unfixed_types
[i
] = null;
2631 fixed_types
[i
] = best_candidate
;
2636 // Uses inferred or partially infered types to inflate delegate type argument. Returns
2637 // null when type parameter was not yet inferres
2639 public TypeSpec
InflateGenericArgument (TypeSpec parameter
)
2641 var tp
= parameter
as TypeParameterSpec
;
2644 // Type inference work on generic arguments (MVAR) only
2646 if (!tp
.IsMethodOwned
)
2649 return fixed_types
[tp
.DeclaredPosition
] ?? parameter
;
2652 var gt
= parameter
as InflatedTypeSpec
;
2654 var inflated_targs
= new TypeSpec
[gt
.TypeArguments
.Length
];
2655 for (int ii
= 0; ii
< inflated_targs
.Length
; ++ii
) {
2656 var inflated
= InflateGenericArgument (gt
.TypeArguments
[ii
]);
2657 if (inflated
== null)
2660 inflated_targs
[ii
] = inflated
;
2663 return gt
.GetDefinition ().MakeGenericType (inflated_targs
);
2670 // Tests whether all delegate input arguments are fixed and generic output type
2671 // requires output type inference
2673 public bool IsReturnTypeNonDependent (ResolveContext ec
, MethodSpec invoke
, TypeSpec returnType
)
2675 if (returnType
.IsGenericParameter
) {
2676 if (IsFixed (returnType
))
2678 } else if (TypeManager
.IsGenericType (returnType
)) {
2679 if (TypeManager
.IsDelegateType (returnType
)) {
2680 invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, returnType
);
2681 return IsReturnTypeNonDependent (ec
, invoke
, invoke
.ReturnType
);
2684 TypeSpec
[] g_args
= TypeManager
.GetTypeArguments (returnType
);
2686 // At least one unfixed return type has to exist
2687 if (AllTypesAreFixed (g_args
))
2693 // All generic input arguments have to be fixed
2694 AParametersCollection d_parameters
= invoke
.Parameters
;
2695 return AllTypesAreFixed (d_parameters
.Types
);
2698 bool IsFixed (TypeSpec type
)
2700 return IsUnfixed (type
) == -1;
2703 int IsUnfixed (TypeSpec type
)
2705 if (!type
.IsGenericParameter
)
2708 //return unfixed_types[type.GenericParameterPosition] != null;
2709 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2710 if (unfixed_types
[i
] == type
)
2718 // 26.3.3.9 Lower-bound Inference
2720 public int LowerBoundInference (TypeSpec u
, TypeSpec v
)
2722 return LowerBoundInference (u
, v
, false);
2726 // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
2728 int LowerBoundInference (TypeSpec u
, TypeSpec v
, bool inversed
)
2730 // If V is one of the unfixed type arguments
2731 int pos
= IsUnfixed (v
);
2733 AddToBounds (new BoundInfo (u
, inversed
? BoundKind
.Upper
: BoundKind
.Lower
), pos
);
2737 // If U is an array type
2738 var u_ac
= u
as ArrayContainer
;
2740 var v_ac
= v
as ArrayContainer
;
2742 if (u_ac
.Rank
!= v_ac
.Rank
)
2745 if (TypeManager
.IsValueType (u_ac
.Element
))
2746 return ExactInference (u_ac
.Element
, v_ac
.Element
);
2748 return LowerBoundInference (u_ac
.Element
, v_ac
.Element
, inversed
);
2754 if (TypeManager
.IsGenericType (v
)) {
2755 TypeSpec g_v
= v
.GetDefinition ();
2756 if (g_v
!= TypeManager
.generic_ilist_type
&&
2757 g_v
!= TypeManager
.generic_icollection_type
&&
2758 g_v
!= TypeManager
.generic_ienumerable_type
)
2761 var v_i
= TypeManager
.GetTypeArguments (v
) [0];
2762 if (TypeManager
.IsValueType (u_ac
.Element
))
2763 return ExactInference (u_ac
.Element
, v_i
);
2765 return LowerBoundInference (u_ac
.Element
, v_i
);
2767 } else if (TypeManager
.IsGenericType (v
)) {
2769 // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
2770 // such that U is identical to, inherits from (directly or indirectly),
2771 // or implements (directly or indirectly) C<U1..Uk>
2773 var u_candidates
= new List
<TypeSpec
> ();
2774 var open_v
= v
.MemberDefinition
;
2776 for (TypeSpec t
= u
; t
!= null; t
= t
.BaseType
) {
2777 if (open_v
== t
.MemberDefinition
)
2778 u_candidates
.Add (t
);
2780 if (t
.Interfaces
!= null) {
2781 foreach (var iface
in t
.Interfaces
) {
2782 if (open_v
== iface
.MemberDefinition
)
2783 u_candidates
.Add (iface
);
2788 TypeSpec
[] unique_candidate_targs
= null;
2789 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2790 foreach (TypeSpec u_candidate
in u_candidates
) {
2792 // The unique set of types U1..Uk means that if we have an interface I<T>,
2793 // class U : I<int>, I<long> then no type inference is made when inferring
2794 // type I<T> by applying type U because T could be int or long
2796 if (unique_candidate_targs
!= null) {
2797 TypeSpec
[] second_unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2798 if (TypeSpecComparer
.Default
.Equals (unique_candidate_targs
, second_unique_candidate_targs
)) {
2799 unique_candidate_targs
= second_unique_candidate_targs
;
2804 // This should always cause type inference failure
2810 unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2813 if (unique_candidate_targs
!= null) {
2814 var ga_open_v
= open_v
.TypeParameters
;
2816 for (int i
= 0; i
< unique_candidate_targs
.Length
; ++i
) {
2817 Variance variance
= ga_open_v
[i
].Variance
;
2819 TypeSpec u_i
= unique_candidate_targs
[i
];
2820 if (variance
== Variance
.None
|| TypeManager
.IsValueType (u_i
)) {
2821 if (ExactInference (u_i
, ga_v
[i
]) == 0)
2824 bool upper_bound
= (variance
== Variance
.Contravariant
&& !inversed
) ||
2825 (variance
== Variance
.Covariant
&& inversed
);
2827 if (LowerBoundInference (u_i
, ga_v
[i
], upper_bound
) == 0)
2839 // 26.3.3.6 Output Type Inference
2841 public int OutputTypeInference (ResolveContext ec
, Expression e
, TypeSpec t
)
2843 // If e is a lambda or anonymous method with inferred return type
2844 AnonymousMethodExpression ame
= e
as AnonymousMethodExpression
;
2846 TypeSpec rt
= ame
.InferReturnType (ec
, this, t
);
2847 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2850 AParametersCollection pd
= invoke
.Parameters
;
2851 return ame
.Parameters
.Count
== pd
.Count
? 1 : 0;
2854 TypeSpec rtype
= invoke
.ReturnType
;
2855 return LowerBoundInference (rt
, rtype
) + 1;
2859 // if E is a method group and T is a delegate type or expression tree type
2860 // return type Tb with parameter types T1..Tk and return type Tb, and overload
2861 // resolution of E with the types T1..Tk yields a single method with return type U,
2862 // then a lower-bound inference is made from U for Tb.
2864 if (e
is MethodGroupExpr
) {
2865 if (!TypeManager
.IsDelegateType (t
)) {
2866 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2869 t
= TypeManager
.GetTypeArguments (t
)[0];
2872 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2873 TypeSpec rtype
= invoke
.ReturnType
;
2875 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2878 // LAMESPEC: Standard does not specify that all methodgroup arguments
2879 // has to be fixed but it does not specify how to do recursive type inference
2880 // either. We choose the simple option and infer return type only
2881 // if all delegate generic arguments are fixed.
2882 TypeSpec
[] param_types
= new TypeSpec
[invoke
.Parameters
.Count
];
2883 for (int i
= 0; i
< param_types
.Length
; ++i
) {
2884 var inflated
= InflateGenericArgument (invoke
.Parameters
.Types
[i
]);
2885 if (inflated
== null)
2888 param_types
[i
] = inflated
;
2891 MethodGroupExpr mg
= (MethodGroupExpr
) e
;
2892 Arguments args
= DelegateCreation
.CreateDelegateMethodArguments (invoke
.Parameters
, param_types
, e
.Location
);
2893 mg
= mg
.OverloadResolve (ec
, ref args
, true, e
.Location
);
2897 return LowerBoundInference (mg
.BestCandidate
.ReturnType
, rtype
) + 1;
2901 // if e is an expression with type U, then
2902 // a lower-bound inference is made from U for T
2904 return LowerBoundInference (e
.Type
, t
) * 2;
2907 void RemoveDependentTypes (List
<TypeSpec
> types
, TypeSpec returnType
)
2909 int idx
= IsUnfixed (returnType
);
2915 if (TypeManager
.IsGenericType (returnType
)) {
2916 foreach (TypeSpec t
in TypeManager
.GetTypeArguments (returnType
)) {
2917 RemoveDependentTypes (types
, t
);
2922 public bool UnfixedVariableExists
{
2924 if (unfixed_types
== null)
2927 foreach (TypeSpec ut
in unfixed_types
)