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
12 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
16 using System
.Collections
.Generic
;
21 using MetaType
= IKVM
.Reflection
.Type
;
22 using IKVM
.Reflection
;
23 using IKVM
.Reflection
.Emit
;
25 using MetaType
= System
.Type
;
26 using System
.Reflection
;
27 using System
.Reflection
.Emit
;
30 namespace Mono
.CSharp
{
31 public class VarianceDecl
33 public VarianceDecl (Variance variance
, Location loc
)
35 this.Variance
= variance
;
39 public Variance Variance { get; private set; }
40 public Location Location { get; private set; }
42 public static Variance
CheckTypeVariance (TypeSpec t
, Variance expected
, IMemberContext member
)
44 var tp
= t
as TypeParameterSpec
;
47 if (expected
== Variance
.None
&& v
!= expected
||
48 expected
== Variance
.Covariant
&& v
== Variance
.Contravariant
||
49 expected
== Variance
.Contravariant
&& v
== Variance
.Covariant
) {
50 ((TypeParameter
) tp
.MemberDefinition
).ErrorInvalidVariance (member
, expected
);
56 if (t
.TypeArguments
.Length
> 0) {
57 var targs_definition
= t
.MemberDefinition
.TypeParameters
;
58 TypeSpec
[] targs
= TypeManager
.GetTypeArguments (t
);
59 for (int i
= 0; i
< targs
.Length
; ++i
) {
60 var v
= targs_definition
[i
].Variance
;
61 CheckTypeVariance (targs
[i
], (Variance
) ((int) v
* (int) expected
), member
);
67 var ac
= t
as ArrayContainer
;
69 return CheckTypeVariance (ac
.Element
, expected
, member
);
78 // Don't add or modify internal values, they are used as -/+ calculation signs
86 public enum SpecialConstraint
94 public class SpecialContraintExpr
: FullNamedExpression
96 public SpecialContraintExpr (SpecialConstraint constraint
, Location loc
)
99 this.Constraint
= constraint
;
102 public SpecialConstraint Constraint { get; private set; }
104 protected override Expression
DoResolve (ResolveContext rc
)
106 throw new NotImplementedException ();
109 public override FullNamedExpression
ResolveAsTypeOrNamespace (IMemberContext mc
, bool allowUnboundTypeArguments
)
111 throw new NotImplementedException ();
116 // A set of parsed constraints for a type parameter
118 public class Constraints
120 readonly SimpleMemberName tparam
;
121 readonly List
<FullNamedExpression
> constraints
;
122 readonly Location loc
;
126 public Constraints (SimpleMemberName tparam
, List
<FullNamedExpression
> constraints
, Location loc
)
128 this.tparam
= tparam
;
129 this.constraints
= constraints
;
135 public List
<FullNamedExpression
> TypeExpressions
{
141 public Location Location
{
147 public SimpleMemberName TypeParameter
{
155 public static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec
, TypeSpec bb
, IMemberContext context
, Location loc
)
157 if (spec
.HasSpecialClass
&& bb
.IsStruct
) {
158 context
.Module
.Compiler
.Report
.Error (455, loc
,
159 "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
160 spec
.Name
, "class", bb
.GetSignatureForError ());
165 return CheckConflictingInheritedConstraint (spec
, spec
.BaseType
, bb
, context
, loc
);
168 static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec
, TypeSpec ba
, TypeSpec bb
, IMemberContext context
, Location loc
)
173 if (TypeSpec
.IsBaseClass (ba
, bb
, false) || TypeSpec
.IsBaseClass (bb
, ba
, false))
176 Error_ConflictingConstraints (context
, spec
, ba
, bb
, loc
);
180 public static void Error_ConflictingConstraints (IMemberContext context
, TypeParameterSpec tp
, TypeSpec ba
, TypeSpec bb
, Location loc
)
182 context
.Module
.Compiler
.Report
.Error (455, loc
,
183 "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
184 tp
.Name
, ba
.GetSignatureForError (), bb
.GetSignatureForError ());
187 public void CheckGenericConstraints (IMemberContext context
, bool obsoleteCheck
)
189 foreach (var c
in constraints
) {
198 t
.CheckObsoleteness (context
, c
.Location
);
201 ConstraintChecker
.Check (context
, t
, c
.Location
);
206 // Resolve the constraints types with only possible early checks, return
207 // value `false' is reserved for recursive failure
209 public bool Resolve (IMemberContext context
, TypeParameter tp
)
219 List
<TypeParameterSpec
> tparam_types
= null;
220 bool iface_found
= false;
222 spec
.BaseType
= context
.Module
.Compiler
.BuiltinTypes
.Object
;
224 for (int i
= 0; i
< constraints
.Count
; ++i
) {
225 var constraint
= constraints
[i
];
227 if (constraint
is SpecialContraintExpr
) {
228 spec
.SpecialConstraint
|= ((SpecialContraintExpr
) constraint
).Constraint
;
229 if (spec
.HasSpecialStruct
)
230 spec
.BaseType
= context
.Module
.Compiler
.BuiltinTypes
.ValueType
;
232 // Set to null as it does not have a type
233 constraints
[i
] = null;
237 var type
= constraint
.ResolveAsType (context
);
241 if (type
.Arity
> 0 && ((InflatedTypeSpec
) type
).HasDynamicArgument ()) {
242 context
.Module
.Compiler
.Report
.Error (1968, constraint
.Location
,
243 "A constraint cannot be the dynamic type `{0}'", type
.GetSignatureForError ());
247 if (!context
.CurrentMemberDefinition
.IsAccessibleAs (type
)) {
248 context
.Module
.Compiler
.Report
.SymbolRelatedToPreviousError (type
);
249 context
.Module
.Compiler
.Report
.Error (703, loc
,
250 "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
251 type
.GetSignatureForError (), context
.GetSignatureForError ());
254 if (type
.IsInterface
) {
255 if (!spec
.AddInterface (type
)) {
256 context
.Module
.Compiler
.Report
.Error (405, constraint
.Location
,
257 "Duplicate constraint `{0}' for type parameter `{1}'", type
.GetSignatureForError (), tparam
.Value
);
264 var constraint_tp
= type
as TypeParameterSpec
;
265 if (constraint_tp
!= null) {
266 if (tparam_types
== null) {
267 tparam_types
= new List
<TypeParameterSpec
> (2);
268 } else if (tparam_types
.Contains (constraint_tp
)) {
269 context
.Module
.Compiler
.Report
.Error (405, constraint
.Location
,
270 "Duplicate constraint `{0}' for type parameter `{1}'", type
.GetSignatureForError (), tparam
.Value
);
275 // Checks whether each generic method parameter constraint type
276 // is valid with respect to T
278 if (tp
.IsMethodTypeParameter
) {
279 VarianceDecl
.CheckTypeVariance (type
, Variance
.Contravariant
, context
);
282 var tp_def
= constraint_tp
.MemberDefinition
as TypeParameter
;
283 if (tp_def
!= null && !tp_def
.ResolveConstraints (context
)) {
284 context
.Module
.Compiler
.Report
.Error (454, constraint
.Location
,
285 "Circular constraint dependency involving `{0}' and `{1}'",
286 constraint_tp
.GetSignatureForError (), tp
.GetSignatureForError ());
291 // Checks whether there are no conflicts between type parameter constraints
297 // A and B are not convertible and only 1 class constraint is allowed
299 if (constraint_tp
.HasTypeConstraint
) {
300 if (spec
.HasTypeConstraint
|| spec
.HasSpecialStruct
) {
301 if (!CheckConflictingInheritedConstraint (spec
, constraint_tp
.BaseType
, context
, constraint
.Location
))
304 for (int ii
= 0; ii
< tparam_types
.Count
; ++ii
) {
305 if (!tparam_types
[ii
].HasTypeConstraint
)
308 if (!CheckConflictingInheritedConstraint (spec
, tparam_types
[ii
].BaseType
, constraint_tp
.BaseType
, context
, constraint
.Location
))
314 if (constraint_tp
.TypeArguments
!= null) {
315 var eb
= constraint_tp
.GetEffectiveBase ();
316 if (eb
!= null && !CheckConflictingInheritedConstraint (spec
, eb
, spec
.BaseType
, context
, constraint
.Location
))
320 if (constraint_tp
.HasSpecialStruct
) {
321 context
.Module
.Compiler
.Report
.Error (456, constraint
.Location
,
322 "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
323 constraint_tp
.GetSignatureForError (), tp
.GetSignatureForError ());
327 tparam_types
.Add (constraint_tp
);
331 if (iface_found
|| spec
.HasTypeConstraint
) {
332 context
.Module
.Compiler
.Report
.Error (406, constraint
.Location
,
333 "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
334 type
.GetSignatureForError ());
337 if (spec
.HasSpecialStruct
|| spec
.HasSpecialClass
) {
338 context
.Module
.Compiler
.Report
.Error (450, constraint
.Location
,
339 "`{0}': cannot specify both a constraint class and the `class' or `struct' constraint",
340 type
.GetSignatureForError ());
343 switch (type
.BuiltinType
) {
344 case BuiltinTypeSpec
.Type
.Array
:
345 case BuiltinTypeSpec
.Type
.Delegate
:
346 case BuiltinTypeSpec
.Type
.MulticastDelegate
:
347 case BuiltinTypeSpec
.Type
.Enum
:
348 case BuiltinTypeSpec
.Type
.ValueType
:
349 case BuiltinTypeSpec
.Type
.Object
:
350 context
.Module
.Compiler
.Report
.Error (702, constraint
.Location
,
351 "A constraint cannot be special class `{0}'", type
.GetSignatureForError ());
353 case BuiltinTypeSpec
.Type
.Dynamic
:
354 context
.Module
.Compiler
.Report
.Error (1967, constraint
.Location
,
355 "A constraint cannot be the dynamic type");
359 if (type
.IsSealed
|| !type
.IsClass
) {
360 context
.Module
.Compiler
.Report
.Error (701, loc
,
361 "`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter",
362 type
.GetSignatureForError ());
367 context
.Module
.Compiler
.Report
.Error (717, constraint
.Location
,
368 "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
369 type
.GetSignatureForError ());
372 spec
.BaseType
= type
;
375 if (tparam_types
!= null)
376 spec
.TypeArguments
= tparam_types
.ToArray ();
383 public void VerifyClsCompliance (Report report
)
385 foreach (var c
in constraints
)
390 if (!c
.Type
.IsCLSCompliant ()) {
391 report
.SymbolRelatedToPreviousError (c
.Type
);
392 report
.Warning (3024, 1, loc
, "Constraint type `{0}' is not CLS-compliant",
393 c
.Type
.GetSignatureForError ());
400 // A type parameter for a generic type or generic method definition
402 public class TypeParameter
: MemberCore
, ITypeDefinition
404 static readonly string[] attribute_target
= { "type parameter" }
;
406 Constraints constraints
;
407 GenericTypeParameterBuilder builder
;
408 readonly TypeParameterSpec spec
;
410 public TypeParameter (int index
, MemberName name
, Constraints constraints
, Attributes attrs
, Variance Variance
)
411 : base (null, name
, attrs
)
413 this.constraints
= constraints
;
414 this.spec
= new TypeParameterSpec (null, index
, this, SpecialConstraint
.None
, Variance
, null);
420 public TypeParameter (MemberName name
, Attributes attrs
, VarianceDecl variance
)
421 : base (null, name
, attrs
)
423 var var = variance
== null ? Variance
.None
: variance
.Variance
;
424 this.spec
= new TypeParameterSpec (null, -1, this, SpecialConstraint
.None
, var, null);
425 this.VarianceDecl
= variance
;
428 public TypeParameter (TypeParameterSpec spec
, TypeSpec parentSpec
, MemberName name
, Attributes attrs
)
429 : base (null, name
, attrs
)
431 this.spec
= new TypeParameterSpec (parentSpec
, spec
.DeclaredPosition
, this, spec
.SpecialConstraint
, spec
.Variance
, null) {
432 BaseType
= spec
.BaseType
,
433 InterfacesDefined
= spec
.InterfacesDefined
,
434 TypeArguments
= spec
.TypeArguments
440 public override AttributeTargets AttributeTargets
{
442 return AttributeTargets
.GenericParameter
;
446 public Constraints Constraints
{
455 public IAssemblyDefinition DeclaringAssembly
{
457 return Module
.DeclaringAssembly
;
461 public override string DocCommentHeader
{
463 throw new InvalidOperationException (
464 "Unexpected attempt to get doc comment from " + this.GetType ());
468 bool ITypeDefinition
.IsComImport
{
474 bool ITypeDefinition
.IsPartial
{
480 public bool IsMethodTypeParameter
{
482 return spec
.IsMethodOwned
;
486 bool ITypeDefinition
.IsTypeForwarder
{
492 bool ITypeDefinition
.IsCyclicTypeForwarder
{
500 return MemberName
.Name
;
504 public string Namespace
{
510 public TypeParameterSpec Type
{
516 public int TypeParametersCount
{
522 public TypeParameterSpec
[] TypeParameters
{
528 public override string[] ValidAttributeTargets
{
530 return attribute_target
;
534 public Variance Variance
{
536 return spec
.Variance
;
540 public VarianceDecl VarianceDecl { get; private set; }
545 // This is called for each part of a partial generic type definition.
547 // If partial type parameters constraints are not null and we don't
548 // already have constraints they become our constraints. If we already
549 // have constraints, we must check that they're same.
551 public bool AddPartialConstraints (TypeDefinition part
, TypeParameter tp
)
554 throw new InvalidOperationException ();
556 var new_constraints
= tp
.constraints
;
557 if (new_constraints
== null)
560 // TODO: could create spec only
561 //tp.Define (null, -1, part.Definition);
562 tp
.spec
.DeclaringType
= part
.Definition
;
563 if (!tp
.ResolveConstraints (part
))
566 if (constraints
!= null)
567 return spec
.HasSameConstraintsDefinition (tp
.Type
);
569 // Copy constraint from resolved part to partial container
570 spec
.SpecialConstraint
= tp
.spec
.SpecialConstraint
;
571 spec
.InterfacesDefined
= tp
.spec
.InterfacesDefined
;
572 spec
.TypeArguments
= tp
.spec
.TypeArguments
;
573 spec
.BaseType
= tp
.spec
.BaseType
;
578 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
580 builder
.SetCustomAttribute ((ConstructorInfo
) ctor
.GetMetaInfo (), cdata
);
583 public void CheckGenericConstraints (bool obsoleteCheck
)
585 if (constraints
!= null)
586 constraints
.CheckGenericConstraints (this, obsoleteCheck
);
589 public TypeParameter
CreateHoistedCopy (TypeSpec declaringSpec
)
591 return new TypeParameter (spec
, declaringSpec
, MemberName
, null);
594 public override bool Define ()
600 // This is the first method which is called during the resolving
601 // process; we're called immediately after creating the type parameters
602 // with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
605 public void Create (TypeSpec declaringType
, TypeContainer parent
)
608 throw new InternalErrorException ();
610 // Needed to get compiler reference
611 this.Parent
= parent
;
612 spec
.DeclaringType
= declaringType
;
615 public void Define (GenericTypeParameterBuilder type
)
618 spec
.SetMetaInfo (type
);
621 public void Define (TypeParameter tp
)
623 builder
= tp
.builder
;
626 public void EmitConstraints (GenericTypeParameterBuilder builder
)
628 var attr
= GenericParameterAttributes
.None
;
629 if (spec
.Variance
== Variance
.Contravariant
)
630 attr
|= GenericParameterAttributes
.Contravariant
;
631 else if (spec
.Variance
== Variance
.Covariant
)
632 attr
|= GenericParameterAttributes
.Covariant
;
634 if (spec
.HasSpecialClass
)
635 attr
|= GenericParameterAttributes
.ReferenceTypeConstraint
;
636 else if (spec
.HasSpecialStruct
)
637 attr
|= GenericParameterAttributes
.NotNullableValueTypeConstraint
| GenericParameterAttributes
.DefaultConstructorConstraint
;
639 if (spec
.HasSpecialConstructor
)
640 attr
|= GenericParameterAttributes
.DefaultConstructorConstraint
;
642 if (spec
.BaseType
.BuiltinType
!= BuiltinTypeSpec
.Type
.Object
)
643 builder
.SetBaseTypeConstraint (spec
.BaseType
.GetMetaInfo ());
645 if (spec
.InterfacesDefined
!= null)
646 builder
.SetInterfaceConstraints (spec
.InterfacesDefined
.Select (l
=> l
.GetMetaInfo ()).ToArray ());
648 if (spec
.TypeArguments
!= null) {
649 var meta_constraints
= new List
<MetaType
> (spec
.TypeArguments
.Length
);
650 foreach (var c
in spec
.TypeArguments
) {
652 // Inflated type parameters can collide with base type constraint, don't
653 // emit any such type parameter.
655 if (c
.IsClass
&& spec
.BaseType
.BuiltinType
!= BuiltinTypeSpec
.Type
.Object
)
658 meta_constraints
.Add (c
.GetMetaInfo ());
661 builder
.SetInterfaceConstraints (meta_constraints
.ToArray ());
664 builder
.SetGenericParameterAttributes (attr
);
667 public override void Emit ()
669 EmitConstraints (builder
);
671 if (OptAttributes
!= null)
672 OptAttributes
.Emit ();
677 public void ErrorInvalidVariance (IMemberContext mc
, Variance expected
)
679 Report
.SymbolRelatedToPreviousError (mc
.CurrentMemberDefinition
);
680 string input_variance
= Variance
== Variance
.Contravariant
? "contravariant" : "covariant";
681 string gtype_variance
;
683 case Variance
.Contravariant
: gtype_variance
= "contravariantly"; break;
684 case Variance
.Covariant
: gtype_variance
= "covariantly"; break;
685 default: gtype_variance
= "invariantly"; break;
688 Delegate d
= mc
as Delegate
;
689 string parameters
= d
!= null ? d
.Parameters
.GetSignatureForError () : "";
691 Report
.Error (1961, Location
,
692 "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'",
693 GetSignatureForError (), mc
.GetSignatureForError (), input_variance
, gtype_variance
, parameters
);
696 public TypeSpec
GetAttributeCoClass ()
701 public string GetAttributeDefaultMember ()
703 throw new NotSupportedException ();
706 public AttributeUsageAttribute
GetAttributeUsage (PredefinedAttribute pa
)
708 throw new NotSupportedException ();
711 public override string GetSignatureForDocumentation ()
713 throw new NotImplementedException ();
716 public override string GetSignatureForError ()
718 return MemberName
.Name
;
721 bool ITypeDefinition
.IsInternalAsPublic (IAssemblyDefinition assembly
)
723 return spec
.MemberDefinition
.DeclaringAssembly
== assembly
;
726 public void LoadMembers (TypeSpec declaringType
, bool onlyTypes
, ref MemberCache cache
)
728 throw new NotSupportedException ("Not supported for compiled definition");
732 // Resolves all type parameter constraints
734 public bool ResolveConstraints (IMemberContext context
)
736 if (constraints
!= null)
737 return constraints
.Resolve (context
, this);
739 if (spec
.BaseType
== null)
740 spec
.BaseType
= context
.Module
.Compiler
.BuiltinTypes
.Object
;
745 public override bool IsClsComplianceRequired ()
750 public new void VerifyClsCompliance ()
752 if (constraints
!= null)
753 constraints
.VerifyClsCompliance (Report
);
756 public void WarningParentNameConflict (TypeParameter conflict
)
758 conflict
.Report
.SymbolRelatedToPreviousError (conflict
.Location
, null);
759 conflict
.Report
.Warning (693, 3, Location
,
760 "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
761 GetSignatureForError (), conflict
.CurrentType
.GetSignatureForError ());
765 [System
.Diagnostics
.DebuggerDisplay ("{DisplayDebugInfo()}")]
766 public class TypeParameterSpec
: TypeSpec
768 public static readonly new TypeParameterSpec
[] EmptyTypes
= new TypeParameterSpec
[0];
771 SpecialConstraint spec
;
774 TypeSpec
[] ifaces_defined
;
775 TypeSpec effective_base
;
776 MemberCache interface_cache
;
779 // Creates type owned type parameter
781 public TypeParameterSpec (TypeSpec declaringType
, int index
, ITypeDefinition definition
, SpecialConstraint spec
, Variance variance
, MetaType info
)
782 : base (MemberKind
.TypeParameter
, declaringType
, definition
, info
, Modifiers
.PUBLIC
)
784 this.variance
= variance
;
786 state
&= ~StateFlags
.Obsolete_Undetected
;
791 // Creates method owned type parameter
793 public TypeParameterSpec (int index
, ITypeDefinition definition
, SpecialConstraint spec
, Variance variance
, MetaType info
)
794 : this (null, index
, definition
, spec
, variance
, info
)
800 public int DeclaredPosition
{
809 public bool HasSpecialConstructor
{
811 return (spec
& SpecialConstraint
.Constructor
) != 0;
815 public bool HasSpecialClass
{
817 return (spec
& SpecialConstraint
.Class
) != 0;
821 public bool HasSpecialStruct
{
823 return (spec
& SpecialConstraint
.Struct
) != 0;
827 public bool HasAnyTypeConstraint
{
829 return (spec
& (SpecialConstraint
.Class
| SpecialConstraint
.Struct
)) != 0 || ifaces
!= null || targs
!= null || HasTypeConstraint
;
833 public bool HasTypeConstraint
{
835 var bt
= BaseType
.BuiltinType
;
836 return bt
!= BuiltinTypeSpec
.Type
.Object
&& bt
!= BuiltinTypeSpec
.Type
.ValueType
;
840 public override IList
<TypeSpec
> Interfaces
{
842 if ((state
& StateFlags
.InterfacesExpanded
) == 0) {
843 if (ifaces
!= null) {
844 if (ifaces_defined
== null)
845 ifaces_defined
= ifaces
.ToArray ();
847 for (int i
= 0; i
< ifaces_defined
.Length
; ++i
) {
848 var iface_type
= ifaces_defined
[i
];
849 var td
= iface_type
.MemberDefinition
as TypeDefinition
;
851 td
.DoExpandBaseInterfaces ();
853 if (iface_type
.Interfaces
!= null) {
854 for (int ii
= 0; ii
< iface_type
.Interfaces
.Count
; ++ii
) {
855 var ii_iface_type
= iface_type
.Interfaces
[ii
];
856 AddInterface (ii_iface_type
);
860 } else if (ifaces_defined
== null) {
861 ifaces_defined
= ifaces
== null ? TypeSpec
.EmptyTypes
: ifaces
.ToArray ();
865 // Include all base type interfaces too, see ImportTypeBase for details
867 if (BaseType
!= null) {
868 var td
= BaseType
.MemberDefinition
as TypeDefinition
;
870 td
.DoExpandBaseInterfaces ();
872 if (BaseType
.Interfaces
!= null) {
873 foreach (var iface
in BaseType
.Interfaces
) {
874 AddInterface (iface
);
879 state
|= StateFlags
.InterfacesExpanded
;
886 public MemberCache InterfaceCache
{
888 return interface_cache
;
893 // Unexpanded interfaces list
895 public TypeSpec
[] InterfacesDefined
{
897 if (ifaces_defined
== null) {
898 ifaces_defined
= ifaces
== null ? TypeSpec
.EmptyTypes
: ifaces
.ToArray ();
901 return ifaces_defined
.Length
== 0 ? null : ifaces_defined
;
904 ifaces_defined
= value;
905 if (value != null && value.Length
!= 0)
906 ifaces
= new List
<TypeSpec
> (value);
910 public bool IsConstrained
{
912 return spec
!= SpecialConstraint
.None
|| ifaces
!= null || targs
!= null || HasTypeConstraint
;
917 // Returns whether the type parameter is known to be a reference type
919 public new bool IsReferenceType
{
921 if ((spec
& (SpecialConstraint
.Class
| SpecialConstraint
.Struct
)) != 0)
922 return (spec
& SpecialConstraint
.Class
) != 0;
925 // Full check is needed (see IsValueType for details)
927 if (HasTypeConstraint
&& TypeSpec
.IsReferenceType (BaseType
))
931 foreach (var ta
in targs
) {
933 // Secondary special constraints are ignored (I am not sure why)
935 var tp
= ta
as TypeParameterSpec
;
936 if (tp
!= null && (tp
.spec
& (SpecialConstraint
.Class
| SpecialConstraint
.Struct
)) != 0)
939 if (TypeSpec
.IsReferenceType (ta
))
949 // Returns whether the type parameter is known to be a value type
951 public new bool IsValueType
{
954 // Even if structs/enums cannot be used directly as constraints
955 // they can apear as constraint type when inheriting base constraint
956 // which has dependant type parameter constraint which has been
957 // inflated using value type
959 // class A : B<int> { override void Foo<U> () {} }
960 // class B<T> { virtual void Foo<U> () where U : T {} }
962 if (HasSpecialStruct
)
966 foreach (var ta
in targs
) {
967 if (TypeSpec
.IsValueType (ta
))
976 public override string Name
{
978 return definition
.Name
;
982 public bool IsMethodOwned
{
984 return DeclaringType
== null;
988 public SpecialConstraint SpecialConstraint
{
998 // Types used to inflate the generic type
1000 public new TypeSpec
[] TypeArguments
{
1009 public Variance Variance
{
1017 public string DisplayDebugInfo ()
1019 var s
= GetSignatureForError ();
1020 return IsMethodOwned
? s
+ "!!" : s
+ "!";
1024 // Finds effective base class. The effective base class is always a class-type
1026 public TypeSpec
GetEffectiveBase ()
1028 if (HasSpecialStruct
)
1032 // If T has a class-type constraint C but no type-parameter constraints, its effective base class is C
1034 if (BaseType
!= null && targs
== null) {
1036 // If T has a constraint V that is a value-type, use instead the most specific base type of V that is a class-type.
1038 // LAMESPEC: Is System.ValueType always the most specific base type in this case?
1040 // Note: This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method
1041 // are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.
1043 return BaseType
.IsStruct
? BaseType
.BaseType
: BaseType
;
1046 if (effective_base
!= null)
1047 return effective_base
;
1049 var types
= new TypeSpec
[HasTypeConstraint
? targs
.Length
+ 1 : targs
.Length
];
1051 for (int i
= 0; i
< targs
.Length
; ++i
) {
1054 // Same issue as above, inherited constraints can be of struct type
1056 types
[i
] = t
.BaseType
;
1060 var tps
= t
as TypeParameterSpec
;
1061 types
[i
] = tps
!= null ? tps
.GetEffectiveBase () : t
;
1064 if (HasTypeConstraint
)
1065 types
[types
.Length
- 1] = BaseType
;
1067 return effective_base
= Convert
.FindMostEncompassedType (types
);
1070 public override string GetSignatureForDocumentation (bool explicitName
)
1075 var prefix
= IsMethodOwned
? "``" : "`";
1076 return prefix
+ DeclaredPosition
;
1079 public override string GetSignatureForError ()
1085 // Constraints have to match by definition but not position, used by
1086 // partial classes or methods
1088 public bool HasSameConstraintsDefinition (TypeParameterSpec other
)
1090 if (spec
!= other
.spec
)
1093 if (BaseType
!= other
.BaseType
)
1096 if (!TypeSpecComparer
.Override
.IsSame (InterfacesDefined
, other
.InterfacesDefined
))
1099 if (!TypeSpecComparer
.Override
.IsSame (targs
, other
.targs
))
1106 // Constraints have to match by using same set of types, used by
1107 // implicit interface implementation
1109 public bool HasSameConstraintsImplementation (TypeParameterSpec other
)
1111 if (spec
!= other
.spec
)
1115 // It can be same base type or inflated type parameter
1117 // interface I<T> { void Foo<U> where U : T; }
1118 // class A : I<int> { void Foo<X> where X : int {} }
1121 if (!TypeSpecComparer
.Override
.IsEqual (BaseType
, other
.BaseType
)) {
1123 if (other
.targs
!= null) {
1124 foreach (var otarg
in other
.targs
) {
1125 if (TypeSpecComparer
.Override
.IsEqual (BaseType
, otarg
)) {
1130 } else if (targs
!= null) {
1131 foreach (var targ
in targs
) {
1132 if (TypeSpecComparer
.Override
.IsEqual (targ
, other
.BaseType
)) {
1143 // Check interfaces implementation -> definition
1144 if (InterfacesDefined
!= null) {
1146 // Iterate over inflated interfaces
1148 foreach (var iface
in InterfacesDefined
) {
1150 if (other
.InterfacesDefined
!= null) {
1151 foreach (var oiface
in other
.Interfaces
) {
1152 if (TypeSpecComparer
.Override
.IsEqual (iface
, oiface
)) {
1162 if (other
.targs
!= null) {
1163 foreach (var otarg
in other
.targs
) {
1164 if (TypeSpecComparer
.Override
.IsEqual (iface
, otarg
)) {
1176 // Check interfaces implementation <- definition
1177 if (other
.InterfacesDefined
!= null) {
1179 // Iterate over inflated interfaces
1181 foreach (var oiface
in other
.InterfacesDefined
) {
1184 if (InterfacesDefined
!= null) {
1185 foreach (var iface
in Interfaces
) {
1186 if (TypeSpecComparer
.Override
.IsEqual (iface
, oiface
)) {
1191 } else if (targs
!= null) {
1192 foreach (var targ
in targs
) {
1193 if (TypeSpecComparer
.Override
.IsEqual (targ
, oiface
)) {
1205 // Check type parameters implementation -> definition
1206 if (targs
!= null) {
1207 foreach (var targ
in targs
) {
1210 if (other
.targs
!= null) {
1211 foreach (var otarg
in other
.targs
) {
1212 if (TypeSpecComparer
.Override
.IsEqual (targ
, otarg
)) {
1219 if (other
.InterfacesDefined
!= null && !found
) {
1220 foreach (var iface
in other
.Interfaces
) {
1221 if (TypeSpecComparer
.Override
.IsEqual (iface
, targ
)) {
1229 found
= TypeSpecComparer
.Override
.IsEqual (targ
, other
.BaseType
);
1236 // Check type parameters implementation <- definition
1237 if (other
.targs
!= null) {
1238 foreach (var otarg
in other
.targs
) {
1239 // Ignore inflated type arguments, were checked above
1240 if (!otarg
.IsGenericParameter
)
1247 foreach (var targ
in targs
) {
1248 if (TypeSpecComparer
.Override
.IsEqual (targ
, otarg
)) {
1262 public static TypeParameterSpec
[] InflateConstraints (TypeParameterInflator inflator
, TypeParameterSpec
[] tparams
)
1264 return InflateConstraints (tparams
, l
=> l
, inflator
);
1267 public static TypeParameterSpec
[] InflateConstraints
<T
> (TypeParameterSpec
[] tparams
, Func
<T
, TypeParameterInflator
> inflatorFactory
, T arg
)
1269 TypeParameterSpec
[] constraints
= null;
1270 TypeParameterInflator
? inflator
= null;
1272 for (int i
= 0; i
< tparams
.Length
; ++i
) {
1273 var tp
= tparams
[i
];
1274 if (tp
.HasTypeConstraint
|| tp
.InterfacesDefined
!= null || tp
.TypeArguments
!= null) {
1275 if (constraints
== null) {
1276 constraints
= new TypeParameterSpec
[tparams
.Length
];
1277 Array
.Copy (tparams
, constraints
, constraints
.Length
);
1281 // Using a factory to avoid possibly expensive inflator build up
1283 if (inflator
== null)
1284 inflator
= inflatorFactory (arg
);
1286 constraints
[i
] = (TypeParameterSpec
) constraints
[i
].InflateMember (inflator
.Value
);
1290 if (constraints
== null)
1291 constraints
= tparams
;
1296 public void InflateConstraints (TypeParameterInflator inflator
, TypeParameterSpec tps
)
1298 tps
.BaseType
= inflator
.Inflate (BaseType
);
1300 var defined
= InterfacesDefined
;
1301 if (defined
!= null) {
1302 tps
.ifaces_defined
= new TypeSpec
[defined
.Length
];
1303 for (int i
= 0; i
< defined
.Length
; ++i
)
1304 tps
.ifaces_defined
[i
] = inflator
.Inflate (defined
[i
]);
1305 } else if (ifaces_defined
== TypeSpec
.EmptyTypes
) {
1306 tps
.ifaces_defined
= TypeSpec
.EmptyTypes
;
1309 var ifaces
= Interfaces
;
1310 if (ifaces
!= null) {
1311 tps
.ifaces
= new List
<TypeSpec
> (ifaces
.Count
);
1312 for (int i
= 0; i
< ifaces
.Count
; ++i
)
1313 tps
.ifaces
.Add (inflator
.Inflate (ifaces
[i
]));
1314 tps
.state
|= StateFlags
.InterfacesExpanded
;
1317 if (targs
!= null) {
1318 tps
.targs
= new TypeSpec
[targs
.Length
];
1319 for (int i
= 0; i
< targs
.Length
; ++i
)
1320 tps
.targs
[i
] = inflator
.Inflate (targs
[i
]);
1324 public override MemberSpec
InflateMember (TypeParameterInflator inflator
)
1326 var tps
= (TypeParameterSpec
) MemberwiseClone ();
1331 InflateConstraints (inflator
, tps
);
1336 // Populates type parameter members using type parameter constraints
1337 // The trick here is to be called late enough but not too late to
1338 // populate member cache with all members from other types
1340 protected override void InitializeMemberCache (bool onlyTypes
)
1342 cache
= new MemberCache ();
1344 if (targs
!= null) {
1345 foreach (var ta
in targs
) {
1346 var tps
= ta
as TypeParameterSpec
;
1347 var b_type
= tps
== null ? ta
: tps
.GetEffectiveBase ();
1350 // Find the most specific type when base type was inflated from base constraints
1352 if (b_type
!= null && !b_type
.IsStructOrEnum
&& TypeSpec
.IsBaseClass (b_type
, BaseType
, false))
1358 // For a type parameter the membercache is the union of the sets of members of the types
1359 // specified as a primary constraint or secondary constraint
1361 bool has_user_base_type
= false;
1362 if (BaseType
.BuiltinType
!= BuiltinTypeSpec
.Type
.Object
&& BaseType
.BuiltinType
!= BuiltinTypeSpec
.Type
.ValueType
) {
1363 cache
.AddBaseType (BaseType
);
1364 has_user_base_type
= true;
1367 if (InterfacesDefined
!= null) {
1369 if (has_user_base_type
) {
1371 // type-parameter lookup rules are more complicated that other types lookup rules.
1372 // Effective base class and its base types member have priority over interface
1373 // constraints which means we cannot lookup interface members before class members
1374 // hence we setup secondary cache for such cases.
1376 interface_cache
= new MemberCache ();
1377 icache
= interface_cache
;
1380 foreach (var iface_type
in InterfacesDefined
) {
1381 icache
.AddInterface (iface_type
);
1386 // Import interfaces after base type to match behavior from ordinary classes
1388 if (targs
!= null) {
1389 foreach (var ta
in targs
) {
1390 var tps
= ta
as TypeParameterSpec
;
1391 var ifaces
= tps
== null ? ta
.Interfaces
: tps
.InterfacesDefined
;
1393 if (ifaces
!= null) {
1395 if (has_user_base_type
) {
1396 interface_cache
= new MemberCache ();
1397 icache
= interface_cache
;
1400 foreach (var iface_type
in ifaces
) {
1401 icache
.AddInterface (iface_type
);
1408 public bool IsConvertibleToInterface (TypeSpec iface
)
1410 if (Interfaces
!= null) {
1411 foreach (var t
in Interfaces
) {
1417 if (TypeArguments
!= null) {
1418 foreach (var t
in TypeArguments
) {
1419 var tps
= t
as TypeParameterSpec
;
1421 if (tps
.IsConvertibleToInterface (iface
))
1427 if (t
.ImplementsInterface (iface
, false))
1435 public static bool HasAnyTypeParameterTypeConstrained (IGenericMethodDefinition md
)
1437 var tps
= md
.TypeParameters
;
1438 for (int i
= 0; i
< md
.TypeParametersCount
; ++i
) {
1439 if (tps
[i
].HasAnyTypeConstraint
) {
1447 public static bool HasAnyTypeParameterConstrained (IGenericMethodDefinition md
)
1449 var tps
= md
.TypeParameters
;
1450 for (int i
= 0; i
< md
.TypeParametersCount
; ++i
) {
1451 if (tps
[i
].IsConstrained
) {
1459 public bool HasDependencyOn (TypeSpec type
)
1461 if (TypeArguments
!= null) {
1462 foreach (var targ
in TypeArguments
) {
1463 if (TypeSpecComparer
.Override
.IsEqual (targ
, type
))
1466 var tps
= targ
as TypeParameterSpec
;
1467 if (tps
!= null && tps
.HasDependencyOn (type
))
1475 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
1477 return mutator
.Mutate (this);
1481 public struct TypeParameterInflator
1483 readonly TypeSpec type
;
1484 readonly TypeParameterSpec
[] tparams
;
1485 readonly TypeSpec
[] targs
;
1486 readonly IModuleContext context
;
1488 public TypeParameterInflator (TypeParameterInflator nested
, TypeSpec type
)
1489 : this (nested
.context
, type
, nested
.tparams
, nested
.targs
)
1493 public TypeParameterInflator (IModuleContext context
, TypeSpec type
, TypeParameterSpec
[] tparams
, TypeSpec
[] targs
)
1495 if (tparams
.Length
!= targs
.Length
)
1496 throw new ArgumentException ("Invalid arguments");
1498 this.context
= context
;
1499 this.tparams
= tparams
;
1506 public IModuleContext Context
{
1512 public TypeSpec TypeInstance
{
1519 // Type parameters to inflate
1521 public TypeParameterSpec
[] TypeParameters
{
1529 public TypeSpec
Inflate (TypeSpec type
)
1531 var tp
= type
as TypeParameterSpec
;
1533 return Inflate (tp
);
1535 var ec
= type
as ElementTypeSpec
;
1537 var et
= Inflate (ec
.Element
);
1538 if (et
!= ec
.Element
) {
1539 var ac
= ec
as ArrayContainer
;
1541 return ArrayContainer
.MakeType (context
.Module
, et
, ac
.Rank
);
1543 if (ec
is PointerContainer
)
1544 return PointerContainer
.MakeType (context
.Module
, et
);
1546 throw new NotImplementedException ();
1552 if (type
.Kind
== MemberKind
.MissingType
)
1556 // When inflating a nested type, inflate its parent first
1557 // in case it's using same type parameters (was inflated within the type)
1561 if (type
.IsNested
) {
1562 var parent
= Inflate (type
.DeclaringType
);
1565 // Keep the inflated type arguments
1567 targs
= type
.TypeArguments
;
1570 // When inflating imported nested type used inside same declaring type, we get TypeSpec
1571 // because the import cache helps us to catch it. However, that means we have to look at
1572 // type definition to get type argument (they are in fact type parameter in this case)
1574 if (targs
.Length
== 0 && type
.Arity
> 0)
1575 targs
= type
.MemberDefinition
.TypeParameters
;
1578 // Parent was inflated, find the same type on inflated type
1579 // to use same cache for nested types on same generic parent
1581 type
= MemberCache
.FindNestedType (parent
, type
.Name
, type
.Arity
, false);
1584 // Handle the tricky case where parent shares local type arguments
1585 // which means inflating inflated type
1588 // public static Nested<T> Foo () { return null; }
1590 // public class Nested<U> {}
1593 // return type of Test<string>.Foo() has to be Test<string>.Nested<string>
1595 if (targs
.Length
> 0) {
1596 var inflated_targs
= new TypeSpec
[targs
.Length
];
1597 for (; i
< targs
.Length
; ++i
)
1598 inflated_targs
[i
] = Inflate (targs
[i
]);
1600 type
= type
.MakeGenericType (context
, inflated_targs
);
1606 // Nothing to do for non-generic type
1607 if (type
.Arity
== 0)
1610 targs
= new TypeSpec
[type
.Arity
];
1613 // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {}
1615 if (type
is InflatedTypeSpec
) {
1616 for (; i
< targs
.Length
; ++i
)
1617 targs
[i
] = Inflate (type
.TypeArguments
[i
]);
1619 type
= type
.GetDefinition ();
1622 // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; }
1624 var args
= type
.MemberDefinition
.TypeParameters
;
1625 foreach (var ds_tp
in args
)
1626 targs
[i
++] = Inflate (ds_tp
);
1629 return type
.MakeGenericType (context
, targs
);
1632 public TypeSpec
Inflate (TypeParameterSpec tp
)
1634 for (int i
= 0; i
< tparams
.Length
; ++i
)
1635 if (tparams
[i
] == tp
)
1638 // This can happen when inflating nested types
1639 // without type arguments specified
1645 // Before emitting any code we have to change all MVAR references to VAR
1646 // when the method is of generic type and has hoisted variables
1648 public class TypeParameterMutator
1650 readonly TypeParameters mvar
;
1651 readonly TypeParameters
var;
1652 readonly TypeParameterSpec
[] src
;
1653 Dictionary
<TypeSpec
, TypeSpec
> mutated_typespec
;
1655 public TypeParameterMutator (TypeParameters mvar
, TypeParameters
var)
1657 if (mvar
.Count
!= var.Count
)
1658 throw new ArgumentException ();
1664 public TypeParameterMutator (TypeParameterSpec
[] srcVar
, TypeParameters destVar
)
1666 if (srcVar
.Length
!= destVar
.Count
)
1667 throw new ArgumentException ();
1675 public TypeParameters MethodTypeParameters
{
1683 public static TypeSpec
GetMemberDeclaringType (TypeSpec type
)
1685 if (type
is InflatedTypeSpec
) {
1686 if (type
.DeclaringType
== null)
1687 return type
.GetDefinition ();
1689 var parent
= GetMemberDeclaringType (type
.DeclaringType
);
1690 type
= MemberCache
.GetMember
<TypeSpec
> (parent
, type
);
1696 public TypeSpec
Mutate (TypeSpec ts
)
1699 if (mutated_typespec
!= null && mutated_typespec
.TryGetValue (ts
, out value))
1702 value = ts
.Mutate (this);
1703 if (mutated_typespec
== null)
1704 mutated_typespec
= new Dictionary
<TypeSpec
, TypeSpec
> ();
1706 mutated_typespec
.Add (ts
, value);
1710 public TypeParameterSpec
Mutate (TypeParameterSpec tp
)
1713 for (int i
= 0; i
< mvar
.Count
; ++i
) {
1714 if (mvar
[i
].Type
== tp
)
1718 for (int i
= 0; i
< src
.Length
; ++i
) {
1727 public TypeSpec
[] Mutate (TypeSpec
[] targs
)
1729 TypeSpec
[] mutated
= new TypeSpec
[targs
.Length
];
1730 bool changed
= false;
1731 for (int i
= 0; i
< targs
.Length
; ++i
) {
1732 mutated
[i
] = Mutate (targs
[i
]);
1733 changed
|= targs
[i
] != mutated
[i
];
1736 return changed
? mutated
: targs
;
1741 /// A TypeExpr which already resolved to a type parameter.
1743 public class TypeParameterExpr
: TypeExpression
1745 public TypeParameterExpr (TypeParameter type_parameter
, Location loc
)
1746 : base (type_parameter
.Type
, loc
)
1748 this.eclass
= ExprClass
.TypeParameter
;
1752 public class InflatedTypeSpec
: TypeSpec
1755 TypeParameterSpec
[] constraints
;
1756 readonly TypeSpec open_type
;
1757 readonly IModuleContext context
;
1759 public InflatedTypeSpec (IModuleContext context
, TypeSpec openType
, TypeSpec declaringType
, TypeSpec
[] targs
)
1760 : base (openType
.Kind
, declaringType
, openType
.MemberDefinition
, null, openType
.Modifiers
)
1763 throw new ArgumentNullException ("targs");
1765 this.state
&= ~SharedStateFlags
;
1766 this.state
|= (openType
.state
& SharedStateFlags
);
1768 this.context
= context
;
1769 this.open_type
= openType
;
1772 foreach (var arg
in targs
) {
1773 if (arg
.HasDynamicElement
|| arg
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
1774 state
|= StateFlags
.HasDynamicElement
;
1779 if (open_type
.Kind
== MemberKind
.MissingType
)
1780 MemberCache
= MemberCache
.Empty
;
1782 if ((open_type
.Modifiers
& Modifiers
.COMPILER_GENERATED
) != 0)
1783 state
|= StateFlags
.ConstraintsChecked
;
1788 public override TypeSpec BaseType
{
1790 if (cache
== null || (state
& StateFlags
.PendingBaseTypeInflate
) != 0)
1791 InitializeMemberCache (true);
1793 return base.BaseType
;
1798 // Inflated type parameters with constraints array, mapping with type arguments is based on index
1800 public TypeParameterSpec
[] Constraints
{
1802 if (constraints
== null) {
1803 constraints
= TypeParameterSpec
.InflateConstraints (MemberDefinition
.TypeParameters
, l
=> l
.CreateLocalInflator (context
), this);
1811 // Used to cache expensive constraints validation on constructed types
1813 public bool HasConstraintsChecked
{
1815 return (state
& StateFlags
.ConstraintsChecked
) != 0;
1818 state
= value ? state
| StateFlags
.ConstraintsChecked
: state
& ~StateFlags
.ConstraintsChecked
;
1822 public override IList
<TypeSpec
> Interfaces
{
1825 InitializeMemberCache (true);
1827 return base.Interfaces
;
1831 public override bool IsExpressionTreeType
{
1833 return (open_type
.state
& StateFlags
.InflatedExpressionType
) != 0;
1837 public override bool IsArrayGenericInterface
{
1839 return (open_type
.state
& StateFlags
.GenericIterateInterface
) != 0;
1843 public override bool IsGenericTask
{
1845 return (open_type
.state
& StateFlags
.GenericTask
) != 0;
1849 public override bool IsNullableType
{
1851 return (open_type
.state
& StateFlags
.InflatedNullableType
) != 0;
1856 // Types used to inflate the generic type
1858 public override TypeSpec
[] TypeArguments
{
1866 public override bool AddInterface (TypeSpec iface
)
1868 var inflator
= CreateLocalInflator (context
);
1869 iface
= inflator
.Inflate (iface
);
1873 return base.AddInterface (iface
);
1876 public static bool ContainsTypeParameter (TypeSpec type
)
1878 if (type
.Kind
== MemberKind
.TypeParameter
)
1881 var element_container
= type
as ElementTypeSpec
;
1882 if (element_container
!= null)
1883 return ContainsTypeParameter (element_container
.Element
);
1885 foreach (var t
in type
.TypeArguments
) {
1886 if (ContainsTypeParameter (t
)) {
1894 public TypeParameterInflator
CreateLocalInflator (IModuleContext context
)
1896 TypeParameterSpec
[] tparams_full
;
1897 TypeSpec
[] targs_full
= targs
;
1900 // Special case is needed when we are inflating an open type (nested type definition)
1901 // on inflated parent. Consider following case
1903 // Foo<T>.Bar<U> => Foo<string>.Bar<U>
1905 // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U>
1907 List
<TypeSpec
> merged_targs
= null;
1908 List
<TypeParameterSpec
> merged_tparams
= null;
1910 var type
= DeclaringType
;
1913 if (type
.TypeArguments
.Length
> 0) {
1914 if (merged_targs
== null) {
1915 merged_targs
= new List
<TypeSpec
> ();
1916 merged_tparams
= new List
<TypeParameterSpec
> ();
1917 if (targs
.Length
> 0) {
1918 merged_targs
.AddRange (targs
);
1919 merged_tparams
.AddRange (open_type
.MemberDefinition
.TypeParameters
);
1922 merged_tparams
.AddRange (type
.MemberDefinition
.TypeParameters
);
1923 merged_targs
.AddRange (type
.TypeArguments
);
1925 type
= type
.DeclaringType
;
1926 } while (type
!= null);
1928 if (merged_targs
!= null) {
1929 // Type arguments are not in the right order but it should not matter in this case
1930 targs_full
= merged_targs
.ToArray ();
1931 tparams_full
= merged_tparams
.ToArray ();
1932 } else if (targs
.Length
== 0) {
1933 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1935 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1937 } else if (targs
.Length
== 0) {
1938 tparams_full
= TypeParameterSpec
.EmptyTypes
;
1940 tparams_full
= open_type
.MemberDefinition
.TypeParameters
;
1943 return new TypeParameterInflator (context
, this, tparams_full
, targs_full
);
1946 MetaType
CreateMetaInfo ()
1949 // Converts nested type arguments into right order
1950 // Foo<string, bool>.Bar<int> => string, bool, int
1952 var all
= new List
<MetaType
> ();
1953 TypeSpec type
= this;
1954 TypeSpec definition
= type
;
1956 if (type
.GetDefinition().IsGeneric
) {
1958 type
.TypeArguments
!= TypeSpec
.EmptyTypes
?
1959 type
.TypeArguments
.Select (l
=> l
.GetMetaInfo ()) :
1960 type
.MemberDefinition
.TypeParameters
.Select (l
=> l
.GetMetaInfo ()));
1963 definition
= definition
.GetDefinition ();
1964 type
= type
.DeclaringType
;
1965 } while (type
!= null);
1967 return definition
.GetMetaInfo ().MakeGenericType (all
.ToArray ());
1970 public override void CheckObsoleteness (IMemberContext mc
, Location loc
)
1972 base.CheckObsoleteness (mc
, loc
);
1974 foreach (var ta
in TypeArguments
)
1975 ta
.CheckObsoleteness (mc
, loc
);
1978 public override ObsoleteAttribute
GetAttributeObsolete ()
1980 return open_type
.GetAttributeObsolete ();
1983 protected override bool IsNotCLSCompliant (out bool attrValue
)
1985 if (base.IsNotCLSCompliant (out attrValue
))
1988 foreach (var ta
in TypeArguments
) {
1989 if (ta
.MemberDefinition
.CLSAttributeValue
== false)
1996 public override TypeSpec
GetDefinition ()
2001 public override MetaType
GetMetaInfo ()
2004 info
= CreateMetaInfo ();
2009 public override string GetSignatureForError ()
2012 return targs
[0].GetSignatureForError () + "?";
2014 return base.GetSignatureForError ();
2017 protected override string GetTypeNameSignature ()
2019 if (targs
.Length
== 0 || MemberDefinition
is AnonymousTypeClass
)
2022 return "<" + TypeManager
.CSharpName (targs
) + ">";
2025 public bool HasDynamicArgument ()
2027 for (int i
= 0; i
< targs
.Length
; ++i
) {
2028 var item
= targs
[i
];
2030 if (item
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
2033 if (item
is InflatedTypeSpec
) {
2034 if (((InflatedTypeSpec
) item
).HasDynamicArgument ())
2041 while (item
.IsArray
) {
2042 item
= ((ArrayContainer
) item
).Element
;
2045 if (item
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
2053 protected override void InitializeMemberCache (bool onlyTypes
)
2055 if (cache
== null) {
2056 var open_cache
= onlyTypes
? open_type
.MemberCacheTypes
: open_type
.MemberCache
;
2058 // Surprisingly, calling MemberCache on open type could meantime create cache on this type
2059 // for imported type parameter constraints referencing nested type of this declaration
2061 cache
= new MemberCache (open_cache
);
2064 var inflator
= CreateLocalInflator (context
);
2067 // Two stage inflate due to possible nested types recursive
2077 // When resolving type of `b' members of `B' cannot be
2078 // inflated because are not yet available in membercache
2080 if ((state
& StateFlags
.PendingMemberCacheMembers
) == 0) {
2081 open_type
.MemberCacheTypes
.InflateTypes (cache
, inflator
);
2084 // Inflate any implemented interfaces
2086 if (open_type
.Interfaces
!= null) {
2087 ifaces
= new List
<TypeSpec
> (open_type
.Interfaces
.Count
);
2088 foreach (var iface
in open_type
.Interfaces
) {
2089 var iface_inflated
= inflator
.Inflate (iface
);
2090 if (iface_inflated
== null)
2093 base.AddInterface (iface_inflated
);
2098 // Handles the tricky case of recursive nested base generic type
2100 // class A<T> : Base<A<T>.Nested> {
2104 // When inflating A<T>. base type is not yet known, secondary
2105 // inflation is required (not common case) once base scope
2108 if (open_type
.BaseType
== null) {
2110 state
|= StateFlags
.PendingBaseTypeInflate
;
2112 BaseType
= inflator
.Inflate (open_type
.BaseType
);
2114 } else if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
2116 // It can happen when resolving base type without being defined
2117 // which is not allowed to happen and will always lead to an error
2119 // class B { class N {} }
2120 // class A<T> : A<B.N> {}
2122 if (open_type
.BaseType
== null)
2125 BaseType
= inflator
.Inflate (open_type
.BaseType
);
2126 state
&= ~StateFlags
.PendingBaseTypeInflate
;
2130 state
|= StateFlags
.PendingMemberCacheMembers
;
2134 var tc
= open_type
.MemberDefinition
as TypeDefinition
;
2135 if (tc
!= null && !tc
.HasMembersDefined
) {
2137 // Inflating MemberCache with undefined members
2142 if ((state
& StateFlags
.PendingBaseTypeInflate
) != 0) {
2143 BaseType
= inflator
.Inflate (open_type
.BaseType
);
2144 state
&= ~StateFlags
.PendingBaseTypeInflate
;
2147 state
&= ~StateFlags
.PendingMemberCacheMembers
;
2148 open_type
.MemberCache
.InflateMembers (cache
, open_type
, inflator
);
2151 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
2153 var targs
= TypeArguments
;
2155 targs
= mutator
.Mutate (targs
);
2157 var decl
= DeclaringType
;
2158 if (IsNested
&& DeclaringType
.IsGenericOrParentIsGeneric
)
2159 decl
= mutator
.Mutate (decl
);
2161 if (targs
== TypeArguments
&& decl
== DeclaringType
)
2164 var mutated
= (InflatedTypeSpec
) MemberwiseClone ();
2166 mutated
.ID
+= 1000000;
2169 if (decl
!= DeclaringType
) {
2170 // Gets back MethodInfo in case of metaInfo was inflated
2171 //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
2173 mutated
.declaringType
= decl
;
2174 mutated
.state
|= StateFlags
.PendingMetaInflate
;
2177 if (targs
!= null) {
2178 mutated
.targs
= targs
;
2179 mutated
.info
= null;
2188 // Tracks the type arguments when instantiating a generic type. It's used
2189 // by both type arguments and type parameters
2191 public class TypeArguments
2193 List
<FullNamedExpression
> args
;
2196 public TypeArguments (params FullNamedExpression
[] types
)
2198 this.args
= new List
<FullNamedExpression
> (types
);
2201 public void Add (FullNamedExpression type
)
2207 /// We may only be used after Resolve() is called and return the fully
2210 // TODO: Not needed, just return type from resolve
2211 public TypeSpec
[] Arguments
{
2226 public virtual bool IsEmpty
{
2232 public List
<FullNamedExpression
> TypeExpressions
{
2238 public string GetSignatureForError()
2240 StringBuilder sb
= new StringBuilder ();
2241 for (int i
= 0; i
< Count
; ++i
) {
2244 sb
.Append (expr
.GetSignatureForError ());
2250 return sb
.ToString ();
2254 /// Resolve the type arguments.
2256 public virtual bool Resolve (IMemberContext ec
, bool allowUnbound
)
2261 int count
= args
.Count
;
2264 atypes
= new TypeSpec
[count
];
2266 var errors
= ec
.Module
.Compiler
.Report
.Errors
;
2268 for (int i
= 0; i
< count
; i
++){
2269 var te
= args
[i
].ResolveAsType (ec
);
2278 ec
.Module
.Compiler
.Report
.Error (718, args
[i
].Location
, "`{0}': static classes cannot be used as generic arguments",
2279 te
.GetSignatureForError ());
2283 if (te
.IsPointer
|| te
.IsSpecialRuntimeType
) {
2284 ec
.Module
.Compiler
.Report
.Error (306, args
[i
].Location
,
2285 "The type `{0}' may not be used as a type argument",
2286 te
.GetSignatureForError ());
2291 if (!ok
|| errors
!= ec
.Module
.Compiler
.Report
.Errors
)
2297 public TypeArguments
Clone ()
2299 TypeArguments copy
= new TypeArguments ();
2300 foreach (var ta
in args
)
2307 public class UnboundTypeArguments
: TypeArguments
2311 public UnboundTypeArguments (int arity
, Location loc
)
2312 : base (new FullNamedExpression
[arity
])
2317 public override bool IsEmpty
{
2323 public override bool Resolve (IMemberContext mc
, bool allowUnbound
)
2325 if (!allowUnbound
) {
2326 mc
.Module
.Compiler
.Report
.Error (7003, loc
, "Unbound generic name is not valid in this context");
2329 // Nothing to be resolved
2334 public class TypeParameters
2336 List
<TypeParameter
> names
;
2337 TypeParameterSpec
[] types
;
2339 public TypeParameters ()
2341 names
= new List
<TypeParameter
> ();
2344 public TypeParameters (int count
)
2346 names
= new List
<TypeParameter
> (count
);
2357 public TypeParameterSpec
[] Types
{
2365 public void Add (TypeParameter tparam
)
2370 public void Add (TypeParameters tparams
)
2372 names
.AddRange (tparams
.names
);
2375 public void Create (TypeSpec declaringType
, int parentOffset
, TypeContainer parent
)
2377 types
= new TypeParameterSpec
[Count
];
2378 for (int i
= 0; i
< types
.Length
; ++i
) {
2381 tp
.Create (declaringType
, parent
);
2383 types
[i
].DeclaredPosition
= i
+ parentOffset
;
2385 if (tp
.Variance
!= Variance
.None
&& !(declaringType
!= null && (declaringType
.Kind
== MemberKind
.Interface
|| declaringType
.Kind
== MemberKind
.Delegate
))) {
2386 parent
.Compiler
.Report
.Error (1960, tp
.Location
, "Variant type parameters can only be used with interfaces and delegates");
2391 public void Define (GenericTypeParameterBuilder
[] builders
)
2393 for (int i
= 0; i
< types
.Length
; ++i
) {
2395 tp
.Define (builders
[types
[i
].DeclaredPosition
]);
2399 public TypeParameter
this[int index
] {
2401 return names
[index
];
2404 names
[index
] = value;
2408 public TypeParameter
Find (string name
)
2410 foreach (var tp
in names
) {
2411 if (tp
.Name
== name
)
2418 public string[] GetAllNames ()
2420 return names
.Select (l
=> l
.Name
).ToArray ();
2423 public string GetSignatureForError ()
2425 StringBuilder sb
= new StringBuilder ();
2426 for (int i
= 0; i
< Count
; ++i
) {
2430 var name
= names
[i
];
2432 sb
.Append (name
.GetSignatureForError ());
2435 return sb
.ToString ();
2439 public void CheckPartialConstraints (Method part
)
2441 var partTypeParameters
= part
.CurrentTypeParameters
;
2443 for (int i
= 0; i
< Count
; i
++) {
2444 var tp_a
= names
[i
];
2445 var tp_b
= partTypeParameters
[i
];
2446 if (tp_a
.Constraints
== null) {
2447 if (tp_b
.Constraints
== null)
2449 } else if (tp_b
.Constraints
!= null && tp_a
.Type
.HasSameConstraintsDefinition (tp_b
.Type
)) {
2453 part
.Compiler
.Report
.SymbolRelatedToPreviousError (this[i
].CurrentMemberDefinition
.Location
, "");
2454 part
.Compiler
.Report
.Error (761, part
.Location
,
2455 "Partial method declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
2456 part
.GetSignatureForError (), partTypeParameters
[i
].GetSignatureForError ());
2460 public void UpdateConstraints (TypeDefinition part
)
2462 var partTypeParameters
= part
.MemberName
.TypeParameters
;
2464 for (int i
= 0; i
< Count
; i
++) {
2466 if (tp
.AddPartialConstraints (part
, partTypeParameters
[i
]))
2469 part
.Compiler
.Report
.SymbolRelatedToPreviousError (this[i
].CurrentMemberDefinition
);
2470 part
.Compiler
.Report
.Error (265, part
.Location
,
2471 "Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
2472 part
.GetSignatureForError (), tp
.GetSignatureForError ());
2476 public void VerifyClsCompliance ()
2478 foreach (var tp
in names
) {
2479 tp
.VerifyClsCompliance ();
2485 // A type expression of generic type with type arguments
2487 class GenericTypeExpr
: TypeExpr
2493 /// Instantiate the generic type `t' with the type arguments `args'.
2494 /// Use this constructor if you already know the fully resolved
2497 public GenericTypeExpr (TypeSpec open_type
, TypeArguments args
, Location l
)
2499 this.open_type
= open_type
;
2504 public override string GetSignatureForError ()
2506 return type
.GetSignatureForError ();
2509 public override TypeSpec
ResolveAsType (IMemberContext mc
, bool allowUnboundTypeArguments
= false)
2511 if (eclass
!= ExprClass
.Unresolved
)
2514 if (!args
.Resolve (mc
, allowUnboundTypeArguments
))
2517 TypeSpec
[] atypes
= args
.Arguments
;
2522 // Now bind the parameters
2524 var inflated
= open_type
.MakeGenericType (mc
, atypes
);
2526 eclass
= ExprClass
.Type
;
2529 // The constraints can be checked only when full type hierarchy is known
2531 if (!inflated
.HasConstraintsChecked
&& mc
.Module
.HasTypesFullyDefined
) {
2532 var constraints
= inflated
.Constraints
;
2533 if (constraints
!= null) {
2534 var cc
= new ConstraintChecker (mc
);
2535 if (cc
.CheckAll (open_type
, atypes
, constraints
, loc
)) {
2536 inflated
.HasConstraintsChecked
= true;
2544 public override bool Equals (object obj
)
2546 GenericTypeExpr cobj
= obj
as GenericTypeExpr
;
2550 if ((type
== null) || (cobj
.type
== null))
2553 return type
== cobj
.type
;
2556 public override int GetHashCode ()
2558 return base.GetHashCode ();
2563 // Generic type with unbound type arguments, used for typeof (G<,,>)
2565 class GenericOpenTypeExpr
: TypeExpression
2567 public GenericOpenTypeExpr (TypeSpec type
, /*UnboundTypeArguments args,*/ Location loc
)
2568 : base (type
.GetDefinition (), loc
)
2573 struct ConstraintChecker
2576 bool recursive_checks
;
2578 public ConstraintChecker (IMemberContext ctx
)
2581 recursive_checks
= false;
2585 // Checks the constraints of open generic type against type
2586 // arguments. This version is used for types which could not be
2587 // checked immediatelly during construction because the type
2588 // hierarchy was not yet fully setup (before Emit phase)
2590 public static bool Check (IMemberContext mc
, TypeSpec type
, Location loc
)
2593 // Check declaring type first if there is any
2595 if (type
.DeclaringType
!= null && !Check (mc
, type
.DeclaringType
, loc
))
2598 while (type
is ElementTypeSpec
)
2599 type
= ((ElementTypeSpec
) type
).Element
;
2601 if (type
.Arity
== 0)
2604 var gtype
= type
as InflatedTypeSpec
;
2608 var constraints
= gtype
.Constraints
;
2609 if (constraints
== null)
2612 if (gtype
.HasConstraintsChecked
)
2615 var cc
= new ConstraintChecker (mc
);
2616 cc
.recursive_checks
= true;
2618 if (cc
.CheckAll (gtype
.GetDefinition (), type
.TypeArguments
, constraints
, loc
)) {
2619 gtype
.HasConstraintsChecked
= true;
2627 // Checks all type arguments againts type parameters constraints
2628 // NOTE: It can run in probing mode when `this.mc' is null
2630 public bool CheckAll (MemberSpec context
, TypeSpec
[] targs
, TypeParameterSpec
[] tparams
, Location loc
)
2635 for (int i
= 0; i
< tparams
.Length
; i
++) {
2636 var targ
= targs
[i
];
2637 if (!CheckConstraint (context
, targ
, tparams
[i
], loc
))
2640 if (!recursive_checks
)
2643 if (!Check (mc
, targ
, loc
))
2650 bool CheckConstraint (MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, Location loc
)
2653 // First, check the `class' and `struct' constraints.
2655 if (tparam
.HasSpecialClass
&& !TypeSpec
.IsReferenceType (atype
)) {
2657 mc
.Module
.Compiler
.Report
.Error (452, loc
,
2658 "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
2659 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
2665 if (tparam
.HasSpecialStruct
&& (!TypeSpec
.IsValueType (atype
) || atype
.IsNullableType
)) {
2667 mc
.Module
.Compiler
.Report
.Error (453, loc
,
2668 "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}'",
2669 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
2678 // Check the class constraint
2680 if (tparam
.HasTypeConstraint
) {
2681 if (!CheckConversion (mc
, context
, atype
, tparam
, tparam
.BaseType
, loc
)) {
2690 // Check the interfaces constraints
2692 if (tparam
.InterfacesDefined
!= null) {
2693 foreach (TypeSpec iface
in tparam
.InterfacesDefined
) {
2694 if (!CheckConversion (mc
, context
, atype
, tparam
, iface
, loc
)) {
2705 // Check the type parameter constraint
2707 if (tparam
.TypeArguments
!= null) {
2708 foreach (var ta
in tparam
.TypeArguments
) {
2709 if (!CheckConversion (mc
, context
, atype
, tparam
, ta
, loc
)) {
2720 // Finally, check the constructor constraint.
2722 if (!tparam
.HasSpecialConstructor
)
2725 if (!HasDefaultConstructor (atype
)) {
2727 mc
.Module
.Compiler
.Report
.SymbolRelatedToPreviousError (atype
);
2728 mc
.Module
.Compiler
.Report
.Error (310, loc
,
2729 "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
2730 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError ());
2738 static bool HasDynamicTypeArgument (TypeSpec
[] targs
)
2740 for (int i
= 0; i
< targs
.Length
; ++i
) {
2741 var targ
= targs
[i
];
2742 if (targ
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
2745 if (HasDynamicTypeArgument (targ
.TypeArguments
))
2752 bool CheckConversion (IMemberContext mc
, MemberSpec context
, TypeSpec atype
, TypeParameterSpec tparam
, TypeSpec ttype
, Location loc
)
2757 if (atype
.IsGenericParameter
) {
2758 var tps
= (TypeParameterSpec
) atype
;
2759 if (tps
.HasDependencyOn (ttype
))
2762 if (Convert
.ImplicitTypeParameterConversion (null, tps
, ttype
) != null)
2765 } else if (TypeSpec
.IsValueType (atype
)) {
2766 if (atype
.IsNullableType
) {
2768 // LAMESPEC: Only identity or base type ValueType or Object satisfy nullable type
2770 if (TypeSpec
.IsBaseClass (atype
, ttype
, false))
2773 if (Convert
.ImplicitBoxingConversion (null, atype
, ttype
) != null)
2777 if (Convert
.ImplicitReferenceConversionExists (atype
, ttype
) || Convert
.ImplicitBoxingConversion (null, atype
, ttype
) != null)
2782 mc
.Module
.Compiler
.Report
.SymbolRelatedToPreviousError (tparam
);
2783 if (atype
.IsGenericParameter
) {
2784 mc
.Module
.Compiler
.Report
.Error (314, loc
,
2785 "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}'",
2786 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
2787 } else if (TypeSpec
.IsValueType (atype
)) {
2788 if (atype
.IsNullableType
) {
2789 if (ttype
.IsInterface
) {
2790 mc
.Module
.Compiler
.Report
.Error (313, loc
,
2791 "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 `{3}'",
2792 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
2794 mc
.Module
.Compiler
.Report
.Error (312, loc
,
2795 "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' does not satisfy constraint `{3}'",
2796 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
2799 mc
.Module
.Compiler
.Report
.Error (315, loc
,
2800 "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}'",
2801 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
2804 mc
.Module
.Compiler
.Report
.Error (311, loc
,
2805 "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}'",
2806 atype
.GetSignatureForError (), tparam
.GetSignatureForError (), context
.GetSignatureForError (), ttype
.GetSignatureForError ());
2813 static bool HasDefaultConstructor (TypeSpec atype
)
2815 var tp
= atype
as TypeParameterSpec
;
2817 return tp
.HasSpecialConstructor
|| tp
.HasSpecialStruct
;
2820 if (atype
.IsStruct
|| atype
.IsEnum
)
2823 if (atype
.IsAbstract
)
2826 var tdef
= atype
.GetDefinition ();
2828 var found
= MemberCache
.FindMember (tdef
,
2829 MemberFilter
.Constructor (ParametersCompiled
.EmptyReadOnlyParameters
),
2830 BindingRestriction
.DeclaredOnly
| BindingRestriction
.InstanceOnly
);
2832 return found
!= null && (found
.Modifiers
& Modifiers
.PUBLIC
) != 0;
2837 // Implements C# type inference
2842 // Tracks successful rate of type inference
2845 readonly Arguments arguments
;
2846 readonly int arg_count
;
2848 public TypeInference (Arguments arguments
)
2850 this.arguments
= arguments
;
2851 if (arguments
!= null)
2852 arg_count
= arguments
.Count
;
2855 public int InferenceScore
{
2861 public TypeSpec
[] InferMethodArguments (ResolveContext ec
, MethodSpec method
)
2863 var method_generic_args
= method
.GenericDefinition
.TypeParameters
;
2864 TypeInferenceContext context
= new TypeInferenceContext (method_generic_args
);
2865 if (!context
.UnfixedVariableExists
)
2866 return TypeSpec
.EmptyTypes
;
2868 AParametersCollection pd
= method
.Parameters
;
2869 if (!InferInPhases (ec
, context
, pd
))
2872 return context
.InferredTypeArguments
;
2876 // Implements method type arguments inference
2878 bool InferInPhases (ResolveContext ec
, TypeInferenceContext tic
, AParametersCollection methodParameters
)
2880 int params_arguments_start
;
2881 if (methodParameters
.HasParams
) {
2882 params_arguments_start
= methodParameters
.Count
- 1;
2884 params_arguments_start
= arg_count
;
2887 TypeSpec
[] ptypes
= methodParameters
.Types
;
2890 // The first inference phase
2892 TypeSpec method_parameter
= null;
2893 for (int i
= 0; i
< arg_count
; i
++) {
2894 Argument a
= arguments
[i
];
2898 if (i
< params_arguments_start
) {
2899 method_parameter
= methodParameters
.Types
[i
];
2900 } else if (i
== params_arguments_start
) {
2901 if (arg_count
== params_arguments_start
+ 1 && TypeManager
.HasElementType (a
.Type
))
2902 method_parameter
= methodParameters
.Types
[params_arguments_start
];
2904 method_parameter
= TypeManager
.GetElementType (methodParameters
.Types
[params_arguments_start
]);
2906 ptypes
= (TypeSpec
[]) ptypes
.Clone ();
2907 ptypes
[i
] = method_parameter
;
2911 // When a lambda expression, an anonymous method
2912 // is used an explicit argument type inference takes a place
2914 AnonymousMethodExpression am
= a
.Expr
as AnonymousMethodExpression
;
2916 if (am
.ExplicitTypeInference (tic
, method_parameter
))
2922 score
+= tic
.ExactInference (a
.Type
, method_parameter
);
2926 if (a
.Expr
.Type
== InternalType
.NullLiteral
)
2929 if (TypeSpec
.IsValueType (method_parameter
)) {
2930 score
+= tic
.LowerBoundInference (a
.Type
, method_parameter
);
2935 // Otherwise an output type inference is made
2937 score
+= tic
.OutputTypeInference (ec
, a
.Expr
, method_parameter
);
2941 // Part of the second phase but because it happens only once
2942 // we don't need to call it in cycle
2944 bool fixed_any
= false;
2945 if (!tic
.FixIndependentTypeArguments (ec
, ptypes
, ref fixed_any
))
2948 return DoSecondPhase (ec
, tic
, ptypes
, !fixed_any
);
2951 bool DoSecondPhase (ResolveContext ec
, TypeInferenceContext tic
, TypeSpec
[] methodParameters
, bool fixDependent
)
2953 bool fixed_any
= false;
2954 if (fixDependent
&& !tic
.FixDependentTypes (ec
, ref fixed_any
))
2957 // If no further unfixed type variables exist, type inference succeeds
2958 if (!tic
.UnfixedVariableExists
)
2961 if (!fixed_any
&& fixDependent
)
2964 // For all arguments where the corresponding argument output types
2965 // contain unfixed type variables but the input types do not,
2966 // an output type inference is made
2967 for (int i
= 0; i
< arg_count
; i
++) {
2969 // Align params arguments
2970 TypeSpec t_i
= methodParameters
[i
>= methodParameters
.Length
? methodParameters
.Length
- 1: i
];
2972 if (!t_i
.IsDelegate
) {
2973 if (!t_i
.IsExpressionTreeType
)
2976 t_i
= TypeManager
.GetTypeArguments (t_i
) [0];
2979 var mi
= Delegate
.GetInvokeMethod (t_i
);
2980 TypeSpec rtype
= mi
.ReturnType
;
2982 if (tic
.IsReturnTypeNonDependent (mi
, rtype
)) {
2983 // It can be null for default arguments
2984 if (arguments
[i
] == null)
2987 score
+= tic
.OutputTypeInference (ec
, arguments
[i
].Expr
, t_i
);
2992 return DoSecondPhase (ec
, tic
, methodParameters
, true);
2996 public class TypeInferenceContext
2998 protected enum BoundKind
3005 struct BoundInfo
: IEquatable
<BoundInfo
>
3007 public readonly TypeSpec Type
;
3008 public readonly BoundKind Kind
;
3010 public BoundInfo (TypeSpec type
, BoundKind kind
)
3016 public override int GetHashCode ()
3018 return Type
.GetHashCode ();
3021 public Expression
GetTypeExpression ()
3023 return new TypeExpression (Type
, Location
.Null
);
3026 #region IEquatable<BoundInfo> Members
3028 public bool Equals (BoundInfo other
)
3030 return Type
== other
.Type
&& Kind
== other
.Kind
;
3036 readonly TypeSpec
[] tp_args
;
3037 readonly TypeSpec
[] fixed_types
;
3038 readonly List
<BoundInfo
>[] bounds
;
3040 // TODO MemberCache: Could it be TypeParameterSpec[] ??
3041 public TypeInferenceContext (TypeSpec
[] typeArguments
)
3043 if (typeArguments
.Length
== 0)
3044 throw new ArgumentException ("Empty generic arguments");
3046 fixed_types
= new TypeSpec
[typeArguments
.Length
];
3047 for (int i
= 0; i
< typeArguments
.Length
; ++i
) {
3048 if (typeArguments
[i
].IsGenericParameter
) {
3049 if (bounds
== null) {
3050 bounds
= new List
<BoundInfo
> [typeArguments
.Length
];
3051 tp_args
= new TypeSpec
[typeArguments
.Length
];
3053 tp_args
[i
] = typeArguments
[i
];
3055 fixed_types
[i
] = typeArguments
[i
];
3061 // Used together with AddCommonTypeBound fo implement
3062 // 7.4.2.13 Finding the best common type of a set of expressions
3064 public TypeInferenceContext ()
3066 fixed_types
= new TypeSpec
[1];
3067 tp_args
= new TypeSpec
[1];
3068 tp_args
[0] = InternalType
.Arglist
; // it can be any internal type
3069 bounds
= new List
<BoundInfo
> [1];
3072 public TypeSpec
[] InferredTypeArguments
{
3078 public void AddCommonTypeBound (TypeSpec type
)
3080 AddToBounds (new BoundInfo (type
, BoundKind
.Lower
), 0, false);
3083 public void AddCommonTypeBoundAsync (TypeSpec type
)
3085 AddToBounds (new BoundInfo (type
, BoundKind
.Lower
), 0, true);
3088 void AddToBounds (BoundInfo bound
, int index
, bool voidAllowed
)
3091 // Some types cannot be used as type arguments
3093 if ((bound
.Type
.Kind
== MemberKind
.Void
&& !voidAllowed
) || bound
.Type
.IsPointer
|| bound
.Type
.IsSpecialRuntimeType
||
3094 bound
.Type
== InternalType
.MethodGroup
|| bound
.Type
== InternalType
.AnonymousMethod
|| bound
.Type
== InternalType
.VarOutType
)
3097 var a
= bounds
[index
];
3099 a
= new List
<BoundInfo
> (2);
3105 if (a
.Contains (bound
))
3111 bool AllTypesAreFixed (TypeSpec
[] types
)
3113 foreach (TypeSpec t
in types
) {
3114 if (t
.IsGenericParameter
) {
3120 if (t
.IsGeneric
&& !AllTypesAreFixed (t
.TypeArguments
))
3128 // 26.3.3.8 Exact Inference
3130 public int ExactInference (TypeSpec u
, TypeSpec v
)
3132 // If V is an array type
3137 var ac_u
= (ArrayContainer
) u
;
3138 var ac_v
= (ArrayContainer
) v
;
3139 if (ac_u
.Rank
!= ac_v
.Rank
)
3142 return ExactInference (ac_u
.Element
, ac_v
.Element
);
3146 // If V is constructed type and U is constructed type or dynamic
3148 if (TypeManager
.IsGenericType (v
)) {
3149 if (u
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
3151 var ga_v
= v
.TypeArguments
;
3154 for (int i
= 0; i
< ga_v
.Length
; ++i
)
3155 score
+= ExactInference (u
, ga_v
[i
]);
3157 return System
.Math
.Min (1, score
);
3160 if (!TypeManager
.IsGenericType (u
) || v
.MemberDefinition
!= u
.MemberDefinition
)
3163 var ga_u
= u
.TypeArguments
;
3164 var ga_v
= v
.TypeArguments
;
3166 if (u
.TypeArguments
.Length
!= v
.TypeArguments
.Length
)
3170 for (int i
= 0; i
< ga_v
.Length
; ++i
)
3171 score
+= ExactInference (ga_u
[i
], ga_v
[i
]);
3173 return System
.Math
.Min (1, score
);
3177 // If V is one of the unfixed type arguments
3178 int pos
= IsUnfixed (v
);
3182 AddToBounds (new BoundInfo (u
, BoundKind
.Exact
), pos
, false);
3186 public bool FixAllTypes (ResolveContext ec
)
3188 for (int i
= 0; i
< tp_args
.Length
; ++i
) {
3189 if (!FixType (ec
, i
))
3196 // All unfixed type variables Xi are fixed for which all of the following hold:
3197 // a, There is at least one type variable Xj that depends on Xi
3198 // b, Xi has a non-empty set of bounds
3200 public bool FixDependentTypes (ResolveContext ec
, ref bool fixed_any
)
3202 for (int i
= 0; i
< tp_args
.Length
; ++i
) {
3203 if (fixed_types
[i
] != null)
3206 if (bounds
[i
] == null)
3209 if (!FixType (ec
, i
))
3219 // All unfixed type variables Xi which depend on no Xj are fixed
3221 public bool FixIndependentTypeArguments (ResolveContext ec
, TypeSpec
[] methodParameters
, ref bool fixed_any
)
3223 var types_to_fix
= new List
<TypeSpec
> (tp_args
);
3224 for (int i
= 0; i
< methodParameters
.Length
; ++i
) {
3225 TypeSpec t
= methodParameters
[i
];
3227 if (!t
.IsDelegate
) {
3228 if (!t
.IsExpressionTreeType
)
3231 t
= TypeManager
.GetTypeArguments (t
) [0];
3234 if (t
.IsGenericParameter
)
3237 var invoke
= Delegate
.GetInvokeMethod (t
);
3238 TypeSpec rtype
= invoke
.ReturnType
;
3239 while (rtype
.IsArray
)
3240 rtype
= ((ArrayContainer
) rtype
).Element
;
3242 if (!rtype
.IsGenericParameter
&& !TypeManager
.IsGenericType (rtype
))
3245 // Remove dependent types, they cannot be fixed yet
3246 RemoveDependentTypes (types_to_fix
, rtype
);
3249 foreach (TypeSpec t
in types_to_fix
) {
3253 int idx
= IsUnfixed (t
);
3254 if (idx
>= 0 && !FixType (ec
, idx
)) {
3259 fixed_any
= types_to_fix
.Count
> 0;
3266 public bool FixType (ResolveContext ec
, int i
)
3268 // It's already fixed
3269 if (fixed_types
[i
] != null)
3270 throw new InternalErrorException ("Type argument has been already fixed");
3272 var candidates
= bounds
[i
];
3273 if (candidates
== null)
3276 if (candidates
.Count
== 1) {
3277 TypeSpec t
= candidates
[0].Type
;
3278 if (t
== InternalType
.NullLiteral
)
3281 fixed_types
[i
] = t
;
3286 // The set of candidate types Uj starts out as the set of
3287 // all types in the set of bounds for Xi
3289 var applicable
= new bool [candidates
.Count
];
3290 for (int ci
= 0; ci
< applicable
.Length
; ++ci
)
3291 applicable
[ci
] = true;
3293 for (int ci
= 0; ci
< applicable
.Length
; ++ci
) {
3294 var bound
= candidates
[ci
];
3297 switch (bound
.Kind
) {
3298 case BoundKind
.Exact
:
3299 for (; cii
!= applicable
.Length
; ++cii
) {
3303 if (!applicable
[cii
])
3307 // For each exact bound U of Xi all types Uj which are not identical
3308 // to U are removed from the candidate set
3310 if (candidates
[cii
].Type
!= bound
.Type
)
3311 applicable
[cii
] = false;
3315 case BoundKind
.Lower
:
3316 for (; cii
!= applicable
.Length
; ++cii
) {
3320 if (!applicable
[cii
])
3324 // For each lower bound U of Xi all types Uj to which there is not an implicit conversion
3325 // from U are removed from the candidate set
3327 if (!Convert
.ImplicitConversionExists (ec
, bound
.GetTypeExpression (), candidates
[cii
].Type
)) {
3328 applicable
[cii
] = false;
3334 case BoundKind
.Upper
:
3335 for (; cii
!= applicable
.Length
; ++cii
) {
3339 if (!applicable
[cii
])
3343 // For each upper bound U of Xi all types Uj from which there is not an implicit conversion
3344 // to U are removed from the candidate set
3346 if (!Convert
.ImplicitConversionExists (ec
, candidates
[cii
].GetTypeExpression (), bound
.Type
))
3347 applicable
[cii
] = false;
3354 TypeSpec best_candidate
= null;
3355 for (int ci
= 0; ci
< applicable
.Length
; ++ci
) {
3356 if (!applicable
[ci
])
3359 var bound
= candidates
[ci
];
3360 if (bound
.Type
== best_candidate
)
3364 for (; cii
< applicable
.Length
; ++cii
) {
3368 if (!applicable
[cii
])
3371 if (!Convert
.ImplicitConversionExists (ec
, candidates
[cii
].GetTypeExpression (), bound
.Type
))
3375 if (cii
!= applicable
.Length
)
3379 // We already have the best candidate, break if it's different (non-unique)
3381 // Dynamic is never ambiguous as we prefer dynamic over other best candidate types
3383 if (best_candidate
!= null) {
3385 if (best_candidate
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
3388 if (bound
.Type
.BuiltinType
!= BuiltinTypeSpec
.Type
.Dynamic
&& best_candidate
!= bound
.Type
)
3392 best_candidate
= bound
.Type
;
3395 if (best_candidate
== null)
3398 fixed_types
[i
] = best_candidate
;
3402 public bool HasBounds (int pos
)
3404 return bounds
[pos
] != null;
3408 // Uses inferred or partially infered types to inflate delegate type argument. Returns
3409 // null when type parameter has not been fixed
3411 public TypeSpec
InflateGenericArgument (IModuleContext context
, TypeSpec parameter
)
3413 var tp
= parameter
as TypeParameterSpec
;
3416 // Type inference works on generic arguments (MVAR) only
3418 if (!tp
.IsMethodOwned
)
3422 // Ensure the type parameter belongs to same container
3424 if (tp
.DeclaredPosition
< tp_args
.Length
&& tp_args
[tp
.DeclaredPosition
] == parameter
)
3425 return fixed_types
[tp
.DeclaredPosition
] ?? parameter
;
3430 var gt
= parameter
as InflatedTypeSpec
;
3432 var inflated_targs
= new TypeSpec
[gt
.TypeArguments
.Length
];
3433 for (int ii
= 0; ii
< inflated_targs
.Length
; ++ii
) {
3434 var inflated
= InflateGenericArgument (context
, gt
.TypeArguments
[ii
]);
3435 if (inflated
== null)
3438 inflated_targs
[ii
] = inflated
;
3441 return gt
.GetDefinition ().MakeGenericType (context
, inflated_targs
);
3444 var ac
= parameter
as ArrayContainer
;
3446 var inflated
= InflateGenericArgument (context
, ac
.Element
);
3447 if (inflated
!= ac
.Element
)
3448 return ArrayContainer
.MakeType (context
.Module
, inflated
);
3455 // Tests whether all delegate input arguments are fixed and generic output type
3456 // requires output type inference
3458 public bool IsReturnTypeNonDependent (MethodSpec invoke
, TypeSpec returnType
)
3460 AParametersCollection d_parameters
= invoke
.Parameters
;
3462 if (d_parameters
.IsEmpty
)
3465 while (returnType
.IsArray
)
3466 returnType
= ((ArrayContainer
) returnType
).Element
;
3468 if (returnType
.IsGenericParameter
) {
3469 if (IsFixed (returnType
))
3471 } else if (TypeManager
.IsGenericType (returnType
)) {
3472 TypeSpec
[] g_args
= TypeManager
.GetTypeArguments (returnType
);
3474 // At least one unfixed return type has to exist
3475 if (AllTypesAreFixed (g_args
))
3481 // All generic input arguments have to be fixed
3482 return AllTypesAreFixed (d_parameters
.Types
);
3485 bool IsFixed (TypeSpec type
)
3487 return IsUnfixed (type
) == -1;
3490 int IsUnfixed (TypeSpec type
)
3492 if (!type
.IsGenericParameter
)
3495 for (int i
= 0; i
< tp_args
.Length
; ++i
) {
3496 if (tp_args
[i
] == type
) {
3497 if (fixed_types
[i
] != null)
3508 // 26.3.3.9 Lower-bound Inference
3510 public int LowerBoundInference (TypeSpec u
, TypeSpec v
)
3512 return LowerBoundInference (u
, v
, false);
3516 // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
3518 int LowerBoundInference (TypeSpec u
, TypeSpec v
, bool inversed
)
3520 // If V is one of the unfixed type arguments
3521 int pos
= IsUnfixed (v
);
3523 AddToBounds (new BoundInfo (u
, inversed
? BoundKind
.Upper
: BoundKind
.Lower
), pos
, false);
3527 // If U is an array type
3528 var u_ac
= u
as ArrayContainer
;
3530 var v_ac
= v
as ArrayContainer
;
3532 if (u_ac
.Rank
!= v_ac
.Rank
)
3535 if (TypeSpec
.IsValueType (u_ac
.Element
))
3536 return ExactInference (u_ac
.Element
, v_ac
.Element
);
3538 return LowerBoundInference (u_ac
.Element
, v_ac
.Element
, inversed
);
3541 if (u_ac
.Rank
!= 1 || !v
.IsArrayGenericInterface
)
3544 var v_i
= TypeManager
.GetTypeArguments (v
) [0];
3545 if (TypeSpec
.IsValueType (u_ac
.Element
))
3546 return ExactInference (u_ac
.Element
, v_i
);
3548 return LowerBoundInference (u_ac
.Element
, v_i
);
3551 if (v
.IsGenericOrParentIsGeneric
) {
3553 // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
3554 // such that U is identical to, inherits from (directly or indirectly),
3555 // or implements (directly or indirectly) C<U1..Uk>
3557 var u_candidates
= new List
<TypeSpec
> ();
3558 var open_v
= v
.MemberDefinition
;
3560 for (TypeSpec t
= u
; t
!= null; t
= t
.BaseType
) {
3561 if (open_v
== t
.MemberDefinition
)
3562 u_candidates
.Add (t
);
3565 // Using this trick for dynamic type inference, the spec says the type arguments are "unknown" but
3566 // that would complicate the process a lot, instead I treat them as dynamic
3568 if (t
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
3569 u_candidates
.Add (t
);
3572 if (u
.Interfaces
!= null) {
3573 foreach (var iface
in u
.Interfaces
) {
3574 if (open_v
== iface
.MemberDefinition
)
3575 u_candidates
.Add (iface
);
3579 TypeSpec
[] unique_candidate_targs
= null;
3580 var ga_v
= TypeSpec
.GetAllTypeArguments (v
);
3581 foreach (TypeSpec u_candidate
in u_candidates
) {
3583 // The unique set of types U1..Uk means that if we have an interface I<T>,
3584 // class U : I<int>, I<long> then no type inference is made when inferring
3585 // type I<T> by applying type U because T could be int or long
3587 if (unique_candidate_targs
!= null) {
3588 TypeSpec
[] second_unique_candidate_targs
= TypeSpec
.GetAllTypeArguments (u_candidate
);
3589 if (TypeSpecComparer
.Equals (unique_candidate_targs
, second_unique_candidate_targs
)) {
3590 unique_candidate_targs
= second_unique_candidate_targs
;
3595 // Break when candidate arguments are ambiguous
3601 // A candidate is dynamic type expression, to simplify things use dynamic
3602 // for all type parameter of this type. For methods like this one
3604 // void M<T, U> (IList<T>, IList<U[]>)
3606 // dynamic becomes both T and U when the arguments are of dynamic type
3608 if (u_candidate
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
3609 unique_candidate_targs
= new TypeSpec
[ga_v
.Length
];
3610 for (int i
= 0; i
< unique_candidate_targs
.Length
; ++i
)
3611 unique_candidate_targs
[i
] = u_candidate
;
3613 unique_candidate_targs
= TypeSpec
.GetAllTypeArguments (u_candidate
);
3617 if (unique_candidate_targs
!= null) {
3620 TypeParameterSpec
[] tps
= null;
3622 for (int i
= 0; i
< unique_candidate_targs
.Length
; ++i
) {
3624 while (v
.Arity
== 0)
3625 v
= v
.DeclaringType
;
3627 tps
= v
.MemberDefinition
.TypeParameters
;
3628 tp_index
= tps
.Length
- 1;
3631 Variance variance
= tps
[tp_index
--].Variance
;
3633 TypeSpec u_i
= unique_candidate_targs
[i
];
3634 if (variance
== Variance
.None
|| TypeSpec
.IsValueType (u_i
)) {
3635 if (ExactInference (u_i
, ga_v
[i
]) == 0)
3638 bool upper_bound
= (variance
== Variance
.Contravariant
&& !inversed
) ||
3639 (variance
== Variance
.Covariant
&& inversed
);
3641 if (LowerBoundInference (u_i
, ga_v
[i
], upper_bound
) == 0)
3654 // 26.3.3.6 Output Type Inference
3656 public int OutputTypeInference (ResolveContext ec
, Expression e
, TypeSpec t
)
3658 // If e is a lambda or anonymous method with inferred return type
3659 AnonymousMethodExpression ame
= e
as AnonymousMethodExpression
;
3661 TypeSpec rt
= ame
.InferReturnType (ec
, this, t
);
3662 var invoke
= Delegate
.GetInvokeMethod (t
);
3665 AParametersCollection pd
= invoke
.Parameters
;
3666 return ame
.Parameters
.Count
== pd
.Count
? 1 : 0;
3669 TypeSpec rtype
= invoke
.ReturnType
;
3670 return LowerBoundInference (rt
, rtype
) + 1;
3674 // if E is a method group and T is a delegate type or expression tree type
3675 // return type Tb with parameter types T1..Tk and return type Tb, and overload
3676 // resolution of E with the types T1..Tk yields a single method with return type U,
3677 // then a lower-bound inference is made from U for Tb.
3679 if (e
is MethodGroupExpr
) {
3680 if (!t
.IsDelegate
) {
3681 if (!t
.IsExpressionTreeType
)
3684 t
= TypeManager
.GetTypeArguments (t
)[0];
3687 var invoke
= Delegate
.GetInvokeMethod (t
);
3688 TypeSpec rtype
= invoke
.ReturnType
;
3690 if (!IsReturnTypeNonDependent (invoke
, rtype
))
3693 // LAMESPEC: Standard does not specify that all methodgroup arguments
3694 // has to be fixed but it does not specify how to do recursive type inference
3695 // either. We choose the simple option and infer return type only
3696 // if all delegate generic arguments are fixed.
3697 TypeSpec
[] param_types
= new TypeSpec
[invoke
.Parameters
.Count
];
3698 for (int i
= 0; i
< param_types
.Length
; ++i
) {
3699 var inflated
= InflateGenericArgument (ec
, invoke
.Parameters
.Types
[i
]);
3700 if (inflated
== null)
3703 param_types
[i
] = inflated
;
3706 MethodGroupExpr mg
= (MethodGroupExpr
) e
;
3707 Arguments args
= DelegateCreation
.CreateDelegateMethodArguments (ec
, invoke
.Parameters
, param_types
, e
.Location
);
3708 mg
= mg
.OverloadResolve (ec
, ref args
, null, OverloadResolver
.Restrictions
.CovariantDelegate
| OverloadResolver
.Restrictions
.ProbingOnly
);
3712 return LowerBoundInference (mg
.BestCandidateReturnType
, rtype
) + 1;
3716 // if e is an expression with type U, then
3717 // a lower-bound inference is made from U for T
3719 return LowerBoundInference (e
.Type
, t
) * 2;
3722 void RemoveDependentTypes (List
<TypeSpec
> types
, TypeSpec returnType
)
3724 int idx
= IsUnfixed (returnType
);
3730 if (TypeManager
.IsGenericType (returnType
)) {
3731 foreach (TypeSpec t
in TypeManager
.GetTypeArguments (returnType
)) {
3732 RemoveDependentTypes (types
, t
);
3737 public bool UnfixedVariableExists
{
3739 foreach (TypeSpec ut
in fixed_types
) {