Browse Source

ResolveVisitor: skip tokens and comments

Make the resolver's debug output more readable.
newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
a1f613e274
  1. 4
      ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs
  2. 2
      ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
  3. 4
      ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs
  4. 10
      ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs
  5. 48
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  6. 40
      ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
  7. 6
      ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
  8. 83
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  9. 109
      ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs

4
ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// Comment.cs
//
// Author:
@ -36,7 +36,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -36,7 +36,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
public override NodeType NodeType {
get {
return NodeType.Unknown;
return NodeType.Whitespace;
}
}

2
ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs

@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
public override NodeType NodeType {
get {
return NodeType.Unknown;
return NodeType.Token;
}
}

4
ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs

@ -45,6 +45,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -45,6 +45,10 @@ namespace ICSharpCode.NRefactory.CSharp
Token,
QueryClause,
/// <summary>
/// Comment or whitespace or pre-processor directive
/// </summary>
Whitespace,
/// <summary>
/// Placeholder for a pattern
/// </summary>
Pattern

10
ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// VariableInitializer.cs
//
// Author:
@ -112,6 +112,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -112,6 +112,14 @@ namespace ICSharpCode.NRefactory.CSharp
return visitor.VisitVariableInitializer (this, data);
}
public override string ToString()
{
if (this.Initializer.IsNull)
return "[VariableInitializer " + this.Name + "]";
else
return "[VariableInitializer " + this.Name + " = " + this.Initializer.ToString() + "]";
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
VariableInitializer o = other as VariableInitializer;

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

@ -2484,4 +2484,52 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2484,4 +2484,52 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
}
/// <summary>
/// Resolver logging helper.
/// Wraps System.Diagnostics.Debug so that resolver-specific logging can be enabled/disabled on demand.
/// (it's a huge amount of debug spew and slows down the resolver quite a bit)
/// </summary>
static class Log
{
[Conditional("DEBUG")]
internal static void WriteLine(string text)
{
Debug.WriteLine(text);
}
[Conditional("DEBUG")]
internal static void WriteLine(string format, params object[] args)
{
Debug.WriteLine(format, args);
}
[Conditional("DEBUG")]
internal static void WriteCollection<T>(string text, IEnumerable<T> lines)
{
#if DEBUG
T[] arr = lines.ToArray();
if (arr.Length == 0) {
Debug.WriteLine(text + "<empty collection>");
} else {
Debug.WriteLine(text + (arr[0] != null ? arr[0].ToString() : "<null>"));
for (int i = 1; i < arr.Length; i++) {
Debug.WriteLine(new string(' ', text.Length) + (arr[i] != null ? arr[i].ToString() : "<null>"));
}
}
#endif
}
[Conditional("DEBUG")]
public static void Indent()
{
Debug.Indent();
}
[Conditional("DEBUG")]
public static void Unindent()
{
Debug.Unindent();
}
}
}

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

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -120,12 +121,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -120,12 +121,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OverloadResolution PerformOverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true)
{
Log.WriteLine("Performing overload resolution for " + this);
Log.WriteCollection(" Arguments: ", arguments);
var typeArgumentArray = this.TypeArguments.ToArray();
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, typeArgumentArray);
or.AllowExpandingParams = allowExpandingParams;
foreach (IMethod method in this.Methods) {
// TODO: grouping by class definition?
or.AddCandidate(method);
Log.Indent();
OverloadResolutionErrors errors = or.AddCandidate(method);
Log.Unindent();
LogOverloadResolution(" Candidate", method, errors, or);
}
if (allowExtensionMethods && !or.FoundApplicableCandidate) {
// No applicable match found, so let's try extension methods.
@ -133,6 +141,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -133,6 +141,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var extensionMethods = this.GetExtensionMethods();
if (extensionMethods.Count > 0) {
Log.WriteLine("No candidate is applicable, trying {0} extension methods groups...", extensionMethods.Count);
ResolveResult[] extArguments = new ResolveResult[arguments.Length + 1];
extArguments[0] = new ResolveResult(this.TargetType);
arguments.CopyTo(extArguments, 1);
@ -146,8 +155,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -146,8 +155,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
extOr.IsExtensionMethodInvocation = true;
foreach (var g in extensionMethods) {
foreach (var m in g) {
extOr.AddCandidate(m);
foreach (var method in g) {
Log.Indent();
OverloadResolutionErrors errors = extOr.AddCandidate(method);
Log.Unindent();
LogOverloadResolution(" Extension", method, errors, or);
}
if (extOr.FoundApplicableCandidate)
break;
@ -161,9 +173,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -161,9 +173,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
}
Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.BestCandidate);
return or;
}
[Conditional("DEBUG")]
void LogOverloadResolution(string text, IMethod method, OverloadResolutionErrors errors, OverloadResolution or)
{
#if DEBUG
StringBuilder b = new StringBuilder(text);
b.Append(' ');
b.Append(method);
b.Append(" = ");
if (errors == OverloadResolutionErrors.None)
b.Append("Success");
else
b.Append(errors);
if (or.BestCandidate == method) {
b.Append(" (best candidate so far)");
} else if (or.BestCandidateAmbiguousWith == method) {
b.Append(" (ambiguous)");
}
Log.WriteLine(b.ToString());
#endif
}
public override IEnumerable<ResolveResult> GetChildResults()
{
if (targetResult != null)

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

@ -555,8 +555,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -555,8 +555,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} else {
switch (BetterFunctionMember(candidate, bestCandidate)) {
case 0:
if (bestCandidateAmbiguousWith == null)
bestCandidateAmbiguousWith = candidate;
// Overwrite 'bestCandidateAmbiguousWith' so that API users can
// detect the set of all ambiguous methods if they look at
// bestCandidateAmbiguousWith after each step.
bestCandidateAmbiguousWith = candidate;
break;
case 1:
bestCandidate = candidate;

83
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -146,6 +146,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -146,6 +146,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (node == null || node.IsNull)
return;
switch (node.NodeType) {
case NodeType.Token:
case NodeType.Whitespace:
return; // skip tokens, identifiers, comments, etc.
}
if (mode == ResolveVisitorNavigationMode.ResolveAll) {
Resolve(node);
} else {
@ -189,6 +194,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -189,6 +194,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
resolver.cancellationToken.ThrowIfCancellationRequested();
resolverBeforeDict[node] = resolver.Clone();
result = resolveResultCache[node] = node.AcceptVisitor(this, null) ?? errorResult;
Log.WriteLine("Resolved '{0}' to {1}", node, result);
ProcessConversionsInResult(result);
}
if (wasScan)
@ -265,17 +271,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -265,17 +271,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
void ProcessConversion(ResolveResult rr, Conversion conversion, IType targetType)
{
if (conversion.IsAnonymousFunctionConversion) {
Debug.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
AnonymousFunctionConversionData data = conversion.data as AnonymousFunctionConversionData;
if (data != null) {
Debug.Indent();
Log.Indent();
if (data.Hypothesis != null)
data.Hypothesis.MergeInto(this, data.ReturnType);
if (data.ExplicitlyTypedLambda != null)
data.ExplicitlyTypedLambda.ApplyReturnType(this, data.ReturnType);
Debug.Unindent();
Log.Unindent();
} else {
Debug.WriteLine(" Data not found.");
Log.WriteLine(" Data not found.");
}
}
}
@ -1150,10 +1156,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1150,10 +1156,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// It's ambiguous
ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
resolveResultCache[identifierExpression] = IsStaticResult(rr, null) ? trr : target;
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}",
identifierExpression, resolveResultCache[identifierExpression]);
return rr;
} else {
// It's not ambiguous
resolveResultCache[identifierExpression] = target;
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target);
if (resolverEnabled) {
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
} else {
@ -1199,14 +1208,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1199,14 +1208,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance);
ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre);
resolveResultCache[mre] = target;
Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target);
TypeResolveResult trr;
if (IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) {
// It's ambiguous
ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression);
resolveResultCache[identifierExpression] = IsStaticResult(target, rr) ? trr : idRR;
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}",
identifierExpression, resolveResultCache[identifierExpression]);
return rr;
} else {
// It's not ambiguous
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR);
resolveResultCache[identifierExpression] = idRR;
if (resolverEnabled) {
return ResolveInvocationOnGivenTarget(target, invocationExpression);
@ -1334,7 +1347,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1334,7 +1347,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (visitor.undecidedLambdas == null)
visitor.undecidedLambdas = new List<LambdaBase>();
visitor.undecidedLambdas.Add(this);
Debug.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression);
Log.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression);
}
public override IList<IParameter> Parameters {
@ -1347,16 +1360,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1347,16 +1360,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
// If it's not already analyzed
if (inferredReturnType == null) {
Debug.WriteLine("Analyzing " + this.LambdaExpression + "...");
Debug.Indent();
Log.WriteLine("Analyzing " + this.LambdaExpression + "...");
Log.Indent();
visitor.ResetContext(
storedContext,
delegate {
visitor.AnalyzeLambda(body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnValues);
});
Debug.Unindent();
Debug.WriteLine("Finished analyzing " + this.LambdaExpression);
Log.Unindent();
Log.WriteLine("Finished analyzing " + this.LambdaExpression);
if (inferredReturnType == null)
throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType");
@ -1366,11 +1379,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1366,11 +1379,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions)
{
Debug.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType);
Debug.Indent();
Log.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType);
Log.Indent();
bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, returnValues, returnType, conversions);
Debug.Unindent();
Debug.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
Log.Unindent();
Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
if (valid) {
return Conversion.AnonymousFunctionConversion(new AnonymousFunctionConversionData(returnType, this));
} else {
@ -1417,7 +1430,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1417,7 +1430,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
actualReturnType = returnType;
visitor.undecidedLambdas.Remove(this);
Analyze();
Debug.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression);
Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression);
foreach (var returnValue in returnValues) {
visitor.ProcessConversion(returnValue, returnType);
}
@ -1464,7 +1477,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1464,7 +1477,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (parentVisitor.undecidedLambdas == null)
parentVisitor.undecidedLambdas = new List<LambdaBase>();
parentVisitor.undecidedLambdas.Add(this);
Debug.WriteLine("Added undecided implicitly-typed lambda: " + lambda);
Log.WriteLine("Added undecided implicitly-typed lambda: " + lambda);
}
public override IList<IParameter> Parameters {
@ -1473,13 +1486,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1473,13 +1486,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions)
{
Debug.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...",
this, string.Join<IType>(", ", parameterTypes), returnType);
Debug.Indent();
Log.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...",
this, string.Join<IType>(", ", parameterTypes), returnType);
Log.Indent();
var hypothesis = GetHypothesis(parameterTypes);
Conversion c = hypothesis.IsValid(returnType, conversions);
Debug.Unindent();
Debug.WriteLine("{0} is {1} for return-type {2}", hypothesis, c ? "valid" : "invalid", returnType);
Log.Unindent();
Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c ? "valid" : "invalid", returnType);
return c;
}
@ -1589,8 +1602,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1589,8 +1602,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.parameterTypes = parameterTypes;
this.visitor = visitor;
Debug.WriteLine("Analyzing " + ToString() + "...");
Debug.Indent();
Log.WriteLine("Analyzing " + ToString() + "...");
Log.Indent();
visitor.resolver.PushLambdaBlock();
int i = 0;
foreach (var pd in lambda.lambda.Parameters) {
@ -1601,8 +1614,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1601,8 +1614,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
visitor.AnalyzeLambda(lambda.lambda.Body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnValues);
visitor.resolver.PopBlock();
Debug.Unindent();
Debug.WriteLine("Finished analyzing " + ToString());
Log.Unindent();
Log.WriteLine("Finished analyzing " + ToString());
}
internal int CountUnknownParameters()
@ -1643,7 +1656,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1643,7 +1656,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
visitor.MergeUndecidedLambdas();
Debug.WriteLine("Merging " + ToString());
Log.WriteLine("Merging " + ToString());
foreach (var pair in visitor.resolveResultCache) {
parentVisitor.resolveResultCache.Add(pair.Key, pair.Value);
}
@ -1684,8 +1697,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1684,8 +1697,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (undecidedLambdas == null)
return;
Debug.WriteLine("MergeUndecidedLambdas()...");
Debug.Indent();
Log.WriteLine("MergeUndecidedLambdas()...");
Log.Indent();
while (undecidedLambdas.Count > 0) {
LambdaBase lambda = undecidedLambdas[0];
AstNode parent = lambda.LambdaExpression.Parent;
@ -1693,21 +1706,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1693,21 +1706,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
parent = parent.Parent;
CSharpResolver storedResolver;
if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
Debug.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda...");
Debug.Indent();
Log.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda...");
Log.Indent();
ResetContext(storedResolver, delegate { Resolve(parent); });
Debug.Unindent();
Log.Unindent();
} else {
Debug.WriteLine("Could not find a suitable parent for '" + lambda);
Log.WriteLine("Could not find a suitable parent for '" + lambda);
}
if (lambda.IsUndecided) {
// Lambda wasn't merged by resolving its parent -> enforce merging
Debug.WriteLine("Lambda wasn't merged by conversion - enforce merging");
Log.WriteLine("Lambda wasn't merged by conversion - enforce merging");
lambda.EnforceMerge(this);
}
}
Debug.Unindent();
Debug.WriteLine("MergeUndecidedLambdas() finished.");
Log.Unindent();
Log.WriteLine("MergeUndecidedLambdas() finished.");
}
/// <summary>
@ -1750,7 +1763,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1750,7 +1763,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// so we can ignore the 'tiSuccess' value
}
}
Debug.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
// TODO: check for compiler errors within the lambda body
success = true;
}

109
ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs

@ -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 non­empty 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
}
}
}

Loading…
Cancel
Save