|
|
|
|
@ -112,18 +112,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -112,18 +112,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
this.arguments[i] = arguments[i]; |
|
|
|
|
this.parameterTypes[i] = parameterTypes[i]; |
|
|
|
|
} |
|
|
|
|
Log("Type Inference"); |
|
|
|
|
Log(" Signature: M<" + string.Join<TP>(", ", this.typeParameters) + ">" |
|
|
|
|
+ "(" + string.Join<IType>(", ", this.parameterTypes) + ")"); |
|
|
|
|
Log(" Arguments: ", arguments); |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.WriteLine("Type Inference"); |
|
|
|
|
Log.WriteLine(" Signature: M<" + string.Join<TP>(", ", this.typeParameters) + ">" |
|
|
|
|
+ "(" + string.Join<IType>(", ", this.parameterTypes) + ")"); |
|
|
|
|
Log.WriteCollection(" Arguments: ", arguments); |
|
|
|
|
Log.Indent(); |
|
|
|
|
|
|
|
|
|
PhaseOne(); |
|
|
|
|
success = PhaseTwo(); |
|
|
|
|
|
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log(" Type inference finished " + (success ? "successfully" : "with errors") + ": " + |
|
|
|
|
"M<" + string.Join(", ", this.typeParameters.Select(tp => tp.FixedTo ?? SharedTypes.UnknownType)) + ">"); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
Log.WriteLine(" Type inference finished " + (success ? "successfully" : "with errors") + ": " + |
|
|
|
|
"M<" + string.Join(", ", this.typeParameters.Select(tp => tp.FixedTo ?? SharedTypes.UnknownType)) + ">"); |
|
|
|
|
return this.typeParameters.Select(tp => tp.FixedTo ?? SharedTypes.UnknownType).ToArray(); |
|
|
|
|
} finally { |
|
|
|
|
Reset(); |
|
|
|
|
@ -228,7 +228,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -228,7 +228,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
void PhaseOne() |
|
|
|
|
{ |
|
|
|
|
// C# 4.0 spec: §7.5.2.1 The first phase
|
|
|
|
|
Log("Phase One"); |
|
|
|
|
Log.WriteLine("Phase One"); |
|
|
|
|
for (int i = 0; i < arguments.Length; i++) { |
|
|
|
|
ResolveResult Ei = arguments[i]; |
|
|
|
|
IType Ti = parameterTypes[i]; |
|
|
|
|
@ -258,7 +258,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -258,7 +258,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
bool PhaseTwo() |
|
|
|
|
{ |
|
|
|
|
// C# 4.0 spec: §7.5.2.2 The second phase
|
|
|
|
|
Log("Phase Two"); |
|
|
|
|
Log.WriteLine("Phase Two"); |
|
|
|
|
// All unfixed type variables Xi which do not depend on any Xj are fixed.
|
|
|
|
|
List<TP> typeParametersToFix = new List<TP>(); |
|
|
|
|
foreach (TP Xi in typeParameters) { |
|
|
|
|
@ -270,8 +270,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -270,8 +270,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
} |
|
|
|
|
// If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
|
|
|
|
|
if (typeParametersToFix.Count == 0) { |
|
|
|
|
Log("Type parameters cannot be fixed due to dependency cycles"); |
|
|
|
|
Log("Trying to break the cycle by fixing any TPs that have non-empty bounds..."); |
|
|
|
|
Log.WriteLine("Type parameters cannot be fixed due to dependency cycles"); |
|
|
|
|
Log.WriteLine("Trying to break the cycle by fixing any TPs that have non-empty bounds..."); |
|
|
|
|
foreach (TP Xi in typeParameters) { |
|
|
|
|
// Xi has a nonempty set of bounds
|
|
|
|
|
if (!Xi.IsFixed && Xi.HasBounds) { |
|
|
|
|
@ -293,7 +293,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -293,7 +293,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
bool unfixedTypeVariablesExist = typeParameters.Any((TP X) => X.IsFixed == false); |
|
|
|
|
if (typeParametersToFix.Count == 0 && unfixedTypeVariablesExist) { |
|
|
|
|
// If no such type variables exist and there are still unfixed type variables, type inference fails.
|
|
|
|
|
Log("Type inference fails: there are still unfixed TPs remaining"); |
|
|
|
|
Log.WriteLine("Type inference fails: there are still unfixed TPs remaining"); |
|
|
|
|
return false; |
|
|
|
|
} else if (!unfixedTypeVariablesExist) { |
|
|
|
|
// Otherwise, if no further unfixed type variables exist, type inference succeeds.
|
|
|
|
|
@ -307,7 +307,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -307,7 +307,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
// but the input types (§7.4.2.3) do not
|
|
|
|
|
if (OutputTypeContainsUnfixed(Ei, Ti) && !InputTypesContainsUnfixed(Ei, Ti)) { |
|
|
|
|
// an output type inference (§7.4.2.6) is made for ei with type Ti.
|
|
|
|
|
Log("MakeOutputTypeInference for argument #" + i); |
|
|
|
|
Log.WriteLine("MakeOutputTypeInference for argument #" + i); |
|
|
|
|
MakeOutputTypeInference(Ei, Ti); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -432,7 +432,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -432,7 +432,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
#region MakeOutputTypeInference (§7.5.2.6)
|
|
|
|
|
void MakeOutputTypeInference(ResolveResult e, IType t) |
|
|
|
|
{ |
|
|
|
|
Log(" MakeOutputTypeInference from " + e + " to " + t); |
|
|
|
|
Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t); |
|
|
|
|
// If E is an anonymous function with inferred return type U (§7.5.2.12) and T is a delegate type or expression
|
|
|
|
|
// tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb.
|
|
|
|
|
LambdaResolveResult lrr = e as LambdaResolveResult; |
|
|
|
|
@ -510,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -510,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
// C# 4.0 spec: §7.5.2.7 Explicit parameter type inferences
|
|
|
|
|
if (e.IsImplicitlyTyped || !e.HasParameterList) |
|
|
|
|
return; |
|
|
|
|
Log(" MakeExplicitParameterTypeInference from " + e + " to " + t); |
|
|
|
|
Log.WriteLine(" MakeExplicitParameterTypeInference from " + e + " to " + t); |
|
|
|
|
IMethod m = GetDelegateOrExpressionTreeSignature(t); |
|
|
|
|
if (m == null) |
|
|
|
|
return; |
|
|
|
|
@ -527,12 +527,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -527,12 +527,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
/// </summary>
|
|
|
|
|
void MakeExactInference(IType U, IType V) |
|
|
|
|
{ |
|
|
|
|
Log("MakeExactInference from " + U + " to " + V); |
|
|
|
|
Log.WriteLine("MakeExactInference from " + U + " to " + V); |
|
|
|
|
|
|
|
|
|
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
|
|
|
|
|
TP tp = GetTPForType(V); |
|
|
|
|
if (tp != null && tp.IsFixed == false) { |
|
|
|
|
Log(" Add exact bound '" + U + "' to " + tp); |
|
|
|
|
Log.WriteLine(" Add exact bound '" + U + "' to " + tp); |
|
|
|
|
tp.LowerBounds.Add(U); |
|
|
|
|
tp.UpperBounds.Add(U); |
|
|
|
|
return; |
|
|
|
|
@ -558,11 +558,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -558,11 +558,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
&& object.Equals(pU.GetDefinition(), pV.GetDefinition()) |
|
|
|
|
&& pU.TypeParameterCount == pV.TypeParameterCount) |
|
|
|
|
{ |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.Indent(); |
|
|
|
|
for (int i = 0; i < pU.TypeParameterCount; i++) { |
|
|
|
|
MakeExactInference(pU.TypeArguments[i], pV.TypeArguments[i]); |
|
|
|
|
} |
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -585,12 +585,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -585,12 +585,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
/// </summary>
|
|
|
|
|
void MakeLowerBoundInference(IType U, IType V) |
|
|
|
|
{ |
|
|
|
|
Log(" MakeLowerBoundInference from " + U + " to " + V); |
|
|
|
|
Log.WriteLine(" MakeLowerBoundInference from " + U + " to " + V); |
|
|
|
|
|
|
|
|
|
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
|
|
|
|
|
TP tp = GetTPForType(V); |
|
|
|
|
if (tp != null && tp.IsFixed == false) { |
|
|
|
|
Log(" Add lower bound '" + U + "' to " + tp); |
|
|
|
|
Log.WriteLine(" Add lower bound '" + U + "' to " + tp); |
|
|
|
|
tp.LowerBounds.Add(U); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
@ -618,7 +618,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -618,7 +618,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
return; // cannot make an inference because it's not unique
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.Indent(); |
|
|
|
|
if (uniqueBaseType != null) { |
|
|
|
|
for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { |
|
|
|
|
IType Ui = uniqueBaseType.TypeArguments[i]; |
|
|
|
|
@ -643,7 +643,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -643,7 +643,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -669,12 +669,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -669,12 +669,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
/// </summary>
|
|
|
|
|
void MakeUpperBoundInference(IType U, IType V) |
|
|
|
|
{ |
|
|
|
|
Log(" MakeUpperBoundInference from " + U + " to " + V); |
|
|
|
|
Log.WriteLine(" MakeUpperBoundInference from " + U + " to " + V); |
|
|
|
|
|
|
|
|
|
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
|
|
|
|
|
TP tp = GetTPForType(V); |
|
|
|
|
if (tp != null && tp.IsFixed == false) { |
|
|
|
|
Log(" Add upper bound '" + U + "' to " + tp); |
|
|
|
|
Log.WriteLine(" Add upper bound '" + U + "' to " + tp); |
|
|
|
|
tp.UpperBounds.Add(U); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
@ -702,7 +702,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -702,7 +702,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
return; // cannot make an inference because it's not unique
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.Indent(); |
|
|
|
|
if (uniqueBaseType != null) { |
|
|
|
|
for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { |
|
|
|
|
IType Ui = pU.TypeArguments[i]; |
|
|
|
|
@ -727,7 +727,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -727,7 +727,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
@ -735,18 +735,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -735,18 +735,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
#region Fixing (§7.5.2.11)
|
|
|
|
|
bool Fix(TP tp) |
|
|
|
|
{ |
|
|
|
|
Log(" Trying to fix " + tp); |
|
|
|
|
Log.WriteLine(" Trying to fix " + tp); |
|
|
|
|
Debug.Assert(!tp.IsFixed); |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.Indent(); |
|
|
|
|
var types = CreateNestedInstance().FindTypesInBounds(tp.LowerBounds.ToArray(), tp.UpperBounds.ToArray()); |
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
if (algorithm == TypeInferenceAlgorithm.ImprovedReturnAllResults) { |
|
|
|
|
tp.FixedTo = IntersectionType.Create(types); |
|
|
|
|
Log(" T was fixed " + (types.Count >= 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); |
|
|
|
|
Log.WriteLine(" T was fixed " + (types.Count >= 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); |
|
|
|
|
return types.Count >= 1; |
|
|
|
|
} else { |
|
|
|
|
tp.FixedTo = GetFirstTypePreferNonInterfaces(types); |
|
|
|
|
Log(" T was fixed " + (types.Count == 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); |
|
|
|
|
Log.WriteLine(" T was fixed " + (types.Count == 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); |
|
|
|
|
return types.Count == 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -756,10 +756,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -756,10 +756,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the best common type (C# 4.0 spec: §7.5.2.14) of a set of expressions.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public IType GetBestCommonType(IEnumerable<ResolveResult> expressions, out bool success) |
|
|
|
|
public IType GetBestCommonType(IList<ResolveResult> expressions, out bool success) |
|
|
|
|
{ |
|
|
|
|
if (expressions == null) |
|
|
|
|
throw new ArgumentNullException("expressions"); |
|
|
|
|
if (expressions.Count == 1) { |
|
|
|
|
success = (expressions[0].Type.Kind != TypeKind.Unknown); |
|
|
|
|
return expressions[0].Type; |
|
|
|
|
} |
|
|
|
|
Log.WriteCollection("GetBestCommonType() for ", expressions); |
|
|
|
|
try { |
|
|
|
|
this.typeParameters = new TP[1] { new TP(DummyTypeParameter.Instance) }; |
|
|
|
|
foreach (ResolveResult r in expressions) { |
|
|
|
|
@ -884,9 +889,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -884,9 +889,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
return EmptyList<IType>.Instance; |
|
|
|
|
|
|
|
|
|
// Finds a type X so that "LB <: X <: UB"
|
|
|
|
|
Log("FindTypesInBound, LowerBounds=", lowerBounds); |
|
|
|
|
Log("FindTypesInBound, UpperBounds=", upperBounds); |
|
|
|
|
Debug.Indent(); |
|
|
|
|
Log.WriteCollection("FindTypesInBound, LowerBounds=", lowerBounds); |
|
|
|
|
Log.WriteCollection("FindTypesInBound, UpperBounds=", upperBounds); |
|
|
|
|
Log.Indent(); |
|
|
|
|
|
|
|
|
|
// First try the Fixing algorithm from the C# spec (§7.5.2.11)
|
|
|
|
|
List<IType> candidateTypes = lowerBounds.Union(upperBounds) |
|
|
|
|
@ -935,7 +940,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -935,7 +940,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
if (candidateDef.TypeParameterCount == 0) { |
|
|
|
|
candidate = candidateDef; |
|
|
|
|
} else { |
|
|
|
|
Log("Inferring arguments for candidate type definition: " + candidateDef); |
|
|
|
|
Log.WriteLine("Inferring arguments for candidate type definition: " + candidateDef); |
|
|
|
|
bool success; |
|
|
|
|
IType[] result = InferTypeArgumentsFromBounds( |
|
|
|
|
candidateDef.TypeParameters, |
|
|
|
|
@ -945,11 +950,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -945,11 +950,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
if (success) { |
|
|
|
|
candidate = new ParameterizedType(candidateDef, result); |
|
|
|
|
} else { |
|
|
|
|
Log("Inference failed; ignoring candidate"); |
|
|
|
|
Log.WriteLine("Inference failed; ignoring candidate"); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Log("Candidate type: " + candidate); |
|
|
|
|
Log.WriteLine("Candidate type: " + candidate); |
|
|
|
|
|
|
|
|
|
if (lowerBounds.Count > 0) { |
|
|
|
|
// if there were lower bounds, we aim for the most specific candidate:
|
|
|
|
|
@ -973,31 +978,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -973,31 +978,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Debug.Unindent(); |
|
|
|
|
Log.Unindent(); |
|
|
|
|
return candidateTypes; |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
[Conditional("DEBUG")] |
|
|
|
|
static void Log(string text) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine(text); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
[Conditional("DEBUG")] |
|
|
|
|
static void Log<T>(string text, IEnumerable<T> lines) |
|
|
|
|
{ |
|
|
|
|
#if DEBUG
|
|
|
|
|
T[] arr = lines.ToArray(); |
|
|
|
|
if (arr.Length == 0) { |
|
|
|
|
Log(text + "<empty collection>"); |
|
|
|
|
} else { |
|
|
|
|
Log(text + (arr[0] != null ? arr[0].ToString() : "<null>")); |
|
|
|
|
for (int i = 1; i < arr.Length; i++) { |
|
|
|
|
Log(new string(' ', text.Length) + (arr[i] != null ? arr[i].ToString() : "<null>")); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|