@ -118,7 +118,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -118,7 +118,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void AddError ( OverloadResolutionErrors newError )
{
this . Errors | = newError ;
this . ErrorCount + + ;
if ( ! IsApplicable ( newError ) )
this . ErrorCount + + ;
}
}
@ -130,6 +131,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -130,6 +131,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Candidate bestCandidate ;
Candidate bestCandidateAmbiguousWith ;
IType [ ] explicitlyGivenTypeArguments ;
bool bestCandidateWasValidated ;
OverloadResolutionErrors bestCandidateValidationResult ;
#region Constructor
public OverloadResolution ( ICompilation compilation , ResolveResult [ ] arguments , string [ ] argumentNames = null , IType [ ] typeArguments = null , CSharpConversions conversions = null )
@ -155,6 +158,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -155,6 +158,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region Input Properties
/// <summary>
/// Gets/Sets whether the methods are extension methods that are being called using extension method syntax.
/// </summary>
@ -183,21 +187,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -183,21 +187,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public IList < ResolveResult > Arguments {
get { return arguments ; }
}
#endregion
#region AddCandidate
/// <summary>
/// Adds a candidate to overload resolution.
/// </summary>
/// <param name="member">The candidate member to add.</param>
/// <returns>The errors that prevent the member from being applicable, if any.
/// Note: this method does not return errors that do not affect applicability.</returns>
public OverloadResolutionErrors AddCandidate ( IParameterizedMember member )
{
return AddCandidate ( member , OverloadResolutionErrors . None ) ;
}
/// <summary>
/// Adds a candidate to overload resolution.
/// </summary>
/// <param name="member">The candidate member to add.</param>
/// <param name="additionalErrors">Additional errors that apply to the candidate.
/// This is used to represent errors during member lookup (e.g. OverloadResolutionErrors.Inaccessible)
/// in overload resolution.</param>
/// <returns>The errors that prevent the member from being applicable, if any.
/// Note: this method does not return errors that do not affect applicability.</returns>
public OverloadResolutionErrors AddCandidate ( IParameterizedMember member , OverloadResolutionErrors additionalErrors )
{
if ( member = = null )
throw new ArgumentNullException ( "member" ) ;
Candidate c = new Candidate ( member , false ) ;
if ( additionalErrors ! = OverloadResolutionErrors . None )
c . AddError ( additionalErrors ) ;
c . AddError ( additionalErrors ) ;
if ( CalculateCandidate ( c ) ) {
//candidates.Add(c);
}
@ -206,8 +225,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -206,8 +225,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
& & member . Parameters [ member . Parameters . Count - 1 ] . IsParams )
{
Candidate expandedCandidate = new Candidate ( member , true ) ;
if ( additionalErrors ! = OverloadResolutionErrors . None )
expandedCandidate . AddError ( additionalErrors ) ;
expandedCandidate . AddError ( additionalErrors ) ;
// consider expanded form only if it isn't obviously wrong
if ( CalculateCandidate ( expandedCandidate ) ) {
//candidates.Add(expandedCandidate);
@ -219,11 +237,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -219,11 +237,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return c . Errors ;
}
public static bool IsApplicable ( OverloadResolutionErrors errors )
{
return ( errors & ~ OverloadResolutionErrors . AmbiguousMatch ) = = OverloadResolutionErrors . None ;
}
/// <summary>
/// Calculates applicability etc. for the candidate.
/// </summary>
@ -236,6 +249,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -236,6 +249,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
RunTypeInference ( candidate ) ;
CheckApplicability ( candidate ) ;
ConsiderIfNewCandidateIsBest ( candidate ) ;
ValidateMethodConstraints ( candidate ) ;
return true ;
}
@ -432,20 +446,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -432,20 +446,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Validate Constraints
OverloadResolutionErrors ValidateMethodConstraints ( Candidate candidate )
{
// If type inference already failed, we won't check the constraints:
if ( ( candidate . Errors & OverloadResolutionErrors . TypeInferenceFailed ) ! = 0 )
return OverloadResolutionErrors . None ;
IMethod method = candidate . Member as IMethod ;
if ( method = = null | | method . TypeParameters . Count = = 0 )
return OverloadResolutionErrors . None ; // the method isn't generic
var substitution = GetSubstitution ( candidate ) ;
for ( int i = 0 ; i < method . TypeParameters . Count ; i + + ) {
if ( ! ValidateConstraints ( method . TypeParameters [ i ] , substitution . MethodTypeArguments [ i ] , substitution ) )
return OverloadResolutionErrors . MethodConstraintsNotSatisfied ;
}
return OverloadResolutionErrors . None ;
}
/// <summary>
/// Validates whether the given type argument satisfies the constraints for the given type parameter.
/// </summary>
/// <param name="typeParameter">The type parameter.</param>
/// <param name="typeArgument">The type argument.</param>
/// <param name="substitution">The substitution that defines how type parameters are replaced with type arguments.
/// The substitution is used to check constraints that depend on other type parameters (or recursively on the same type parameter).</param>
/// The substitution is used to check constraints that depend on other type parameters (or recursively on the same type parameter).
/// May be null if no substitution should be used.</param>
/// <returns>True if the constraints are satisfied; false otherwise.</returns>
public static bool ValidateConstraints ( ITypeParameter typeParameter , IType typeArgument , TypeVisitor substitution )
public static bool ValidateConstraints ( ITypeParameter typeParameter , IType typeArgument , TypeVisitor substitution = null )
{
if ( typeParameter = = null )
throw new ArgumentNullException ( "typeParameter" ) ;
if ( typeParameter . Owner = = null )
throw new ArgumentNullException ( "typeParameter.Owner" ) ;
if ( typeArgument = = null )
throw new ArgumentNullException ( "typeArgument" ) ;
return ValidateConstraints ( typeParameter , typeArgument , substitution , CSharpConversions . Get ( typeParameter . Owner . Compilation ) ) ;
@ -490,6 +520,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -490,6 +520,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region CheckApplicability
/// <summary>
/// Returns whether a candidate with the given errors is still considered to be applicable.
/// </summary>
public static bool IsApplicable ( OverloadResolutionErrors errors )
{
const OverloadResolutionErrors errorsThatDoNotMatterForApplicability =
OverloadResolutionErrors . AmbiguousMatch | OverloadResolutionErrors . MethodConstraintsNotSatisfied ;
return ( errors & ~ errorsThatDoNotMatterForApplicability ) = = OverloadResolutionErrors . None ;
}
void CheckApplicability ( Candidate candidate )
{
// C# 4.0 spec: §7.5.3.1 Applicable function member
@ -697,6 +737,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -697,6 +737,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if ( bestCandidate = = null ) {
bestCandidate = candidate ;
bestCandidateWasValidated = false ;
} else {
switch ( BetterFunctionMember ( candidate , bestCandidate ) ) {
case 0 :
@ -707,6 +748,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -707,6 +748,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
break ;
case 1 :
bestCandidate = candidate ;
bestCandidateWasValidated = false ;
bestCandidateAmbiguousWith = null ;
break ;
// case 2: best candidate stays best
@ -715,15 +757,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -715,15 +757,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region Output Properties
public IParameterizedMember BestCandidate {
get { return bestCandidate ! = null ? bestCandidate . Member : null ; }
}
/// <summary>
/// Returns the errors that apply to the best candidate.
/// This includes additional errors that do not affect applicability (e.g. AmbiguousMatch, MethodConstraintsNotSatisfied)
/// </summary>
public OverloadResolutionErrors BestCandidateErrors {
get {
if ( bestCandidate = = null )
return OverloadResolutionErrors . None ;
OverloadResolutionErrors err = bestCandidate . Errors ;
if ( ! bestCandidateWasValidated ) {
bestCandidateValidationResult = ValidateMethodConstraints ( bestCandidate ) ;
bestCandidateWasValidated = true ;
}
OverloadResolutionErrors err = bestCandidate . Errors | bestCandidateValidationResult ;
if ( bestCandidateAmbiguousWith ! = null )
err | = OverloadResolutionErrors . AmbiguousMatch ;
return err ;
@ -731,7 +782,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -731,7 +782,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
public bool FoundApplicableCandidate {
get { return bestCandidate ! = null & & bestCandidate . Errors = = OverloadResolutionErrors . None ; }
get { return bestCandidate ! = null & & IsApplicable ( bestCandidate . Errors ) ; }
}
public IParameterizedMember BestCandidateAmbiguousWith {
@ -848,21 +899,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -848,21 +899,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return null ;
IMethod method = bestCandidate . Member as IMethod ;
if ( method ! = null & & method . TypeParameters . Count > 0 ) {
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 ) ) ;
}
return new SpecializedMethod ( ( IMethod ) method . MemberDefinition , GetSubstitution ( bestCandidate ) ) ;
} else {
return bestCandidate . Member ;
}
}
TypeParameterSubstitution GetSubstitution ( Candidate candidate )
{
SpecializedMethod sm = candidate . Member as SpecializedMethod ;
if ( sm ! = null ) {
// Do not compose the substitutions, but merge them.
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
return new TypeParameterSubstitution ( sm . Substitution . ClassTypeArguments , candidate . InferredTypes ) ;
} else {
return new TypeParameterSubstitution ( null , candidate . InferredTypes ) ;
}
}
/// <summary>
/// Creates a ResolveResult representing the result of overload resolution.
/// </summary>
@ -890,5 +944,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -890,5 +944,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
argumentToParameterMap : this . GetArgumentToParameterMap ( ) ,
initializerStatements : initializerStatements ) ;
}
#endregion
}
}