1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
22
using System.Threading;
23
using ICSharpCode.NRefactory.Utils;
25
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
27
public class DefaultTypeParameter : AbstractTypeParameter
29
readonly bool hasValueTypeConstraint;
30
readonly bool hasReferenceTypeConstraint;
31
readonly bool hasDefaultConstructorConstraint;
32
readonly IList<IType> constraints;
34
public DefaultTypeParameter(
36
int index, string name = null,
37
VarianceModifier variance = VarianceModifier.Invariant,
38
IList<IAttribute> attributes = null,
39
DomRegion region = default(DomRegion),
40
bool hasValueTypeConstraint = false, bool hasReferenceTypeConstraint = false, bool hasDefaultConstructorConstraint = false,
41
IList<IType> constraints = null)
42
: base(owner, index, name, variance, attributes, region)
44
this.hasValueTypeConstraint = hasValueTypeConstraint;
45
this.hasReferenceTypeConstraint = hasReferenceTypeConstraint;
46
this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
47
this.constraints = constraints ?? EmptyList<IType>.Instance;
50
public DefaultTypeParameter(
51
ICompilation compilation, EntityType ownerType,
52
int index, string name = null,
53
VarianceModifier variance = VarianceModifier.Invariant,
54
IList<IAttribute> attributes = null,
55
DomRegion region = default(DomRegion),
56
bool hasValueTypeConstraint = false, bool hasReferenceTypeConstraint = false, bool hasDefaultConstructorConstraint = false,
57
IList<IType> constraints = null)
58
: base(compilation, ownerType, index, name, variance, attributes, region)
60
this.hasValueTypeConstraint = hasValueTypeConstraint;
61
this.hasReferenceTypeConstraint = hasReferenceTypeConstraint;
62
this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
63
this.constraints = constraints ?? EmptyList<IType>.Instance;
66
public override bool HasValueTypeConstraint {
67
get { return hasValueTypeConstraint; }
70
public override bool HasReferenceTypeConstraint {
71
get { return hasReferenceTypeConstraint; }
74
public override bool HasDefaultConstructorConstraint {
75
get { return hasDefaultConstructorConstraint; }
78
public override IEnumerable<IType> DirectBaseTypes {
80
bool hasNonInterfaceConstraint = false;
81
foreach (IType c in constraints) {
83
if (c.Kind != TypeKind.Interface)
84
hasNonInterfaceConstraint = true;
86
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
87
if (this.HasValueTypeConstraint || !hasNonInterfaceConstraint) {
88
yield return this.Compilation.FindType(this.HasValueTypeConstraint ? KnownTypeCode.ValueType : KnownTypeCode.Object);
96
/// Default implementation of <see cref="ITypeParameter"/>.
99
public sealed class DefaultTypeParameter : AbstractTypeParameter
101
IList<ITypeReference> constraints;
105
const ushort FlagReferenceTypeConstraint = 0x0001;
106
const ushort FlagValueTypeConstraint = 0x0002;
107
const ushort FlagDefaultConstructorConstraint = 0x0004;
109
protected override void FreezeInternal()
111
constraints = FreezeList(constraints);
112
base.FreezeInternal();
115
public DefaultTypeParameter(EntityType ownerType, int index, string name)
116
: base(ownerType, index, name)
120
public IList<ITypeReference> Constraints {
122
if (constraints == null)
123
constraints = new List<ITypeReference>();
128
public bool HasDefaultConstructorConstraint {
129
get { return flags[FlagDefaultConstructorConstraint]; }
131
CheckBeforeMutation();
132
flags[FlagDefaultConstructorConstraint] = value;
136
public bool HasReferenceTypeConstraint {
137
get { return flags[FlagReferenceTypeConstraint]; }
139
CheckBeforeMutation();
140
flags[FlagReferenceTypeConstraint] = value;
144
public bool HasValueTypeConstraint {
145
get { return flags[FlagValueTypeConstraint]; }
147
CheckBeforeMutation();
148
flags[FlagValueTypeConstraint] = value;
152
public override bool? IsReferenceType(ITypeResolveContext context)
154
switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) {
155
case FlagReferenceTypeConstraint:
157
case FlagValueTypeConstraint:
161
return base.IsReferenceTypeHelper(GetEffectiveBaseClass(context));
164
public override IType GetEffectiveBaseClass(ITypeResolveContext context)
166
// protect against cyclic type parameters
167
using (var busyLock = BusyManager.Enter(this)) {
168
if (!busyLock.Success)
169
return SpecialTypes.UnknownType;
171
if (HasValueTypeConstraint)
172
return context.GetTypeDefinition("System", "ValueType", 0, StringComparer.Ordinal) ?? SpecialTypes.UnknownType;
174
List<IType> classTypeConstraints = new List<IType>();
175
foreach (ITypeReference constraintRef in this.Constraints) {
176
IType constraint = constraintRef.Resolve(context);
177
if (constraint.Kind == TypeKind.Class) {
178
classTypeConstraints.Add(constraint);
179
} else if (constraint.Kind == TypeKind.TypeParameter) {
180
IType baseClass = ((ITypeParameter)constraint).GetEffectiveBaseClass(context);
181
if (baseClass.Kind == TypeKind.Class)
182
classTypeConstraints.Add(baseClass);
185
if (classTypeConstraints.Count == 0)
186
return KnownTypeReference.Object.Resolve(context);
187
// Find the derived-most type in the resulting set:
188
IType result = classTypeConstraints[0];
189
for (int i = 1; i < classTypeConstraints.Count; i++) {
190
if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition(), context))
191
result = classTypeConstraints[i];
197
public override IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context)
199
List<IType> result = new List<IType>();
200
// protect against cyclic type parameters
201
using (var busyLock = BusyManager.Enter(this)) {
202
if (busyLock.Success) {
203
foreach (ITypeReference constraintRef in this.Constraints) {
204
IType constraint = constraintRef.Resolve(context);
205
if (constraint.Kind == TypeKind.Interface) {
206
result.Add(constraint);
207
} else if (constraint.Kind == TypeKind.TypeParameter) {
208
result.AddRange(((ITypeParameter)constraint).GetEffectiveInterfaceSet(context));
213
return result.Distinct();
216
public override ITypeParameterConstraints GetConstraints(ITypeResolveContext context)
218
return new DefaultTypeParameterConstraints(
219
this.Constraints.Select(c => c.Resolve(context)),
220
this.HasDefaultConstructorConstraint, this.HasReferenceTypeConstraint, this.HasValueTypeConstraint);
224
* Interning for type parameters is disabled; we can't intern cyclic structures as might
225
* occur in the constraints, and incomplete interning is dangerous for type parameters
226
* as we use reference equality.
227
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
229
// protect against cyclic constraints
230
using (var busyLock = BusyManager.Enter(this)) {
231
if (busyLock.Success) {
232
constraints = provider.InternList(constraints);
233
base.PrepareForInterning(provider);
238
int ISupportsInterning.GetHashCodeForInterning()
241
int hashCode = base.GetHashCodeForInterning();
242
if (constraints != null)
243
hashCode += constraints.GetHashCode();
244
hashCode += 771 * flags.Data;
249
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
251
DefaultTypeParameter o = other as DefaultTypeParameter;
252
return base.EqualsForInterning(o)
253
&& this.constraints == o.constraints
254
&& this.flags == o.flags;