Browse Source

Rewrite of the substitution logic in SpecializedMember.

Specializing an already-specialized member now produces the same result as performing the two specializations in a single step.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
777be39cca
  1. 11
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  2. 2
      ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  3. 11
      ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  4. 13
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  5. 48
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  6. 2
      ICSharpCode.NRefactory/Editor/ITextSource.cs
  7. 17
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  8. 1
      ICSharpCode.NRefactory/TypeSystem/IMember.cs
  9. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
  10. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  11. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs
  12. 23
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs
  13. 15
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs
  14. 184
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs
  15. 103
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  16. 21
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs
  17. 45
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs
  18. 94
      ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs

11
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -1167,13 +1167,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1167,13 +1167,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal readonly IParameterizedMember nonLiftedOperator;
public LiftedUserDefinedOperator(IMethod nonLiftedMethod)
: base(nonLiftedMethod.DeclaringType, (IMethod)nonLiftedMethod.MemberDefinition,
EmptyList<IType>.Instance, new MakeNullableVisitor(nonLiftedMethod.Compilation))
: base(nonLiftedMethod, TypeParameterSubstitution.Identity)
{
this.nonLiftedOperator = nonLiftedMethod;
var substitution = new MakeNullableVisitor(nonLiftedMethod.Compilation);
this.Parameters = base.CreateParameters(substitution);
// Comparison operators keep the 'bool' return type even when lifted.
if (IsComparisonOperator(nonLiftedMethod))
this.ReturnType = nonLiftedMethod.ReturnType;
else
this.ReturnType = nonLiftedMethod.ReturnType.AcceptVisitor(substitution);
}
public IList<IParameter> NonLiftedParameters {
@ -1726,13 +1729,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1726,13 +1729,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (typeArguments != null && typeArguments.Count > 0) {
if (method.TypeParameters.Count != typeArguments.Count)
continue;
SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments);
SpecializedMethod sm = new SpecializedMethod(method, new TypeParameterSubstitution(null, typeArguments));
if (IsEligibleExtensionMethod(targetType, method, false, out inferredTypes))
outputGroup.Add(sm);
} else {
if (IsEligibleExtensionMethod(targetType, method, true, out inferredTypes)) {
if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes));
outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else {
outputGroup.Add(method);
}

2
ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs

@ -164,7 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -164,7 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.TargetType, method, true, out inferredTypes))
{
if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes));
outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else {
outputGroup.Add(method);
}

11
ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

@ -807,7 +807,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -807,7 +807,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return null;
IMethod method = bestCandidate.Member as IMethod;
if (method != null && method.TypeParameters.Count > 0) {
return new SpecializedMethod(method.DeclaringType, (IMethod)method.MemberDefinition, bestCandidate.InferredTypes);
SpecializedMethod sm = method as SpecializedMethod;
if (sm != null) {
// Do not compose the substitutions, but merge them.
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
return new SpecializedMethod(
(IMethod)method.MemberDefinition,
new TypeParameterSubstitution(sm.Substitution.ClassTypeArguments, bestCandidate.InferredTypes));
} else {
return new SpecializedMethod(method, new TypeParameterSubstitution(null, bestCandidate.InferredTypes));
}
} else {
return bestCandidate.Member;
}

13
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs

@ -260,5 +260,18 @@ class Test { @@ -260,5 +260,18 @@ class Test {
Assert.AreEqual("Test", rr.Type.ReflectionName);
Assert.AreEqual(5, rr.InitializerStatements.Count);
}
[Test]
public void CreateGeneric()
{
string program = @"using System;
class Test<T> where T : new() {
object x = $new T()$;
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind);
Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind);
}
}
}

48
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -182,6 +182,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -182,6 +182,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex");
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name);
@ -190,6 +191,53 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -190,6 +191,53 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
}
[Test]
public void GetIndexSpecializedTypeParameter()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
var m = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int16), compilation.FindType(KnownTypeCode.Int32) },
null
));
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name);
Assert.AreEqual(1, constraint.TypeParameterCount);
Assert.AreEqual(1, constraint.TypeArguments.Count);
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
}
[Test]
public void GetIndexDoubleSpecialization()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
// GenericClass<A, B>.GetIndex<T>
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
// GenericClass<B, A>.GetIndex<A>
var m1 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { testClass.TypeParameters[1], testClass.TypeParameters[0] },
new[] { testClass.TypeParameters[0] }
));
// GenericClass<string, int>.GetIndex<int>
var m2 = new SpecializedMethod(m1, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int32), compilation.FindType(KnownTypeCode.String) },
null
));
// GenericClass<string, int>.GetIndex<int>
var m12 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.String), compilation.FindType(KnownTypeCode.Int32) },
new[] { compilation.FindType(KnownTypeCode.Int32) }
));
Assert.AreEqual(m12, m2);
}
[Test]
public void GenericEnum()
{

2
ICSharpCode.NRefactory/Editor/ITextSource.cs

@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.Editor @@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.Editor
/// <remarks>
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
/// or even to implement incremental parsers.
/// It is a separate class from ITextBuffer to allow the GC to collect the text buffer while
/// It is a separate class from ITextSource to allow the GC to collect the text source while
/// the version checkpoint is still in use.
/// </remarks>
public interface ITextSourceVersion

17
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -246,19 +246,10 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -246,19 +246,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
{
if (type == null)
throw new ArgumentNullException("type");
ITypeDefinition def = type.GetDefinition();
if (def != null && def.Kind == TypeKind.Delegate) {
foreach (IMember member in def.Members) {
if (member.Name == "Invoke" && member is IMethod) {
ParameterizedType pt = type as ParameterizedType;
if (pt != null) {
return new SpecializedMethod(pt, (IMethod)member);
}
return (IMethod)member;
}
}
}
return null;
if (type.Kind == TypeKind.Delegate)
return type.GetMethods(m => m.Name == "Invoke", GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
else
return null;
}
#endregion

1
ICSharpCode.NRefactory/TypeSystem/IMember.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{

2
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs

@ -261,7 +261,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -261,7 +261,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) {
if (filter == null || filter(dummyConstructor)) {
var resolvedCtor = GetDummyConstructor(compilation);
IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList<IType>.Instance);
IMethod m = new SpecializedMethod(resolvedCtor, TypeParameterSubstitution.Identity) { DeclaringType = this };
return new [] { m };
}
}

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -781,7 +781,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -781,7 +781,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IType coClass = ComHelper.GetCoClass(this);
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
return coClass.GetConstructors(filter, options).Select(m => new SpecializedMethod(this, m));
return coClass.GetConstructors(filter, options)
.Select(m => new SpecializedMethod(m, TypeParameterSubstitution.Identity) { DeclaringType = this });
}
}
return EmptyList<IMethod>.Instance;

10
ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs

@ -132,7 +132,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -132,7 +132,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else
substitution = new TypeParameterSubstitution(null, methodTypeArguments);
}
yield return new SpecializedMethod(baseType, m, methodTypeArguments, substitution);
yield return new SpecializedMethod(m, substitution);
}
} else {
foreach (IMethod m in declaredMethods) {
@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredCtors.Select(m => new SpecializedMethod(pt, m, null, substitution));
return declaredCtors.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt });
} else {
return declaredCtors;
}
@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredProperties.Select(m => new SpecializedProperty(pt, m, substitution));
return declaredProperties.Select(m => new SpecializedProperty(m, substitution) { DeclaringType = pt });
} else {
return declaredProperties;
}
@ -216,7 +216,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -216,7 +216,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredFields.Select(m => new SpecializedField(pt, m, substitution));
return declaredFields.Select(m => new SpecializedField(m, substitution) { DeclaringType = pt });
} else {
return declaredFields;
}
@ -243,7 +243,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -243,7 +243,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredEvents.Select(m => new SpecializedEvent(pt, m, substitution));
return declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt });
} else {
return declaredEvents;
}

23
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IEvent eventDefinition;
public SpecializedEvent(IType declaringType, IEvent eventDefinition)
: base(declaringType, eventDefinition)
public SpecializedEvent(IEvent eventDefinition, TypeParameterSubstitution substitution)
: base(eventDefinition)
{
this.eventDefinition = eventDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedEvent(IType declaringType, IEvent eventDefinition, TypeVisitor substitution)
: base(declaringType, eventDefinition)
{
this.eventDefinition = eventDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.eventDefinition = (IEvent)base.MemberDefinition;
}
public bool CanAdd {
@ -53,16 +46,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -53,16 +46,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return eventDefinition.CanInvoke; }
}
IMethod addAccessor, removeAccessor, invokeAccessor;
public IMethod AddAccessor {
get { return WrapAccessor(eventDefinition.AddAccessor); }
get { return WrapAccessor(ref this.addAccessor, eventDefinition.AddAccessor); }
}
public IMethod RemoveAccessor {
get { return WrapAccessor(eventDefinition.RemoveAccessor); }
get { return WrapAccessor(ref this.removeAccessor, eventDefinition.RemoveAccessor); }
}
public IMethod InvokeAccessor {
get { return WrapAccessor(eventDefinition.InvokeAccessor); }
get { return WrapAccessor(ref this.invokeAccessor, eventDefinition.InvokeAccessor); }
}
}
}

15
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IField fieldDefinition;
public SpecializedField(IType declaringType, IField fieldDefinition)
: base(declaringType, fieldDefinition)
public SpecializedField(IField fieldDefinition, TypeParameterSubstitution substitution)
: base(fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedField(IType declaringType, IField fieldDefinition, TypeVisitor substitution)
: base(declaringType, fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.fieldDefinition = (IField)base.MemberDefinition;
}
public bool IsReadOnly {

184
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
@ -31,58 +32,115 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -31,58 +32,115 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary>
public abstract class SpecializedMember : IMember
{
readonly IType declaringType;
readonly IMember memberDefinition;
TypeParameterSubstitution substitution;
IType declaringType;
IType returnType;
protected SpecializedMember(IType declaringType, IMember memberDefinition)
protected SpecializedMember(IMember memberDefinition)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (memberDefinition == null)
throw new ArgumentNullException("memberDefinition");
this.declaringType = declaringType;
this.memberDefinition = memberDefinition;
SpecializedMember sm = memberDefinition as SpecializedMember;
if (sm != null) {
this.memberDefinition = sm.memberDefinition;
this.substitution = sm.substitution;
} else {
this.memberDefinition = memberDefinition;
this.substitution = TypeParameterSubstitution.Identity;
}
}
protected virtual void Initialize(TypeVisitor substitution)
/// <summary>
/// Performs a substitution. This method may only be called by constructors in derived classes.
/// </summary>
protected void AddSubstitution(TypeParameterSubstitution newSubstitution)
{
this.returnType = Substitute(memberDefinition.ReturnType, substitution);
Debug.Assert(declaringType == null);
Debug.Assert(returnType == null);
this.substitution = TypeParameterSubstitution.Compose(newSubstitution, this.substitution);
}
public virtual IMemberReference ToMemberReference()
public static SpecializedMember Create(IMember memberDefinition, TypeParameterSubstitution substitution)
{
return new SpecializingMemberReference(declaringType.ToTypeReference(), memberDefinition.ToMemberReference());
if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod((IMethod)memberDefinition, substitution);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty((IProperty)memberDefinition, substitution);
} else if (memberDefinition is IField) {
return new SpecializedField((IField)memberDefinition, substitution);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent((IEvent)memberDefinition, substitution);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
}
internal static TypeVisitor GetSubstitution(IType declaringType)
public IMemberReference ToMemberReference()
{
ParameterizedType pt = declaringType as ParameterizedType;
if (pt != null)
return pt.GetSubstitution();
else
return null;
return new SpecializingMemberReference(
memberDefinition.ToMemberReference(),
ToTypeReference(substitution.ClassTypeArguments),
ToTypeReference(substitution.MethodTypeArguments));
}
internal static IType Substitute(IType type, TypeVisitor substitution)
static IList<ITypeReference> ToTypeReference(IList<IType> typeArguments)
{
if (substitution == null)
return type;
if (typeArguments == null)
return null;
else
return type.AcceptVisitor(substitution);
return typeArguments.Select(t => t.ToTypeReference()).ToArray();
}
internal IMethod WrapAccessor(IMethod accessorDefinition)
internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition)
{
if (accessorDefinition == null)
return null;
var result = LazyInit.VolatileRead(ref cachingField);
if (result != null)
return result;
else
return new SpecializedMethod(declaringType, accessorDefinition);
return LazyInit.GetOrSet(ref cachingField, new SpecializedMethod(accessorDefinition, substitution));
}
/// <summary>
/// Gets the substitution belonging to this specialized member.
/// </summary>
public TypeParameterSubstitution Substitution {
get { return substitution; }
}
public IType DeclaringType {
get { return declaringType; }
get {
var result = LazyInit.VolatileRead(ref this.declaringType);
if (result != null)
return result;
IType definitionDeclaringType = memberDefinition.DeclaringType;
ITypeDefinition definitionDeclaringTypeDef = definitionDeclaringType as ITypeDefinition;
if (definitionDeclaringTypeDef != null && definitionDeclaringType.TypeParameterCount > 0) {
if (substitution.ClassTypeArguments != null && substitution.ClassTypeArguments.Count == definitionDeclaringType.TypeParameterCount) {
result = new ParameterizedType(definitionDeclaringTypeDef, substitution.ClassTypeArguments);
} else {
result = new ParameterizedType(definitionDeclaringTypeDef, definitionDeclaringTypeDef.TypeParameters).AcceptVisitor(substitution);
}
} else {
result = definitionDeclaringType.AcceptVisitor(substitution);
}
return LazyInit.GetOrSet(ref this.declaringType, result);
}
internal set {
// This setter is used as an optimization when the code constructing
// the SpecializedMember already knows the declaring type.
Debug.Assert(this.declaringType == null);
Debug.Assert(value != null);
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.declaringType = value;
}
}
public IMember MemberDefinition {
@ -94,8 +152,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -94,8 +152,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
public IType ReturnType {
get { return returnType; }
protected set { returnType = value; }
get {
var result = LazyInit.VolatileRead(ref this.returnType);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.returnType, memberDefinition.ReturnType.AcceptVisitor(substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.returnType = value;
}
}
public bool IsVirtual {
@ -143,19 +214,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -143,19 +214,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
var definitionImplementations = memberDefinition.ImplementedInterfaceMembers;
IMember[] result = new IMember[definitionImplementations.Count];
for (int i = 0; i < result.Length; i++) {
result[i] = Specialize(definitionImplementations[i]);
result[i] = SpecializedMember.Create(definitionImplementations[i], substitution);
}
return result;
}
/// <summary>
/// Specialize another member using the same type arguments as this member.
/// </summary>
protected virtual IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(declaringType, memberDefinition, null);
}
public bool IsExplicitInterfaceImplementation {
get { return memberDefinition.IsExplicitInterfaceImplementation; }
}
@ -241,13 +304,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -241,13 +304,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
SpecializedMember other = obj as SpecializedMember;
if (other == null)
return false;
return this.declaringType.Equals(other.declaringType) && this.memberDefinition.Equals(other.memberDefinition);
return this.memberDefinition.Equals(other.memberDefinition) && this.substitution.Equals(other.substitution);
}
public override int GetHashCode()
{
unchecked {
return 1000000007 * declaringType.GetHashCode() + 1000000009 * memberDefinition.GetHashCode();
return 1000000007 * memberDefinition.GetHashCode() + 1000000009 * substitution.GetHashCode();
}
}
@ -256,11 +319,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -256,11 +319,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
StringBuilder b = new StringBuilder("[");
b.Append(GetType().Name);
b.Append(' ');
b.Append(declaringType.ToString());
b.Append(this.DeclaringType.ToString());
b.Append('.');
b.Append(this.Name);
b.Append(':');
b.Append(returnType.ToString());
b.Append(this.ReturnType.ToString());
b.Append(']');
return b.ToString();
}
@ -270,36 +333,48 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -270,36 +333,48 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
IList<IParameter> parameters;
protected SpecializedParameterizedMember(IType declaringType, IParameterizedMember memberDefinition)
: base(declaringType, memberDefinition)
protected SpecializedParameterizedMember(IParameterizedMember memberDefinition)
: base(memberDefinition)
{
}
protected override void Initialize(TypeVisitor substitution)
public IList<IParameter> Parameters {
get {
var result = LazyInit.VolatileRead(ref this.parameters);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.parameters, CreateParameters(this.Substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.parameters = value;
}
}
protected IList<IParameter> CreateParameters(TypeVisitor substitution)
{
base.Initialize(substitution);
var paramDefs = ((IParameterizedMember)this.MemberDefinition).Parameters;
if (paramDefs.Count == 0) {
this.parameters = EmptyList<IParameter>.Instance;
return EmptyList<IParameter>.Instance;
} else {
var parameters = new IParameter[paramDefs.Count];
for (int i = 0; i < parameters.Length; i++) {
IType newType = Substitute(paramDefs[i].Type, substitution);
IType newType = paramDefs[i].Type.AcceptVisitor(substitution);
if (newType != paramDefs[i].Type) {
parameters[i] = new SpecializedParameter(paramDefs[i], newType);
} else {
parameters[i] = paramDefs[i];
}
}
this.parameters = Array.AsReadOnly(parameters);
return Array.AsReadOnly(parameters);
}
}
public IList<IParameter> Parameters {
get { return parameters; }
}
public override string ToString()
{
StringBuilder b = new StringBuilder("[");
@ -309,9 +384,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -309,9 +384,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append('.');
b.Append(this.Name);
b.Append('(');
for (int i = 0; i < parameters.Count; i++) {
for (int i = 0; i < this.Parameters.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(parameters[i].ToString());
b.Append(this.Parameters[i].ToString());
}
b.Append("):");
b.Append(this.ReturnType.ToString());
@ -326,7 +401,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -326,7 +401,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public SpecializedParameter(IParameter originalParameter, IType newType)
{
this.originalParameter = originalParameter;
if (originalParameter is SpecializedParameter)
this.originalParameter = ((SpecializedParameter)originalParameter).originalParameter;
else
this.originalParameter = originalParameter;
this.newType = newType;
}

103
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

@ -32,50 +32,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -32,50 +32,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public class SpecializedMethod : SpecializedParameterizedMember, IMethod
{
readonly IMethod methodDefinition;
readonly IList<IType> typeArguments;
readonly IList<ITypeParameter> specializedTypeParameters;
readonly ITypeParameter[] specializedTypeParameters;
public SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments = null)
: this(declaringType, methodDefinition, typeArguments, GetSubstitution(declaringType, typeArguments))
public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution)
: base(methodDefinition)
{
}
internal protected SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments, TypeVisitor substitution)
: base(declaringType, methodDefinition)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (methodDefinition == null)
throw new ArgumentNullException("methodDefinition");
// The base ctor might have unpacked a SpecializedMember
// (in case we are specializing an already-specialized method)
methodDefinition = (IMethod)base.MemberDefinition;
this.methodDefinition = methodDefinition;
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
if (methodDefinition.TypeParameters.Any(ConstraintNeedsSpecialization)) {
// The method is generic, and we need to specialize the type parameters
specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count];
for (int i = 0; i < specializedTypeParameters.Count; i++) {
for (int i = 0; i < specializedTypeParameters.Length; i++) {
ITypeParameter tp = methodDefinition.TypeParameters[i];
if (ConstraintNeedsSpecialization(tp))
tp = new SpecializedTypeParameter(tp, this, substitution);
tp = new SpecializedTypeParameter(tp, this);
specializedTypeParameters[i] = tp;
}
// add substitution that replaces the base method's type parameters with our specialized version
AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters));
}
if (typeArguments != null && typeArguments.Count > 0) {
if (typeArguments.Count != methodDefinition.TypeParameters.Count)
throw new ArgumentException("Incorrect number of type arguments");
} else if (specializedTypeParameters != null) {
// No type arguments were specified, but the method is generic.
// -> substitute original type parameters with the specialized ones
substitution = GetSubstitution(declaringType, specializedTypeParameters.ToArray<IType>());
for (int i = 0; i < specializedTypeParameters.Count; i++) {
if (ConstraintNeedsSpecialization(methodDefinition.TypeParameters[i])) {
((SpecializedTypeParameter)specializedTypeParameters[i]).substitution = substitution;
}
// Add the main substitution after the method type parameter specialization.
AddSubstitution(substitution);
if (specializedTypeParameters != null) {
// Set the substitution on the type parameters to the final composed substitution
foreach (var tp in specializedTypeParameters.OfType<SpecializedTypeParameter>()) {
if (tp.Owner == this)
tp.substitution = base.Substitution;
}
}
Initialize(substitution);
}
static bool ConstraintNeedsSpecialization(ITypeParameter tp)
@ -95,53 +81,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -95,53 +81,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return null;
}
public override IMemberReference ToMemberReference()
{
return new SpecializingMemberReference(
this.DeclaringType.ToTypeReference(),
this.MemberDefinition.ToMemberReference(),
typeArguments.Select(ta => ta.ToTypeReference()).ToList()
);
}
protected override IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(this.DeclaringType, this.MemberDefinition, typeArguments);
}
/// <summary>
/// Gets the type arguments passed to this method.
/// If only the type parameters for the class were specified and the generic method
/// itself is not specialized yet, this property will return an empty list.
/// </summary>
public IList<IType> TypeArguments {
get { return typeArguments; }
}
public override int GetHashCode()
{
int hashCode = base.GetHashCode();
unchecked {
for (int i = 0; i < typeArguments.Count; i++) {
hashCode *= 362631391;
hashCode += typeArguments[i].GetHashCode();
}
}
return hashCode;
}
public override bool Equals(object obj)
{
SpecializedMethod other = obj as SpecializedMethod;
if (!base.Equals(other))
return false;
if (typeArguments.Count != other.typeArguments.Count)
return false;
for (int i = 0; i < typeArguments.Count; i++) {
if (!typeArguments[i].Equals(other.typeArguments[i]))
return false;
}
return true;
get { return this.Substitution.MethodTypeArguments ?? EmptyList<IType>.Instance; }
}
public IList<IUnresolvedMethod> Parts {
@ -182,11 +128,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -182,11 +128,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append(this.DeclaringType.ToString());
b.Append('.');
b.Append(this.Name);
if (typeArguments.Count > 0) {
if (this.TypeArguments.Count > 0) {
b.Append('[');
for (int i = 0; i < typeArguments.Count; i++) {
for (int i = 0; i < this.TypeArguments.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(typeArguments[i].ToString());
b.Append(this.TypeArguments[i].ToString());
}
b.Append(']');
}
@ -205,14 +151,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -205,14 +151,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly ITypeParameter baseTp;
// not readonly: The substition may be replaced at the end of SpecializedMethod constructor
// The substition is set at the end of SpecializedMethod constructor
internal TypeVisitor substitution;
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner, TypeVisitor substitution)
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner)
: base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region)
{
// We don't have to consider already-specialized baseTps because
// we read the baseTp directly from the unpacked memberDefinition.
this.baseTp = baseTp;
this.substitution = substitution;
}
public override int GetHashCode()

21
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IProperty propertyDefinition;
public SpecializedProperty(IType declaringType, IProperty propertyDefinition)
: base(declaringType, propertyDefinition)
public SpecializedProperty(IProperty propertyDefinition, TypeParameterSubstitution substitution)
: base(propertyDefinition)
{
this.propertyDefinition = propertyDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedProperty(IType declaringType, IProperty propertyDefinition, TypeVisitor substitution)
: base(declaringType, propertyDefinition)
{
this.propertyDefinition = propertyDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.propertyDefinition = (IProperty)base.MemberDefinition;
}
public bool CanGet {
@ -49,12 +42,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -49,12 +42,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return propertyDefinition.CanSet; }
}
IMethod getter, setter;
public IMethod Getter {
get { return WrapAccessor(propertyDefinition.Getter); }
get { return WrapAccessor(ref this.getter, propertyDefinition.Getter); }
}
public IMethod Setter {
get { return WrapAccessor(propertyDefinition.Setter); }
get { return WrapAccessor(ref this.setter, propertyDefinition.Setter); }
}
public bool IsIndexer {

45
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs

@ -24,50 +24,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -24,50 +24,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
[Serializable]
public sealed class SpecializingMemberReference : IMemberReference
{
ITypeReference declaringTypeReference;
IMemberReference memberDefinitionReference;
IList<ITypeReference> typeArgumentReferences;
IList<ITypeReference> classTypeArgumentReferences;
IList<ITypeReference> methodTypeArgumentReferences;
public SpecializingMemberReference(ITypeReference declaringTypeReference, IMemberReference memberDefinitionReference, IList<ITypeReference> typeArgumentReferences = null)
public SpecializingMemberReference(IMemberReference memberDefinitionReference, IList<ITypeReference> classTypeArgumentReferences = null, IList<ITypeReference> methodTypeArgumentReferences = null)
{
if (declaringTypeReference == null)
throw new ArgumentNullException("declaringTypeReference");
if (memberDefinitionReference == null)
throw new ArgumentNullException("memberDefinitionReference");
this.declaringTypeReference = declaringTypeReference;
this.memberDefinitionReference = memberDefinitionReference;
this.typeArgumentReferences = typeArgumentReferences;
this.classTypeArgumentReferences = classTypeArgumentReferences;
this.methodTypeArgumentReferences = methodTypeArgumentReferences;
}
public IMember Resolve(ITypeResolveContext context)
{
var declaringType = declaringTypeReference.Resolve(context);
var memberDefinition = memberDefinitionReference.Resolve(context);
IType[] typeArguments = null;
if (typeArgumentReferences != null) {
typeArguments = new IType[typeArgumentReferences.Count];
for (int i = 0; i < typeArguments.Length; i++) {
typeArguments[i] = typeArgumentReferences[i].Resolve(context);
}
}
return CreateSpecializedMember(declaringType, memberDefinition, typeArguments);
}
internal static IMember CreateSpecializedMember(IType declaringType, IMember memberDefinition, IList<IType> typeArguments)
{
if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod(declaringType, (IMethod)memberDefinition, typeArguments);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty(declaringType, (IProperty)memberDefinition);
} else if (memberDefinition is IField) {
return new SpecializedField(declaringType, (IField)memberDefinition);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent(declaringType, (IEvent)memberDefinition);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
return SpecializedMember.Create(
memberDefinition,
new TypeParameterSubstitution(
classTypeArgumentReferences != null ? classTypeArgumentReferences.Resolve(context) : null,
methodTypeArgumentReferences != null ? methodTypeArgumentReferences.Resolve(context) : null
)
);
}
}
}

94
ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs

@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary>
public class TypeParameterSubstitution : TypeVisitor
{
/// <summary>
/// The identity function.
/// </summary>
public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null);
readonly IList<IType> classTypeArguments;
readonly IList<IType> methodTypeArguments;
@ -47,6 +52,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -47,6 +52,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.methodTypeArguments = methodTypeArguments;
}
/// <summary>
/// Gets the list of class type arguments.
/// Returns <c>null</c> if this substitution keeps class type parameter unmodified.
/// </summary>
public IList<IType> ClassTypeArguments {
get { return classTypeArguments; }
}
public IList<IType> MethodTypeArguments {
get { return methodTypeArguments; }
}
#region Compose
/// <summary>
/// Computes a single TypeParameterSubstitution so that for all types <c>t</c>:
/// <c>t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g)</c>
/// </summary>
/// <remarks>If you consider type parameter substitution to be a function, this is function composition.</remarks>
public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f)
{
if (g == null)
return f;
if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null))
return g;
// The composition is a copy of 'f', with 'g' applied on the array elements.
// If 'f' has a null list (keeps type parameters unmodified), we have to treat it as
// the identity function, and thus use the list from 'g'.
var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments;
var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments;
return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments);
}
static IList<IType> GetComposedTypeArguments(IList<IType> input, TypeParameterSubstitution substitution)
{
IType[] result = new IType[input.Count];
for (int i = 0; i < result.Length; i++) {
result[i] = input[i].AcceptVisitor(substitution);
}
return result;
}
#endregion
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
TypeParameterSubstitution other = obj as TypeParameterSubstitution;
if (other == null)
return false;
return TypeListEquals(classTypeArguments, other.classTypeArguments)
&& TypeListEquals(methodTypeArguments, other.methodTypeArguments);
}
public override int GetHashCode()
{
unchecked {
return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments);
}
}
static bool TypeListEquals(IList<IType> a, IList<IType> b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Equals(b[i]))
return false;
}
return true;
}
static int TypeListHashCode(IList<IType> obj)
{
if (obj == null)
return 0;
unchecked {
int hashCode = 1;
foreach (var element in obj) {
hashCode *= 27;
hashCode += element.GetHashCode();
}
return hashCode;
}
}
#endregion
public override IType VisitTypeParameter(ITypeParameter type)
{
int index = type.Index;

Loading…
Cancel
Save