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 bool IsConvertibleToInterface (TypeSpec iface
)
981 if (Interfaces
!= null) {
982 foreach (var t
in Interfaces
) {
988 if (TypeArguments
!= null) {
989 foreach (var t
in TypeArguments
) {
990 if (((TypeParameterSpec
) t
).IsConvertibleToInterface (iface
))
998 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1000 return mutator
.Mutate (this);
1004 public struct TypeParameterInflator
1006 readonly TypeSpec type
;
1007 readonly TypeParameterSpec
[] tparams
;
1008 readonly TypeSpec
[] targs
;
1010 public TypeParameterInflator (TypeParameterInflator nested
, TypeSpec type
)
1011 : this (type
, nested
.tparams
, nested
.targs
)
1015 public TypeParameterInflator (TypeSpec type
, TypeParameterSpec
[] tparams
, TypeSpec
[] targs
)
1017 if (tparams
.Length
!= targs
.Length
)
1018 throw new ArgumentException ("Invalid arguments");
1020 this.tparams
= tparams
;
1026 // Type parameters to inflate
1028 public TypeParameterSpec
[] TypeParameters
{
1034 public TypeSpec
Inflate (TypeSpec ts
)
1036 var tp
= ts
as TypeParameterSpec
;
1038 return Inflate (tp
);
1040 var ac
= ts
as ArrayContainer
;
1042 var et
= Inflate (ac
.Element
);
1043 if (et
!= ac
.Element
)
1044 return ArrayContainer
.MakeType (et
, ac
.Rank
);
1050 // When inflating a nested type, inflate its parent first
1051 // in case it's using same type parameters (was inflated within the type)
1054 var parent
= Inflate (ts
.DeclaringType
);
1055 if (ts
.DeclaringType
!= parent
) {
1057 // Keep the inflated type arguments
1059 var targs
= ts
.TypeArguments
;
1062 // Parent was inflated, find the same type on inflated type
1063 // to use same cache for nested types on same generic parent
1065 // TODO: Should use BindingRestriction.DeclaredOnly or GetMember
1066 ts
= MemberCache
.FindNestedType (parent
, ts
.Name
, targs
.Length
);
1069 // Handle the tricky case where parent shares local type arguments
1070 // which means inflating inflated type
1073 // public static Nested<T> Foo () { return null; }
1075 // public class Nested<U> {}
1078 // return type of Test<string>.Foo() has to be Test<string>.Nested<string>
1080 if (targs
.Length
> 0) {
1081 var inflated_targs
= new TypeSpec
[targs
.Length
];
1082 for (var i
= 0; i
< targs
.Length
; ++i
)
1083 inflated_targs
[i
] = Inflate (targs
[i
]);
1085 ts
= ts
.MakeGenericType (inflated_targs
);
1092 // Inflate generic type
1094 return InflateTypeParameters (ts
);
1099 public TypeSpec
Inflate (TypeParameterSpec tp
)
1101 for (int i
= 0; i
< tparams
.Length
; ++i
)
1102 if (tparams
[i
] == tp
)
1105 // This can happen when inflating nested types
1106 // without type arguments specified
1111 // Inflates generic types
1113 TypeSpec
InflateTypeParameters (TypeSpec type
)
1115 var targs
= new TypeSpec
[type
.Arity
];
1118 var gti
= type
as InflatedTypeSpec
;
1121 // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {}
1124 for (; i
< targs
.Length
; ++i
)
1125 targs
[i
] = Inflate (gti
.TypeArguments
[i
]);
1127 return gti
.GetDefinition ().MakeGenericType (targs
);
1131 // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; }
1133 var args
= type
.MemberDefinition
.TypeParameters
;
1134 foreach (var ds_tp
in args
)
1135 targs
[i
++] = Inflate (ds_tp
);
1137 return type
.MakeGenericType (targs
);
1140 public TypeSpec TypeInstance
{
1141 get { return type; }
1146 // Before emitting any code we have to change all MVAR references to VAR
1147 // when the method is of generic type and has hoisted variables
1149 public class TypeParameterMutator
1151 TypeParameter
[] mvar
;
1152 TypeParameter
[] var;
1153 Dictionary
<TypeSpec
, TypeSpec
> mutated_typespec
= new Dictionary
<TypeSpec
, TypeSpec
> ();
1155 public TypeParameterMutator (TypeParameter
[] mvar
, TypeParameter
[] var)
1157 if (mvar
.Length
!= var.Length
)
1158 throw new ArgumentException ();
1164 public TypeSpec
Mutate (TypeSpec ts
)
1167 if (mutated_typespec
.TryGetValue (ts
, out value))
1170 value = ts
.Mutate (this);
1171 mutated_typespec
.Add (ts
, value);
1175 public FieldInfo
Mutate (FieldSpec fs
)
1178 return fs
.GetMetaInfo ();
1181 public TypeParameterSpec
Mutate (TypeParameterSpec tp
)
1183 for (int i
= 0; i
< mvar
.Length
; ++i
) {
1184 if (mvar
[i
].Type
== tp
)
1191 public TypeSpec
[] Mutate (TypeSpec
[] targs
)
1193 TypeSpec
[] mutated
= new TypeSpec
[targs
.Length
];
1194 bool changed
= false;
1195 for (int i
= 0; i
< targs
.Length
; ++i
) {
1196 mutated
[i
] = Mutate (targs
[i
]);
1197 changed
|= targs
[i
] != mutated
[i
];
1200 return changed
? mutated
: targs
;
1205 /// A TypeExpr which already resolved to a type parameter.
1207 public class TypeParameterExpr
: TypeExpr
{
1209 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1211 this.type
= type_parameter
.Type
;
1212 this.eclass
= ExprClass
.TypeParameter
;
1216 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1218 throw new NotSupportedException ();
1221 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
1226 public override bool CheckAccessLevel (IMemberContext ds
)
1232 public class InflatedTypeSpec
: TypeSpec
1235 TypeParameterSpec
[] constraints
;
1236 readonly TypeSpec open_type
;
1238 public InflatedTypeSpec (TypeSpec openType
, TypeSpec declaringType
, TypeSpec
[] targs
)
1239 : base (openType
.Kind
, declaringType
, openType
.MemberDefinition
, null, openType
.Modifiers
)
1242 throw new ArgumentNullException ("targs");
1244 // this.state = openType.state;
1245 this.open_type
= openType
;
1251 public override TypeSpec BaseType
{
1253 if (cache
== null || (state
& StateFlags
.PendingBaseTypeInflate
) != 0)
1254 InitializeMemberCache (true);
1256 return base.BaseType
;
1261 // Inflated type parameters with constraints array, mapping with type arguments is based on index
1263 public TypeParameterSpec
[] Constraints
{
1265 if (constraints
== null) {
1266 var inflator
= new TypeParameterInflator (this, MemberDefinition
.TypeParameters
, targs
);
1267 constraints
= TypeParameterSpec
.InflateConstraints (inflator
, MemberDefinition
.TypeParameters
);
1274 public override IList
<TypeSpec
> Interfaces
{
1277 InitializeMemberCache (true);
1279 return base.Interfaces
;
1283 public override MemberCache MemberCacheTypes
{
1286 InitializeMemberCache (true);
1293 // Types used to inflate the generic type
1295 public override TypeSpec
[] TypeArguments
{
1303 Type
CreateMetaInfo (TypeParameterMutator mutator
)
1306 // Converts nested type arguments into right order
1307 // Foo<string, bool>.Bar<int> => string, bool, int
1309 var all
= new List
<Type
> ();
1310 TypeSpec type
= this;
1311 TypeSpec definition
= type
;
1313 if (type
.GetDefinition().IsGeneric
) {
1315 type
.TypeArguments
!= TypeSpec
.EmptyTypes
?
1316 type
.TypeArguments
.Select (l
=> l
.GetMetaInfo ()) :
1317 type
.MemberDefinition
.TypeParameters
.Select (l
=> l
.GetMetaInfo ()));
1320 definition
= definition
.GetDefinition ();
1321 type
= type
.DeclaringType
;
1322 } while (type
!= null);
1324 return definition
.GetMetaInfo ().MakeGenericType (all
.ToArray ());
1327 public override ObsoleteAttribute
GetAttributeObsolete ()
1329 return open_type
.GetAttributeObsolete ();
1332 protected override bool IsNotCLSCompliant ()
1334 if (base.IsNotCLSCompliant ())
1337 foreach (var ta
in TypeArguments
) {
1338 if (ta
.MemberDefinition
.IsNotCLSCompliant ())
1345 public override TypeSpec
GetDefinition ()
1350 public override Type
GetMetaInfo ()
1353 info
= CreateMetaInfo (null);
1358 public override string GetSignatureForError ()
1360 if (TypeManager
.IsNullableType (open_type
))
1361 return targs
[0].GetSignatureForError () + "?";
1363 if (MemberDefinition
is AnonymousTypeClass
)
1364 return ((AnonymousTypeClass
) MemberDefinition
).GetSignatureForError ();
1366 return base.GetSignatureForError ();
1369 protected override string GetTypeNameSignature ()
1371 if (targs
.Length
== 0 || MemberDefinition
is AnonymousTypeClass
)
1374 return "<" + TypeManager
.CSharpName (targs
) + ">";
1377 protected override void InitializeMemberCache (bool onlyTypes
)
1380 cache
= new MemberCache (open_type
.MemberCache
);
1382 TypeParameterSpec
[] tparams_full
;
1383 TypeSpec
[] targs_full
= targs
;
1386 // Special case is needed when we are inflating an open type (nested type definition)
1387 // on inflated parent. Consider following case
1389 // Foo<T>.Bar<U> => Foo<string>.Bar<U>
1391 // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U>
1393 List
<TypeSpec
> merged_targs
= null;
1394 List
<TypeParameterSpec
> merged_tparams
= null;
1396 var type
= DeclaringType
;
1399 if (type
.TypeArguments
.Length
> 0) {
1400 if (merged_targs
== null) {
1401 merged_targs
= new List
<TypeSpec
> ();
1402 merged_tparams
= new List
<TypeParameterSpec
> ();
1403 if (targs
.Length
> 0) {
1404 merged_targs
.AddRange (targs
);
1405 merged_tparams
.AddRange (open_type
.MemberDefinition
.TypeParameters
);
1408 merged_tparams
.AddRange (type
.MemberDefinition
.TypeParameters
);
1409 merged_targs
.AddRange (type
.TypeArguments
);
1411 type
= type
.DeclaringType
;
1412 } while (type
!= null);
1414 if (merged_targs
!= null) {
1415 // Type arguments are not in the right order but it should not matter in this case
1416 targs_full
= merged_targs
.ToArray ();
1417 tparams_full
= merged_tparams
.ToArray ();
1418 } else if (targs
.Length
== 0) {
1419 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1421 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1423 } else if (targs
.Length
== 0) {
1424 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1426 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1429 var inflator
= new TypeParameterInflator (this, tparams_full
, targs_full
);
1432 // Two stage inflate due to possible nested types recursive
1442 // When resolving type of `b' members of `B' cannot be
1443 // inflated because are not yet available in membercache
1445 if ((state
& StateFlags
.PendingMemberCacheMembers
) == 0) {
1446 open_type
.MemberCache
.InflateTypes (cache
, inflator
);
1449 // Inflate any implemented interfaces
1451 if (open_type
.Interfaces
!= null) {
1452 ifaces
= new List
<TypeSpec
> (open_type
.Interfaces
.Count
);
1453 foreach (var iface
in open_type
.Interfaces
) {
1454 var iface_inflated
= inflator
.Inflate (iface
);
1455 AddInterface (iface_inflated
);
1460 // Handles the tricky case of recursive nested base generic type
1462 // class A<T> : Base<A<T>.Nested> {
1466 // When inflating A<T>. base type is not yet known, secondary
1467 // inflation is required (not common case) once base scope
1470 if (open_type
.BaseType
== null) {
1472 state
|= StateFlags
.PendingBaseTypeInflate
;
1474 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1476 } else if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1477 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1478 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1482 state
|= StateFlags
.PendingMemberCacheMembers
;
1486 var tc
= open_type
.MemberDefinition
as TypeContainer
;
1487 if (tc
!= null && !tc
.HasMembersDefined
)
1488 throw new InternalErrorException ("Inflating MemberCache with undefined members");
1490 if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
1491 BaseType
= inflator
.Inflate (open_type
.BaseType
);
1492 state
&= ~StateFlags
.PendingBaseTypeInflate
;
1495 state
&= ~StateFlags
.PendingMemberCacheMembers
;
1496 open_type
.MemberCache
.InflateMembers (cache
, open_type
, inflator
);
1499 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1501 var targs
= TypeArguments
;
1503 targs
= mutator
.Mutate (targs
);
1505 var decl
= DeclaringType
;
1506 if (IsNested
&& DeclaringType
.IsGenericOrParentIsGeneric
)
1507 decl
= mutator
.Mutate (decl
);
1509 if (targs
== TypeArguments
&& decl
== DeclaringType
)
1512 var mutated
= (InflatedTypeSpec
) MemberwiseClone ();
1513 if (decl
!= DeclaringType
) {
1514 // Gets back MethodInfo in case of metaInfo was inflated
1515 //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
1517 mutated
.declaringType
= decl
;
1518 mutated
.state
|= StateFlags
.PendingMetaInflate
;
1521 if (targs
!= null) {
1522 mutated
.targs
= targs
;
1523 mutated
.info
= null;
1532 // Tracks the type arguments when instantiating a generic type. It's used
1533 // by both type arguments and type parameters
1535 public class TypeArguments
1537 List
<FullNamedExpression
> args
;
1540 public TypeArguments (params FullNamedExpression
[] types
)
1542 this.args
= new List
<FullNamedExpression
> (types
);
1545 public void Add (FullNamedExpression type
)
1550 // TODO: Kill this monster
1551 public TypeParameterName
[] GetDeclarations ()
1553 return args
.ConvertAll (i
=> (TypeParameterName
) i
).ToArray ();
1557 /// We may only be used after Resolve() is called and return the fully
1560 // TODO: Not needed, just return type from resolve
1561 public TypeSpec
[] Arguments
{
1573 public virtual bool IsEmpty
{
1579 public string GetSignatureForError()
1581 StringBuilder sb
= new StringBuilder ();
1582 for (int i
= 0; i
< Count
; ++i
) {
1585 sb
.Append (expr
.GetSignatureForError ());
1591 return sb
.ToString ();
1595 /// Resolve the type arguments.
1597 public virtual bool Resolve (IMemberContext ec
)
1600 return atypes
.Length
!= 0;
1602 int count
= args
.Count
;
1605 atypes
= new TypeSpec
[count
];
1607 for (int i
= 0; i
< count
; i
++){
1608 TypeExpr te
= args
[i
].ResolveAsTypeTerminal (ec
, false);
1614 atypes
[i
] = te
.Type
;
1616 if (te
.Type
.IsStatic
) {
1617 ec
.Compiler
.Report
.Error (718, te
.Location
, "`{0}': static classes cannot be used as generic arguments",
1618 te
.GetSignatureForError ());
1622 if (te
.Type
.IsPointer
|| TypeManager
.IsSpecialType (te
.Type
)) {
1623 ec
.Compiler
.Report
.Error (306, te
.Location
,
1624 "The type `{0}' may not be used as a type argument",
1625 te
.GetSignatureForError ());
1631 atypes
= TypeSpec
.EmptyTypes
;
1636 public TypeArguments
Clone ()
1638 TypeArguments copy
= new TypeArguments ();
1639 foreach (var ta
in args
)
1646 public class UnboundTypeArguments
: TypeArguments
1648 public UnboundTypeArguments (int arity
)
1649 : base (new FullNamedExpression
[arity
])
1653 public override bool IsEmpty
{
1659 public override bool Resolve (IMemberContext ec
)
1661 // should not be called
1662 throw new NotSupportedException ();
1666 public class TypeParameterName
: SimpleName
1668 Attributes attributes
;
1671 public TypeParameterName (string name
, Attributes attrs
, Location loc
)
1672 : this (name
, attrs
, Variance
.None
, loc
)
1676 public TypeParameterName (string name
, Attributes attrs
, Variance variance
, Location loc
)
1680 this.variance
= variance
;
1683 public Attributes OptAttributes
{
1689 public Variance Variance
{
1697 // A type expression of generic type with type arguments
1699 class GenericTypeExpr
: TypeExpr
1703 bool constraints_checked
;
1706 /// Instantiate the generic type `t' with the type arguments `args'.
1707 /// Use this constructor if you already know the fully resolved
1710 public GenericTypeExpr (TypeSpec open_type
, TypeArguments args
, Location l
)
1712 this.open_type
= open_type
;
1717 public TypeArguments TypeArguments
{
1718 get { return args; }
1721 public override string GetSignatureForError ()
1723 return TypeManager
.CSharpName (type
);
1726 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
1728 if (!args
.Resolve (ec
))
1731 TypeSpec
[] atypes
= args
.Arguments
;
1734 // Now bind the parameters
1736 type
= open_type
.MakeGenericType (atypes
);
1739 // Check constraints when context is not method/base type
1741 if (!ec
.HasUnresolvedConstraints
)
1742 CheckConstraints (ec
);
1748 // Checks the constraints of open generic type against type
1749 // arguments. Has to be called onafter all members are defined
1751 public bool CheckConstraints (IMemberContext ec
)
1753 if (constraints_checked
)
1756 constraints_checked
= true;
1758 var gtype
= (InflatedTypeSpec
) type
;
1759 var constraints
= gtype
.Constraints
;
1760 if (constraints
== null)
1763 return ConstraintChecker
.CheckAll (open_type
, args
.Arguments
, constraints
, loc
, ec
.Compiler
.Report
);
1766 public override bool CheckAccessLevel (IMemberContext mc
)
1768 DeclSpace c
= mc
.CurrentMemberDefinition
as DeclSpace
;
1770 c
= mc
.CurrentMemberDefinition
.Parent
;
1772 return c
.CheckAccessLevel (open_type
);
1775 public bool HasDynamicArguments ()
1777 return HasDynamicArguments (args
.Arguments
);
1780 static bool HasDynamicArguments (TypeSpec
[] args
)
1782 foreach (var item
in args
) {
1783 if (item
== InternalType
.Dynamic
)
1786 if (TypeManager
.IsGenericType (item
))
1787 return HasDynamicArguments (TypeManager
.GetTypeArguments (item
));
1793 public override bool Equals (object obj
)
1795 GenericTypeExpr cobj
= obj
as GenericTypeExpr
;
1799 if ((type
== null) || (cobj
.type
== null))
1802 return type
== cobj
.type
;
1805 public override int GetHashCode ()
1807 return base.GetHashCode ();
1811 static class ConstraintChecker
1814 /// Check the constraints; we're called from ResolveAsTypeTerminal()
1815 /// after fully resolving the constructed type.
1817 public static bool CheckAll (MemberSpec context
, TypeSpec
[] targs
, TypeParameterSpec
[] tparams
, Location loc
, Report report
)
1819 for (int i
= 0; i
< tparams
.Length
; i
++) {
1820 if (!CheckConstraint (context
, targs
[i
], tparams
[i
], loc
, report
))
1827 static bool CheckConstraint (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, Location loc
, Report report
)
1830 // First, check the `class' and `struct' constraints.
1832 if (tparam
.HasSpecialClass
&& !TypeManager
.IsReferenceType (atype
)) {
1833 report
.Error (452, loc
,
1834 "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
1835 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1839 if (tparam
.HasSpecialStruct
&& (!TypeManager
.IsValueType (atype
) || TypeManager
.IsNullableType (atype
))) {
1840 report
.Error (453, loc
,
1841 "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}'",
1842 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1847 // The class constraint comes next.
1849 if (tparam
.HasTypeConstraint
) {
1850 CheckConversion (context
, atype
, tparam
, tparam
.BaseType
, loc
, report
);
1854 // Now, check the interfaces and type parameters constraints
1856 if (tparam
.Interfaces
!= null) {
1857 if (TypeManager
.IsNullableType (atype
)) {
1858 report
.Error (313, loc
,
1859 "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",
1860 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1862 foreach (TypeSpec iface
in tparam
.Interfaces
) {
1863 CheckConversion (context
, atype
, tparam
, iface
, loc
, report
);
1869 // Finally, check the constructor constraint.
1871 if (!tparam
.HasSpecialConstructor
)
1874 if (!HasDefaultConstructor (atype
)) {
1875 report
.SymbolRelatedToPreviousError (atype
);
1876 report
.Error (310, loc
,
1877 "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
1878 TypeManager
.CSharpName (atype
), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
1885 static void CheckConversion (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, TypeSpec ttype
, Location loc
, Report report
)
1887 var expr
= new EmptyExpression (atype
);
1888 if (!Convert
.ImplicitStandardConversionExists (expr
, ttype
)) {
1889 report
.SymbolRelatedToPreviousError (tparam
);
1890 if (TypeManager
.IsValueType (atype
)) {
1891 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}'",
1892 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1893 } else if (atype
.IsGenericParameter
) {
1894 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}'",
1895 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1897 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}'",
1898 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
1903 static bool HasDefaultConstructor (TypeSpec atype
)
1905 var tp
= atype
as TypeParameterSpec
;
1907 return tp
.HasSpecialConstructor
|| tp
.HasSpecialStruct
;
1910 if (atype
.IsStruct
|| atype
.IsEnum
)
1913 if (atype
.IsAbstract
)
1916 var tdef
= atype
.GetDefinition ();
1919 // In some circumstances MemberCache is not yet populated and members
1920 // cannot be defined yet (recursive type new constraints)
1922 // class A<T> where T : B<T>, new () {}
1923 // class B<T> where T : A<T>, new () {}
1925 var tc
= tdef
.MemberDefinition
as Class
;
1927 if (tc
.InstanceConstructors
== null) {
1928 // Default ctor will be generated later
1932 foreach (var c
in tc
.InstanceConstructors
) {
1933 if (c
.ParameterInfo
.IsEmpty
) {
1934 if ((c
.ModFlags
& Modifiers
.PUBLIC
) != 0)
1942 var found
= MemberCache
.FindMember (tdef
,
1943 MemberFilter
.Constructor (ParametersCompiled
.EmptyReadOnlyParameters
),
1944 BindingRestriction
.DeclaredOnly
| BindingRestriction
.InstanceOnly
);
1946 return found
!= null && (found
.Modifiers
& Modifiers
.PUBLIC
) != 0;
1951 /// A generic method definition.
1953 public class GenericMethod
: DeclSpace
1955 ParametersCompiled parameters
;
1957 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1958 FullNamedExpression return_type
, ParametersCompiled parameters
)
1959 : base (ns
, parent
, name
, null)
1961 this.parameters
= parameters
;
1964 public GenericMethod (NamespaceEntry ns
, DeclSpace parent
, MemberName name
, TypeParameter
[] tparams
,
1965 FullNamedExpression return_type
, ParametersCompiled parameters
)
1966 : this (ns
, parent
, name
, return_type
, parameters
)
1968 this.type_params
= tparams
;
1971 public override TypeParameter
[] CurrentTypeParameters
{
1973 return base.type_params
;
1977 public override TypeBuilder
DefineType ()
1979 throw new Exception ();
1982 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
1984 throw new NotSupportedException ();
1987 public override bool Define ()
1989 throw new NotSupportedException ();
1993 /// Define and resolve the type parameters.
1994 /// We're called from Method.Define().
1996 public bool Define (MethodOrOperator m
)
1998 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1999 string[] snames
= new string [names
.Length
];
2000 for (int i
= 0; i
< names
.Length
; i
++) {
2001 string type_argument_name
= names
[i
].Name
;
2002 int idx
= parameters
.GetParameterIndexByName (type_argument_name
);
2007 b
= new ToplevelBlock (Compiler
, Location
);
2009 b
.Error_AlreadyDeclaredTypeParameter (parameters
[i
].Location
,
2010 type_argument_name
, "method parameter");
2013 if (m
.Block
!= null) {
2014 var ikv
= m
.Block
.GetKnownVariable (type_argument_name
);
2016 ikv
.Block
.Error_AlreadyDeclaredTypeParameter (ikv
.Location
, type_argument_name
, "local variable");
2019 snames
[i
] = type_argument_name
;
2022 GenericTypeParameterBuilder
[] gen_params
= m
.MethodBuilder
.DefineGenericParameters (snames
);
2023 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
2024 TypeParameters
[i
].Define (gen_params
[i
], null);
2029 public void EmitAttributes ()
2031 if (OptAttributes
!= null)
2032 OptAttributes
.Emit ();
2035 public override string GetSignatureForError ()
2037 return base.GetSignatureForError () + parameters
.GetSignatureForError ();
2040 public override AttributeTargets AttributeTargets
{
2042 return AttributeTargets
.Method
| AttributeTargets
.ReturnValue
;
2046 public override string DocCommentHeader
{
2047 get { return "M:"; }
2050 public new void VerifyClsCompliance ()
2052 foreach (TypeParameter tp
in TypeParameters
) {
2053 tp
.VerifyClsCompliance ();
2058 public partial class TypeManager
2060 public static Variance
CheckTypeVariance (TypeSpec t
, Variance expected
, IMemberContext member
)
2062 var tp
= t
as TypeParameterSpec
;
2064 Variance v
= tp
.Variance
;
2065 if (expected
== Variance
.None
&& v
!= expected
||
2066 expected
== Variance
.Covariant
&& v
== Variance
.Contravariant
||
2067 expected
== Variance
.Contravariant
&& v
== Variance
.Covariant
) {
2068 ((TypeParameter
)tp
.MemberDefinition
).ErrorInvalidVariance (member
, expected
);
2074 if (t
.TypeArguments
.Length
> 0) {
2075 var targs_definition
= t
.MemberDefinition
.TypeParameters
;
2076 TypeSpec
[] targs
= GetTypeArguments (t
);
2077 for (int i
= 0; i
< targs
.Length
; ++i
) {
2078 Variance v
= targs_definition
[i
].Variance
;
2079 CheckTypeVariance (targs
[i
], (Variance
) ((int)v
* (int)expected
), member
);
2086 return CheckTypeVariance (GetElementType (t
), expected
, member
);
2088 return Variance
.None
;
2092 /// Type inference. Try to infer the type arguments from `method',
2093 /// which is invoked with the arguments `arguments'. This is used
2094 /// when resolving an Invocation or a DelegateInvocation and the user
2095 /// did not explicitly specify type arguments.
2097 public static int InferTypeArguments (ResolveContext ec
, Arguments arguments
, ref MethodSpec method
)
2099 ATypeInference ti
= ATypeInference
.CreateInstance (arguments
);
2100 TypeSpec
[] i_args
= ti
.InferMethodArguments (ec
, method
);
2102 return ti
.InferenceScore
;
2104 if (i_args
.Length
== 0)
2107 method
= method
.MakeGenericMethod (i_args
);
2112 abstract class ATypeInference
2114 protected readonly Arguments arguments
;
2115 protected readonly int arg_count
;
2117 protected ATypeInference (Arguments arguments
)
2119 this.arguments
= arguments
;
2120 if (arguments
!= null)
2121 arg_count
= arguments
.Count
;
2124 public static ATypeInference
CreateInstance (Arguments arguments
)
2126 return new TypeInference (arguments
);
2129 public virtual int InferenceScore
{
2131 return int.MaxValue
;
2135 public abstract TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
);
2139 // Implements C# type inference
2141 class TypeInference
: ATypeInference
2144 // Tracks successful rate of type inference
2146 int score
= int.MaxValue
;
2148 public TypeInference (Arguments arguments
)
2153 public override int InferenceScore
{
2159 public override TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
)
2161 var method_generic_args
= method
.GenericDefinition
.TypeParameters
;
2162 TypeInferenceContext context
= new TypeInferenceContext (method_generic_args
);
2163 if (!context
.UnfixedVariableExists
)
2164 return TypeSpec
.EmptyTypes
;
2166 AParametersCollection pd
= method
.Parameters
;
2167 if (!InferInPhases (ec
, context
, pd
))
2170 return context
.InferredTypeArguments
;
2174 // Implements method type arguments inference
2176 bool InferInPhases (ResolveContext ec
, TypeInferenceContext tic
, AParametersCollection methodParameters
)
2178 int params_arguments_start
;
2179 if (methodParameters
.HasParams
) {
2180 params_arguments_start
= methodParameters
.Count
- 1;
2182 params_arguments_start
= arg_count
;
2185 TypeSpec
[] ptypes
= methodParameters
.Types
;
2188 // The first inference phase
2190 TypeSpec method_parameter
= null;
2191 for (int i
= 0; i
< arg_count
; i
++) {
2192 Argument a
= arguments
[i
];
2196 if (i
< params_arguments_start
) {
2197 method_parameter
= methodParameters
.Types
[i
];
2198 } else if (i
== params_arguments_start
) {
2199 if (arg_count
== params_arguments_start
+ 1 && TypeManager
.HasElementType (a
.Type
))
2200 method_parameter
= methodParameters
.Types
[params_arguments_start
];
2202 method_parameter
= TypeManager
.GetElementType (methodParameters
.Types
[params_arguments_start
]);
2204 ptypes
= (TypeSpec
[]) ptypes
.Clone ();
2205 ptypes
[i
] = method_parameter
;
2209 // When a lambda expression, an anonymous method
2210 // is used an explicit argument type inference takes a place
2212 AnonymousMethodExpression am
= a
.Expr
as AnonymousMethodExpression
;
2214 if (am
.ExplicitTypeInference (ec
, tic
, method_parameter
))
2220 score
-= tic
.ExactInference (a
.Type
, method_parameter
);
2224 if (a
.Expr
.Type
== InternalType
.Null
)
2227 if (TypeManager
.IsValueType (method_parameter
)) {
2228 score
-= tic
.LowerBoundInference (a
.Type
, method_parameter
);
2233 // Otherwise an output type inference is made
2235 score
-= tic
.OutputTypeInference (ec
, a
.Expr
, method_parameter
);
2239 // Part of the second phase but because it happens only once
2240 // we don't need to call it in cycle
2242 bool fixed_any
= false;
2243 if (!tic
.FixIndependentTypeArguments (ec
, ptypes
, ref fixed_any
))
2246 return DoSecondPhase (ec
, tic
, ptypes
, !fixed_any
);
2249 bool DoSecondPhase (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec
[] methodParameters
, bool fixDependent
)
2251 bool fixed_any
= false;
2252 if (fixDependent
&& !tic
.FixDependentTypes (ec
, ref fixed_any
))
2255 // If no further unfixed type variables exist, type inference succeeds
2256 if (!tic
.UnfixedVariableExists
)
2259 if (!fixed_any
&& fixDependent
)
2262 // For all arguments where the corresponding argument output types
2263 // contain unfixed type variables but the input types do not,
2264 // an output type inference is made
2265 for (int i
= 0; i
< arg_count
; i
++) {
2267 // Align params arguments
2268 TypeSpec t_i
= methodParameters
[i
>= methodParameters
.Length
? methodParameters
.Length
- 1: i
];
2270 if (!TypeManager
.IsDelegateType (t_i
)) {
2271 if (t_i
.GetDefinition () != TypeManager
.expression_type
)
2274 t_i
= TypeManager
.GetTypeArguments (t_i
) [0];
2277 var mi
= Delegate
.GetInvokeMethod (ec
.Compiler
, t_i
);
2278 TypeSpec rtype
= mi
.ReturnType
;
2280 if (tic
.IsReturnTypeNonDependent (ec
, mi
, rtype
))
2281 score
-= tic
.OutputTypeInference (ec
, arguments
[i
].Expr
, t_i
);
2285 return DoSecondPhase (ec
, tic
, methodParameters
, true);
2289 public class TypeInferenceContext
2300 public readonly TypeSpec Type
;
2301 public readonly BoundKind Kind
;
2303 public BoundInfo (TypeSpec type
, BoundKind kind
)
2309 public override int GetHashCode ()
2311 return Type
.GetHashCode ();
2314 public override bool Equals (object obj
)
2316 BoundInfo a
= (BoundInfo
) obj
;
2317 return Type
== a
.Type
&& Kind
== a
.Kind
;
2321 readonly TypeSpec
[] unfixed_types
;
2322 readonly TypeSpec
[] fixed_types
;
2323 readonly List
<BoundInfo
>[] bounds
;
2326 // TODO MemberCache: Could it be TypeParameterSpec[] ??
2327 public TypeInferenceContext (TypeSpec
[] typeArguments
)
2329 if (typeArguments
.Length
== 0)
2330 throw new ArgumentException ("Empty generic arguments");
2332 fixed_types
= new TypeSpec
[typeArguments
.Length
];
2333 for (int i
= 0; i
< typeArguments
.Length
; ++i
) {
2334 if (typeArguments
[i
].IsGenericParameter
) {
2335 if (bounds
== null) {
2336 bounds
= new List
<BoundInfo
> [typeArguments
.Length
];
2337 unfixed_types
= new TypeSpec
[typeArguments
.Length
];
2339 unfixed_types
[i
] = typeArguments
[i
];
2341 fixed_types
[i
] = typeArguments
[i
];
2347 // Used together with AddCommonTypeBound fo implement
2348 // 7.4.2.13 Finding the best common type of a set of expressions
2350 public TypeInferenceContext ()
2352 fixed_types
= new TypeSpec
[1];
2353 unfixed_types
= new TypeSpec
[1];
2354 unfixed_types
[0] = InternalType
.Arglist
; // it can be any internal type
2355 bounds
= new List
<BoundInfo
> [1];
2358 public TypeSpec
[] InferredTypeArguments
{
2364 public void AddCommonTypeBound (TypeSpec type
)
2366 AddToBounds (new BoundInfo (type
, BoundKind
.Lower
), 0);
2369 void AddToBounds (BoundInfo bound
, int index
)
2372 // Some types cannot be used as type arguments
2374 if (bound
.Type
== TypeManager
.void_type
|| bound
.Type
.IsPointer
)
2377 var a
= bounds
[index
];
2379 a
= new List
<BoundInfo
> ();
2382 if (a
.Contains (bound
))
2387 // SPEC: does not cover type inference using constraints
2389 //if (TypeManager.IsGenericParameter (t)) {
2390 // GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
2391 // if (constraints != null) {
2392 // //if (constraints.EffectiveBaseClass != null)
2393 // // t = constraints.EffectiveBaseClass;
2399 bool AllTypesAreFixed (TypeSpec
[] types
)
2401 foreach (TypeSpec t
in types
) {
2402 if (t
.IsGenericParameter
) {
2408 if (TypeManager
.IsGenericType (t
))
2409 return AllTypesAreFixed (TypeManager
.GetTypeArguments (t
));
2416 // 26.3.3.8 Exact Inference
2418 public int ExactInference (TypeSpec u
, TypeSpec v
)
2420 // If V is an array type
2425 // TODO MemberCache: GetMetaInfo ()
2426 if (u
.GetMetaInfo ().GetArrayRank () != v
.GetMetaInfo ().GetArrayRank ())
2429 return ExactInference (TypeManager
.GetElementType (u
), TypeManager
.GetElementType (v
));
2432 // If V is constructed type and U is constructed type
2433 if (TypeManager
.IsGenericType (v
)) {
2434 if (!TypeManager
.IsGenericType (u
))
2437 TypeSpec
[] ga_u
= TypeManager
.GetTypeArguments (u
);
2438 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2439 if (ga_u
.Length
!= ga_v
.Length
)
2443 for (int i
= 0; i
< ga_u
.Length
; ++i
)
2444 score
+= ExactInference (ga_u
[i
], ga_v
[i
]);
2446 return score
> 0 ? 1 : 0;
2449 // If V is one of the unfixed type arguments
2450 int pos
= IsUnfixed (v
);
2454 AddToBounds (new BoundInfo (u
, BoundKind
.Exact
), pos
);
2458 public bool FixAllTypes (ResolveContext ec
)
2460 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2461 if (!FixType (ec
, i
))
2468 // All unfixed type variables Xi are fixed for which all of the following hold:
2469 // a, There is at least one type variable Xj that depends on Xi
2470 // b, Xi has a non-empty set of bounds
2472 public bool FixDependentTypes (ResolveContext ec
, ref bool fixed_any
)
2474 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2475 if (unfixed_types
[i
] == null)
2478 if (bounds
[i
] == null)
2481 if (!FixType (ec
, i
))
2491 // All unfixed type variables Xi which depend on no Xj are fixed
2493 public bool FixIndependentTypeArguments (ResolveContext ec
, TypeSpec
[] methodParameters
, ref bool fixed_any
)
2495 var types_to_fix
= new List
<TypeSpec
> (unfixed_types
);
2496 for (int i
= 0; i
< methodParameters
.Length
; ++i
) {
2497 TypeSpec t
= methodParameters
[i
];
2499 if (!TypeManager
.IsDelegateType (t
)) {
2500 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2503 t
= TypeManager
.GetTypeArguments (t
) [0];
2506 if (t
.IsGenericParameter
)
2509 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2510 TypeSpec rtype
= invoke
.ReturnType
;
2511 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2514 // Remove dependent types, they cannot be fixed yet
2515 RemoveDependentTypes (types_to_fix
, rtype
);
2518 foreach (TypeSpec t
in types_to_fix
) {
2522 int idx
= IsUnfixed (t
);
2523 if (idx
>= 0 && !FixType (ec
, idx
)) {
2528 fixed_any
= types_to_fix
.Count
> 0;
2535 public bool FixType (ResolveContext ec
, int i
)
2537 // It's already fixed
2538 if (unfixed_types
[i
] == null)
2539 throw new InternalErrorException ("Type argument has been already fixed");
2544 var candidates
= bounds
[i
];
2545 if (candidates
== null)
2548 if (candidates
.Count
== 1) {
2549 unfixed_types
[i
] = null;
2550 TypeSpec t
= candidates
[0].Type
;
2551 if (t
== InternalType
.Null
)
2554 fixed_types
[i
] = t
;
2559 // Determines a unique type from which there is
2560 // a standard implicit conversion to all the other
2563 TypeSpec best_candidate
= null;
2565 int candidates_count
= candidates
.Count
;
2566 for (int ci
= 0; ci
< candidates_count
; ++ci
) {
2567 BoundInfo bound
= candidates
[ci
];
2568 for (cii
= 0; cii
< candidates_count
; ++cii
) {
2572 BoundInfo cbound
= candidates
[cii
];
2574 // Same type parameters with different bounds
2575 if (cbound
.Type
== bound
.Type
) {
2576 if (bound
.Kind
!= BoundKind
.Exact
)
2582 if (bound
.Kind
== BoundKind
.Exact
|| cbound
.Kind
== BoundKind
.Exact
) {
2583 if (cbound
.Kind
!= BoundKind
.Exact
) {
2584 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2591 if (bound
.Kind
!= BoundKind
.Exact
) {
2592 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2603 if (bound
.Kind
== BoundKind
.Lower
) {
2604 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (cbound
.Type
, Location
.Null
), bound
.Type
)) {
2608 if (!Convert
.ImplicitConversionExists (ec
, new TypeExpression (bound
.Type
, Location
.Null
), cbound
.Type
)) {
2614 if (cii
!= candidates_count
)
2617 if (best_candidate
!= null && best_candidate
!= bound
.Type
)
2620 best_candidate
= bound
.Type
;
2623 if (best_candidate
== null)
2626 unfixed_types
[i
] = null;
2627 fixed_types
[i
] = best_candidate
;
2632 // Uses inferred or partially infered types to inflate delegate type argument. Returns
2633 // null when type parameter was not yet inferres
2635 public TypeSpec
InflateGenericArgument (TypeSpec parameter
)
2637 var tp
= parameter
as TypeParameterSpec
;
2640 // Type inference work on generic arguments (MVAR) only
2642 if (!tp
.IsMethodOwned
)
2645 return fixed_types
[tp
.DeclaredPosition
] ?? parameter
;
2648 var gt
= parameter
as InflatedTypeSpec
;
2650 var inflated_targs
= new TypeSpec
[gt
.TypeArguments
.Length
];
2651 for (int ii
= 0; ii
< inflated_targs
.Length
; ++ii
) {
2652 var inflated
= InflateGenericArgument (gt
.TypeArguments
[ii
]);
2653 if (inflated
== null)
2656 inflated_targs
[ii
] = inflated
;
2659 return gt
.GetDefinition ().MakeGenericType (inflated_targs
);
2666 // Tests whether all delegate input arguments are fixed and generic output type
2667 // requires output type inference
2669 public bool IsReturnTypeNonDependent (ResolveContext ec
, MethodSpec invoke
, TypeSpec returnType
)
2671 if (returnType
.IsGenericParameter
) {
2672 if (IsFixed (returnType
))
2674 } else if (TypeManager
.IsGenericType (returnType
)) {
2675 if (TypeManager
.IsDelegateType (returnType
)) {
2676 invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, returnType
);
2677 return IsReturnTypeNonDependent (ec
, invoke
, invoke
.ReturnType
);
2680 TypeSpec
[] g_args
= TypeManager
.GetTypeArguments (returnType
);
2682 // At least one unfixed return type has to exist
2683 if (AllTypesAreFixed (g_args
))
2689 // All generic input arguments have to be fixed
2690 AParametersCollection d_parameters
= invoke
.Parameters
;
2691 return AllTypesAreFixed (d_parameters
.Types
);
2694 bool IsFixed (TypeSpec type
)
2696 return IsUnfixed (type
) == -1;
2699 int IsUnfixed (TypeSpec type
)
2701 if (!type
.IsGenericParameter
)
2704 //return unfixed_types[type.GenericParameterPosition] != null;
2705 for (int i
= 0; i
< unfixed_types
.Length
; ++i
) {
2706 if (unfixed_types
[i
] == type
)
2714 // 26.3.3.9 Lower-bound Inference
2716 public int LowerBoundInference (TypeSpec u
, TypeSpec v
)
2718 return LowerBoundInference (u
, v
, false);
2722 // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
2724 int LowerBoundInference (TypeSpec u
, TypeSpec v
, bool inversed
)
2726 // If V is one of the unfixed type arguments
2727 int pos
= IsUnfixed (v
);
2729 AddToBounds (new BoundInfo (u
, inversed
? BoundKind
.Upper
: BoundKind
.Lower
), pos
);
2733 // If U is an array type
2734 var u_ac
= u
as ArrayContainer
;
2736 var v_ac
= v
as ArrayContainer
;
2738 if (u_ac
.Rank
!= v_ac
.Rank
)
2741 if (TypeManager
.IsValueType (u_ac
.Element
))
2742 return ExactInference (u_ac
.Element
, v_ac
.Element
);
2744 return LowerBoundInference (u_ac
.Element
, v_ac
.Element
, inversed
);
2750 if (TypeManager
.IsGenericType (v
)) {
2751 TypeSpec g_v
= v
.GetDefinition ();
2752 if (g_v
!= TypeManager
.generic_ilist_type
&&
2753 g_v
!= TypeManager
.generic_icollection_type
&&
2754 g_v
!= TypeManager
.generic_ienumerable_type
)
2757 var v_i
= TypeManager
.GetTypeArguments (v
) [0];
2758 if (TypeManager
.IsValueType (u_ac
.Element
))
2759 return ExactInference (u_ac
.Element
, v_i
);
2761 return LowerBoundInference (u_ac
.Element
, v_i
);
2763 } else if (TypeManager
.IsGenericType (v
)) {
2765 // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
2766 // such that U is identical to, inherits from (directly or indirectly),
2767 // or implements (directly or indirectly) C<U1..Uk>
2769 var u_candidates
= new List
<TypeSpec
> ();
2770 var open_v
= v
.MemberDefinition
;
2772 for (TypeSpec t
= u
; t
!= null; t
= t
.BaseType
) {
2773 if (open_v
== t
.MemberDefinition
)
2774 u_candidates
.Add (t
);
2776 if (t
.Interfaces
!= null) {
2777 foreach (var iface
in t
.Interfaces
) {
2778 if (open_v
== iface
.MemberDefinition
)
2779 u_candidates
.Add (iface
);
2784 TypeSpec
[] unique_candidate_targs
= null;
2785 TypeSpec
[] ga_v
= TypeManager
.GetTypeArguments (v
);
2786 foreach (TypeSpec u_candidate
in u_candidates
) {
2788 // The unique set of types U1..Uk means that if we have an interface I<T>,
2789 // class U : I<int>, I<long> then no type inference is made when inferring
2790 // type I<T> by applying type U because T could be int or long
2792 if (unique_candidate_targs
!= null) {
2793 TypeSpec
[] second_unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2794 if (TypeSpecComparer
.Default
.Equals (unique_candidate_targs
, second_unique_candidate_targs
)) {
2795 unique_candidate_targs
= second_unique_candidate_targs
;
2800 // This should always cause type inference failure
2806 unique_candidate_targs
= TypeManager
.GetTypeArguments (u_candidate
);
2809 if (unique_candidate_targs
!= null) {
2810 var ga_open_v
= open_v
.TypeParameters
;
2812 for (int i
= 0; i
< unique_candidate_targs
.Length
; ++i
) {
2813 Variance variance
= ga_open_v
[i
].Variance
;
2815 TypeSpec u_i
= unique_candidate_targs
[i
];
2816 if (variance
== Variance
.None
|| TypeManager
.IsValueType (u_i
)) {
2817 if (ExactInference (u_i
, ga_v
[i
]) == 0)
2820 bool upper_bound
= (variance
== Variance
.Contravariant
&& !inversed
) ||
2821 (variance
== Variance
.Covariant
&& inversed
);
2823 if (LowerBoundInference (u_i
, ga_v
[i
], upper_bound
) == 0)
2835 // 26.3.3.6 Output Type Inference
2837 public int OutputTypeInference (ResolveContext ec
, Expression e
, TypeSpec t
)
2839 // If e is a lambda or anonymous method with inferred return type
2840 AnonymousMethodExpression ame
= e
as AnonymousMethodExpression
;
2842 TypeSpec rt
= ame
.InferReturnType (ec
, this, t
);
2843 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2846 AParametersCollection pd
= invoke
.Parameters
;
2847 return ame
.Parameters
.Count
== pd
.Count
? 1 : 0;
2850 TypeSpec rtype
= invoke
.ReturnType
;
2851 return LowerBoundInference (rt
, rtype
) + 1;
2855 // if E is a method group and T is a delegate type or expression tree type
2856 // return type Tb with parameter types T1..Tk and return type Tb, and overload
2857 // resolution of E with the types T1..Tk yields a single method with return type U,
2858 // then a lower-bound inference is made from U for Tb.
2860 if (e
is MethodGroupExpr
) {
2861 if (!TypeManager
.IsDelegateType (t
)) {
2862 if (TypeManager
.expression_type
== null || t
.MemberDefinition
!= TypeManager
.expression_type
.MemberDefinition
)
2865 t
= TypeManager
.GetTypeArguments (t
)[0];
2868 var invoke
= Delegate
.GetInvokeMethod (ec
.Compiler
, t
);
2869 TypeSpec rtype
= invoke
.ReturnType
;
2871 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
2874 // LAMESPEC: Standard does not specify that all methodgroup arguments
2875 // has to be fixed but it does not specify how to do recursive type inference
2876 // either. We choose the simple option and infer return type only
2877 // if all delegate generic arguments are fixed.
2878 TypeSpec
[] param_types
= new TypeSpec
[invoke
.Parameters
.Count
];
2879 for (int i
= 0; i
< param_types
.Length
; ++i
) {
2880 var inflated
= InflateGenericArgument (invoke
.Parameters
.Types
[i
]);
2881 if (inflated
== null)
2884 param_types
[i
] = inflated
;
2887 MethodGroupExpr mg
= (MethodGroupExpr
) e
;
2888 Arguments args
= DelegateCreation
.CreateDelegateMethodArguments (invoke
.Parameters
, param_types
, e
.Location
);
2889 mg
= mg
.OverloadResolve (ec
, ref args
, true, e
.Location
);
2893 return LowerBoundInference (mg
.BestCandidate
.ReturnType
, rtype
) + 1;
2897 // if e is an expression with type U, then
2898 // a lower-bound inference is made from U for T
2900 return LowerBoundInference (e
.Type
, t
) * 2;
2903 void RemoveDependentTypes (List
<TypeSpec
> types
, TypeSpec returnType
)
2905 int idx
= IsUnfixed (returnType
);
2911 if (TypeManager
.IsGenericType (returnType
)) {
2912 foreach (TypeSpec t
in TypeManager
.GetTypeArguments (returnType
)) {
2913 RemoveDependentTypes (types
, t
);
2918 public bool UnfixedVariableExists
{
2920 if (unfixed_types
== null)
2923 foreach (TypeSpec ut
in unfixed_types
)