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;
23
namespace ICSharpCode.NRefactory.TypeSystem
26
/// Substitutes class and method type parameters.
28
public class TypeParameterSubstitution : TypeVisitor
31
/// The identity function.
33
public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null);
35
readonly IList<IType> classTypeArguments;
36
readonly IList<IType> methodTypeArguments;
39
/// Creates a new type parameter substitution.
41
/// <param name="classTypeArguments">
42
/// The type arguments to substitute for class type parameters.
43
/// Pass <c>null</c> to keep class type parameters unmodified.
45
/// <param name="methodTypeArguments">
46
/// The type arguments to substitute for method type parameters.
47
/// Pass <c>null</c> to keep method type parameters unmodified.
49
public TypeParameterSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments)
51
this.classTypeArguments = classTypeArguments;
52
this.methodTypeArguments = methodTypeArguments;
56
/// Gets the list of class type arguments.
57
/// Returns <c>null</c> if this substitution keeps class type parameters unmodified.
59
public IList<IType> ClassTypeArguments {
60
get { return classTypeArguments; }
64
/// Gets the list of method type arguments.
65
/// Returns <c>null</c> if this substitution keeps method type parameters unmodified.
67
public IList<IType> MethodTypeArguments {
68
get { return methodTypeArguments; }
73
/// Computes a single TypeParameterSubstitution so that for all types <c>t</c>:
74
/// <c>t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g)</c>
76
/// <remarks>If you consider type parameter substitution to be a function, this is function composition.</remarks>
77
public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f)
81
if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null))
83
// The composition is a copy of 'f', with 'g' applied on the array elements.
84
// If 'f' has a null list (keeps type parameters unmodified), we have to treat it as
85
// the identity function, and thus use the list from 'g'.
86
var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments;
87
var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments;
88
return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments);
91
static IList<IType> GetComposedTypeArguments(IList<IType> input, TypeParameterSubstitution substitution)
93
IType[] result = new IType[input.Count];
94
for (int i = 0; i < result.Length; i++) {
95
result[i] = input[i].AcceptVisitor(substitution);
101
#region Equals and GetHashCode implementation
102
public override bool Equals(object obj)
104
TypeParameterSubstitution other = obj as TypeParameterSubstitution;
107
return TypeListEquals(classTypeArguments, other.classTypeArguments)
108
&& TypeListEquals(methodTypeArguments, other.methodTypeArguments);
111
public override int GetHashCode()
114
return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments);
118
static bool TypeListEquals(IList<IType> a, IList<IType> b)
122
if (a == null || b == null)
124
if (a.Count != b.Count)
126
for (int i = 0; i < a.Count; i++) {
127
if (!a[i].Equals(b[i]))
133
static int TypeListHashCode(IList<IType> obj)
139
foreach (var element in obj) {
141
hashCode += element.GetHashCode();
148
public override IType VisitTypeParameter(ITypeParameter type)
150
int index = type.Index;
151
if (classTypeArguments != null && type.OwnerType == EntityType.TypeDefinition) {
152
if (index >= 0 && index < classTypeArguments.Count)
153
return classTypeArguments[index];
155
return SpecialType.UnknownType;
156
} else if (methodTypeArguments != null && type.OwnerType == EntityType.Method) {
157
if (index >= 0 && index < methodTypeArguments.Count)
158
return methodTypeArguments[index];
160
return SpecialType.UnknownType;
162
return base.VisitTypeParameter(type);
166
public override string ToString()
168
StringBuilder b = new StringBuilder();
171
if (classTypeArguments != null) {
172
for (int i = 0; i < classTypeArguments.Count; i++) {
173
if (first) first = false; else b.Append(", ");
177
b.Append(classTypeArguments[i].ReflectionName);
180
if (methodTypeArguments != null) {
181
for (int i = 0; i < methodTypeArguments.Count; i++) {
182
if (first) first = false; else b.Append(", ");
186
b.Append(methodTypeArguments[i].ReflectionName);