1
ļ»æ// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
21
using System.Diagnostics;
25
using ICSharpCode.NRefactory.Semantics;
26
using ICSharpCode.NRefactory.TypeSystem;
27
using ICSharpCode.NRefactory.TypeSystem.Implementation;
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
32
/// C# overload resolution (C# 4.0 spec: Ā§7.5).
34
public class OverloadResolution
36
sealed class Candidate
38
public readonly IParameterizedMember Member;
41
/// Returns the normal form candidate, if this is an expanded candidate.
43
public readonly bool IsExpandedForm;
46
/// Gets the parameter types. In the first step, these are the types without any substition.
47
/// After type inference, substitutions will be performed.
49
public readonly IType[] ParameterTypes;
52
/// argument index -> parameter index; -1 for arguments that could not be mapped
54
public int[] ArgumentToParameterMap;
56
public OverloadResolutionErrors Errors;
57
public int ErrorCount;
59
public bool HasUnmappedOptionalParameters;
61
public IType[] InferredTypes;
64
/// Gets the original member parameters (before any substitution!)
66
public readonly IList<IParameter> Parameters;
69
/// Gets the original method type parameters (before any substitution!)
71
public readonly IList<ITypeParameter> TypeParameters;
74
/// Conversions applied to the arguments.
75
/// This field is set by the CheckApplicability step.
77
public Conversion[] ArgumentConversions;
79
public bool IsGenericMethod {
81
IMethod method = Member as IMethod;
82
return method != null && method.TypeParameters.Count > 0;
86
public int ArgumentsPassedToParamsArray {
90
int paramsParameterIndex = this.Parameters.Count - 1;
91
foreach (int parameterIndex in ArgumentToParameterMap) {
92
if (parameterIndex == paramsParameterIndex)
100
public Candidate(IParameterizedMember member, bool isExpanded)
102
this.Member = member;
103
this.IsExpandedForm = isExpanded;
104
IMethod method = member as IMethod;
105
if (method != null && method.TypeParameters.Count > 0) {
106
// For generic methods, go back to the original parameters
107
// (without any type parameter substitution, not even class type parameters)
108
// We'll re-substitute them as part of RunTypeInference().
109
method = (IMethod)method.MemberDefinition;
110
this.Parameters = method.Parameters;
111
this.TypeParameters = method.TypeParameters;
113
this.Parameters = member.Parameters;
115
this.ParameterTypes = new IType[this.Parameters.Count];
118
public void AddError(OverloadResolutionErrors newError)
120
this.Errors |= newError;
125
readonly ICompilation compilation;
126
readonly ResolveResult[] arguments;
127
readonly string[] argumentNames;
128
readonly CSharpConversions conversions;
129
//List<Candidate> candidates = new List<Candidate>();
130
Candidate bestCandidate;
131
Candidate bestCandidateAmbiguousWith;
132
IType[] explicitlyGivenTypeArguments;
135
public OverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null, CSharpConversions conversions = null)
137
if (compilation == null)
138
throw new ArgumentNullException("compilation");
139
if (arguments == null)
140
throw new ArgumentNullException("arguments");
141
if (argumentNames == null)
142
argumentNames = new string[arguments.Length];
143
else if (argumentNames.Length != arguments.Length)
144
throw new ArgumentException("argumentsNames.Length must be equal to arguments.Length");
145
this.compilation = compilation;
146
this.arguments = arguments;
147
this.argumentNames = argumentNames;
149
// keep explicitlyGivenTypeArguments==null when no type arguments were specified
150
if (typeArguments != null && typeArguments.Length > 0)
151
this.explicitlyGivenTypeArguments = typeArguments;
153
this.conversions = conversions ?? CSharpConversions.Get(compilation);
154
this.AllowExpandingParams = true;
159
/// Gets/Sets whether the methods are extension methods that are being called using extension method syntax.
162
/// Setting this property to true restricts the possible conversions on the first argument to
163
/// implicit identity, reference, or boxing conversions.
165
public bool IsExtensionMethodInvocation { get; set; }
168
/// Gets/Sets whether expanding 'params' into individual elements is allowed.
169
/// The default value is true.
171
public bool AllowExpandingParams { get; set; }
174
/// Gets the arguments for which this OverloadResolution instance was created.
176
public IList<ResolveResult> Arguments {
177
get { return arguments; }
181
public OverloadResolutionErrors AddCandidate(IParameterizedMember member)
183
return AddCandidate(member, OverloadResolutionErrors.None);
186
public OverloadResolutionErrors AddCandidate(IParameterizedMember member, OverloadResolutionErrors additionalErrors)
189
throw new ArgumentNullException("member");
191
Candidate c = new Candidate(member, false);
192
if (additionalErrors != OverloadResolutionErrors.None)
193
c.AddError(additionalErrors);
194
if (CalculateCandidate(c)) {
198
if (this.AllowExpandingParams && member.Parameters.Count > 0
199
&& member.Parameters[member.Parameters.Count - 1].IsParams)
201
Candidate expandedCandidate = new Candidate(member, true);
202
if (additionalErrors != OverloadResolutionErrors.None)
203
expandedCandidate.AddError(additionalErrors);
204
// consider expanded form only if it isn't obviously wrong
205
if (CalculateCandidate(expandedCandidate)) {
206
//candidates.Add(expandedCandidate);
208
if (expandedCandidate.ErrorCount < c.ErrorCount)
209
return expandedCandidate.Errors;
215
public static bool IsApplicable(OverloadResolutionErrors errors)
217
return (errors & ~OverloadResolutionErrors.AmbiguousMatch) == OverloadResolutionErrors.None;
221
/// Calculates applicability etc. for the candidate.
223
/// <returns>True if the calculation was successful, false if the candidate should be removed without reporting an error</returns>
224
bool CalculateCandidate(Candidate candidate)
226
if (!ResolveParameterTypes(candidate))
228
MapCorrespondingParameters(candidate);
229
RunTypeInference(candidate);
230
CheckApplicability(candidate);
231
ConsiderIfNewCandidateIsBest(candidate);
235
bool ResolveParameterTypes(Candidate candidate)
237
for (int i = 0; i < candidate.Parameters.Count; i++) {
238
IType type = candidate.Parameters[i].Type;
239
if (candidate.IsExpandedForm && i == candidate.Parameters.Count - 1) {
240
ArrayType arrayType = type as ArrayType;
241
if (arrayType != null && arrayType.Dimensions == 1)
242
type = arrayType.ElementType;
244
return false; // error: cannot unpack params-array. abort considering the expanded form for this candidate
246
candidate.ParameterTypes[i] = type;
252
#region AddMethodLists
254
/// Adds all candidates from the method lists.
256
/// This method implements the logic that causes applicable methods in derived types to hide
257
/// all methods in base types.
259
/// <param name="methodLists">The methods, grouped by declaring type. Base types must come first in the list.</param>
260
public void AddMethodLists(IList<MethodListWithDeclaringType> methodLists)
262
if (methodLists == null)
263
throw new ArgumentNullException("methodLists");
264
// Base types come first, so go through the list backwards (derived types first)
265
bool[] isHiddenByDerivedType;
266
if (methodLists.Count > 1)
267
isHiddenByDerivedType = new bool[methodLists.Count];
269
isHiddenByDerivedType = null;
270
for (int i = methodLists.Count - 1; i >= 0; i--) {
271
if (isHiddenByDerivedType != null && isHiddenByDerivedType[i]) {
272
Log.WriteLine(" Skipping methods in {0} because they are hidden by an applicable method in a derived type", methodLists[i].DeclaringType);
276
MethodListWithDeclaringType methodList = methodLists[i];
277
bool foundApplicableCandidateInCurrentList = false;
279
for (int j = 0; j < methodList.Count; j++) {
280
IParameterizedMember method = methodList[j];
282
OverloadResolutionErrors errors = AddCandidate(method);
284
LogCandidateAddingResult(" Candidate", method, errors);
286
foundApplicableCandidateInCurrentList |= IsApplicable(errors);
289
if (foundApplicableCandidateInCurrentList && i > 0) {
290
foreach (IType baseType in methodList.DeclaringType.GetAllBaseTypes()) {
291
for (int j = 0; j < i; j++) {
292
if (!isHiddenByDerivedType[j] && baseType.Equals(methodLists[j].DeclaringType))
293
isHiddenByDerivedType[j] = true;
300
[Conditional("DEBUG")]
301
internal void LogCandidateAddingResult(string text, IParameterizedMember method, OverloadResolutionErrors errors)
304
Log.WriteLine(string.Format("{0} {1} = {2}{3}",
306
errors == OverloadResolutionErrors.None ? "Success" : errors.ToString(),
307
this.BestCandidate == method ? " (best candidate so far)" :
308
this.BestCandidateAmbiguousWith == method ? " (ambiguous)" : ""
314
#region MapCorrespondingParameters
315
void MapCorrespondingParameters(Candidate candidate)
317
// C# 4.0 spec: Ā§7.5.1.1 Corresponding parameters
318
candidate.ArgumentToParameterMap = new int[arguments.Length];
319
for (int i = 0; i < arguments.Length; i++) {
320
candidate.ArgumentToParameterMap[i] = -1;
321
if (argumentNames[i] == null) {
322
// positional argument
323
if (i < candidate.ParameterTypes.Length) {
324
candidate.ArgumentToParameterMap[i] = i;
325
} else if (candidate.IsExpandedForm) {
326
candidate.ArgumentToParameterMap[i] = candidate.ParameterTypes.Length - 1;
328
candidate.AddError(OverloadResolutionErrors.TooManyPositionalArguments);
332
for (int j = 0; j < candidate.Parameters.Count; j++) {
333
if (argumentNames[i] == candidate.Parameters[j].Name) {
334
candidate.ArgumentToParameterMap[i] = j;
337
if (candidate.ArgumentToParameterMap[i] < 0)
338
candidate.AddError(OverloadResolutionErrors.NoParameterFoundForNamedArgument);
344
#region RunTypeInference
345
void RunTypeInference(Candidate candidate)
347
IMethod method = candidate.Member as IMethod;
348
if (method == null || method.TypeParameters.Count == 0) {
349
if (explicitlyGivenTypeArguments != null) {
350
// method does not expect type arguments, but was given some
351
candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
355
ParameterizedType parameterizedDeclaringType = candidate.Member.DeclaringType as ParameterizedType;
356
IList<IType> classTypeArguments;
357
if (parameterizedDeclaringType != null) {
358
classTypeArguments = parameterizedDeclaringType.TypeArguments;
360
classTypeArguments = null;
362
// The method is generic:
363
if (explicitlyGivenTypeArguments != null) {
364
if (explicitlyGivenTypeArguments.Length == method.TypeParameters.Count) {
365
candidate.InferredTypes = explicitlyGivenTypeArguments;
367
candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
368
// wrong number of type arguments given, so truncate the list or pad with UnknownType
369
candidate.InferredTypes = new IType[method.TypeParameters.Count];
370
for (int i = 0; i < candidate.InferredTypes.Length; i++) {
371
if (i < explicitlyGivenTypeArguments.Length)
372
candidate.InferredTypes[i] = explicitlyGivenTypeArguments[i];
374
candidate.InferredTypes[i] = SpecialType.UnknownType;
378
TypeInference ti = new TypeInference(compilation, conversions);
380
candidate.InferredTypes = ti.InferTypeArguments(candidate.TypeParameters, arguments, candidate.ParameterTypes, out success, classTypeArguments);
382
candidate.AddError(OverloadResolutionErrors.TypeInferenceFailed);
384
// Now substitute in the formal parameters:
385
var substitution = new ConstraintValidatingSubstitution(classTypeArguments, candidate.InferredTypes, this);
386
for (int i = 0; i < candidate.ParameterTypes.Length; i++) {
387
candidate.ParameterTypes[i] = candidate.ParameterTypes[i].AcceptVisitor(substitution);
389
if (!substitution.ConstraintsValid)
390
candidate.AddError(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint);
393
sealed class ConstraintValidatingSubstitution : TypeParameterSubstitution
395
readonly CSharpConversions conversions;
396
public bool ConstraintsValid = true;
398
public ConstraintValidatingSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments, OverloadResolution overloadResolution)
399
: base(classTypeArguments, methodTypeArguments)
401
this.conversions = overloadResolution.conversions;
404
public override IType VisitParameterizedType(ParameterizedType type)
406
IType newType = base.VisitParameterizedType(type);
407
if (newType != type && ConstraintsValid) {
408
// something was changed, so we need to validate the constraints
409
ParameterizedType newParameterizedType = newType as ParameterizedType;
410
if (newParameterizedType != null) {
411
// C# 4.0 spec: Ā§4.4.4 Satisfying constraints
412
var typeParameters = newParameterizedType.GetDefinition().TypeParameters;
413
var substitution = newParameterizedType.GetSubstitution();
414
for (int i = 0; i < typeParameters.Count; i++) {
415
if (!ValidateConstraints(typeParameters[i], newParameterizedType.GetTypeArgument(i), substitution, conversions)) {
416
ConstraintsValid = false;
427
#region Validate Constraints
429
/// Validates whether the given type argument satisfies the constraints for the given type parameter.
431
/// <param name="typeParameter">The type parameter.</param>
432
/// <param name="typeArgument">The type argument.</param>
433
/// <param name="substitution">The substitution that defines how type parameters are replaced with type arguments.
434
/// The substitution is used to check constraints that depend on other type parameters (or recursively on the same type parameter).</param>
435
/// <returns>True if the constraints are satisfied; false otherwise.</returns>
436
public static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution)
438
if (typeParameter == null)
439
throw new ArgumentNullException("typeParameter");
440
if (typeParameter.Owner == null)
441
throw new ArgumentNullException("typeParameter.Owner");
442
if (typeArgument == null)
443
throw new ArgumentNullException("typeArgument");
444
return ValidateConstraints(typeParameter, typeArgument, substitution, CSharpConversions.Get(typeParameter.Owner.Compilation));
447
internal static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution, CSharpConversions conversions)
449
switch (typeArgument.Kind) { // void, null, and pointers cannot be used as type arguments
452
case TypeKind.Pointer:
455
if (typeParameter.HasReferenceTypeConstraint) {
456
if (typeArgument.IsReferenceType != true)
459
if (typeParameter.HasValueTypeConstraint) {
460
if (!NullableType.IsNonNullableValueType(typeArgument))
463
if (typeParameter.HasDefaultConstructorConstraint) {
464
ITypeDefinition def = typeArgument.GetDefinition();
465
if (def != null && def.IsAbstract)
467
var ctors = typeArgument.GetConstructors(
468
m => m.Parameters.Count == 0 && m.Accessibility == Accessibility.Public,
469
GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
474
foreach (IType constraintType in typeParameter.DirectBaseTypes) {
475
IType c = constraintType;
476
if (substitution != null)
477
c = c.AcceptVisitor(substitution);
478
if (!conversions.IsConstraintConvertible(typeArgument, c))
485
#region CheckApplicability
486
void CheckApplicability(Candidate candidate)
488
// C# 4.0 spec: Ā§7.5.3.1 Applicable function member
490
// Test whether parameters were mapped the correct number of arguments:
491
int[] argumentCountPerParameter = new int[candidate.ParameterTypes.Length];
492
foreach (int parameterIndex in candidate.ArgumentToParameterMap) {
493
if (parameterIndex >= 0)
494
argumentCountPerParameter[parameterIndex]++;
496
for (int i = 0; i < argumentCountPerParameter.Length; i++) {
497
if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1)
498
continue; // any number of arguments is fine for the params-array
499
if (argumentCountPerParameter[i] == 0) {
500
if (candidate.Parameters[i].IsOptional)
501
candidate.HasUnmappedOptionalParameters = true;
503
candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter);
504
} else if (argumentCountPerParameter[i] > 1) {
505
candidate.AddError(OverloadResolutionErrors.MultipleArgumentsForSingleParameter);
509
candidate.ArgumentConversions = new Conversion[arguments.Length];
510
// Test whether argument passing mode matches the parameter passing mode
511
for (int i = 0; i < arguments.Length; i++) {
512
int parameterIndex = candidate.ArgumentToParameterMap[i];
513
if (parameterIndex < 0) {
514
candidate.ArgumentConversions[i] = Conversion.None;
518
ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
520
if ((brrr.IsOut && !candidate.Parameters[parameterIndex].IsOut) || (brrr.IsRef && !candidate.Parameters[parameterIndex].IsRef))
521
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
523
if (candidate.Parameters[parameterIndex].IsOut || candidate.Parameters[parameterIndex].IsRef)
524
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
526
IType parameterType = candidate.ParameterTypes[parameterIndex];
527
Conversion c = conversions.ImplicitConversion(arguments[i], parameterType);
528
candidate.ArgumentConversions[i] = c;
529
if (IsExtensionMethodInvocation && parameterIndex == 0) {
530
// First parameter to extension method must be an identity, reference or boxing conversion
531
if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
532
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
534
if (!c.IsValid && parameterType.Kind != TypeKind.Unknown)
535
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
541
#region BetterFunctionMember
543
/// Returns 1 if c1 is better than c2; 2 if c2 is better than c1; or 0 if neither is better.
545
int BetterFunctionMember(Candidate c1, Candidate c2)
547
// prefer applicable members (part of heuristic that produces a best candidate even if none is applicable)
548
if (c1.ErrorCount == 0 && c2.ErrorCount > 0)
550
if (c1.ErrorCount > 0 && c2.ErrorCount == 0)
553
// C# 4.0 spec: Ā§7.5.3.2 Better function member
554
bool c1IsBetter = false;
555
bool c2IsBetter = false;
556
for (int i = 0; i < arguments.Length; i++) {
557
int p1 = c1.ArgumentToParameterMap[i];
558
int p2 = c2.ArgumentToParameterMap[i];
559
if (p1 >= 0 && p2 < 0) {
561
} else if (p1 < 0 && p2 >= 0) {
563
} else if (p1 >= 0 && p2 >= 0) {
564
switch (conversions.BetterConversion(arguments[i], c1.ParameterTypes[p1], c2.ParameterTypes[p2])) {
574
if (c1IsBetter && !c2IsBetter)
576
if (!c1IsBetter && c2IsBetter)
579
// prefer members with less errors (part of heuristic that produces a best candidate even if none is applicable)
580
if (c1.ErrorCount < c2.ErrorCount) return 1;
581
if (c1.ErrorCount > c2.ErrorCount) return 2;
583
if (!c1IsBetter && !c2IsBetter) {
584
// we need the tie-breaking rules
586
// non-generic methods are better
587
if (!c1.IsGenericMethod && c2.IsGenericMethod)
589
else if (c1.IsGenericMethod && !c2.IsGenericMethod)
592
// non-expanded members are better
593
if (!c1.IsExpandedForm && c2.IsExpandedForm)
595
else if (c1.IsExpandedForm && !c2.IsExpandedForm)
598
// prefer the member with less arguments mapped to the params-array
599
int r = c1.ArgumentsPassedToParamsArray.CompareTo(c2.ArgumentsPassedToParamsArray);
601
else if (r > 0) return 2;
603
// prefer the member where no default values need to be substituted
604
if (!c1.HasUnmappedOptionalParameters && c2.HasUnmappedOptionalParameters)
606
else if (c1.HasUnmappedOptionalParameters && !c2.HasUnmappedOptionalParameters)
609
// compare the formal parameters
610
r = MoreSpecificFormalParameters(c1, c2);
614
// prefer non-lifted operators
615
ILiftedOperator lift1 = c1.Member as ILiftedOperator;
616
ILiftedOperator lift2 = c2.Member as ILiftedOperator;
617
if (lift1 == null && lift2 != null)
619
if (lift1 != null && lift2 == null)
626
/// Implement this interface to give overload resolution a hint that the member represents a lifted operator,
627
/// which is used in the tie-breaking rules.
629
public interface ILiftedOperator : IParameterizedMember
631
IList<IParameter> NonLiftedParameters { get; }
634
int MoreSpecificFormalParameters(Candidate c1, Candidate c2)
636
// prefer the member with more formal parmeters (in case both have different number of optional parameters)
637
int r = c1.Parameters.Count.CompareTo(c2.Parameters.Count);
639
else if (r < 0) return 2;
641
return MoreSpecificFormalParameters(c1.Parameters.Select(p => p.Type), c2.Parameters.Select(p => p.Type));
644
static int MoreSpecificFormalParameters(IEnumerable<IType> t1, IEnumerable<IType> t2)
646
bool c1IsBetter = false;
647
bool c2IsBetter = false;
648
foreach (var pair in t1.Zip(t2, (a,b) => new { Item1 = a, Item2 = b })) {
649
switch (MoreSpecificFormalParameter(pair.Item1, pair.Item2)) {
658
if (c1IsBetter && !c2IsBetter)
660
if (!c1IsBetter && c2IsBetter)
665
static int MoreSpecificFormalParameter(IType t1, IType t2)
667
if ((t1 is ITypeParameter) && !(t2 is ITypeParameter))
669
if ((t2 is ITypeParameter) && !(t1 is ITypeParameter))
672
ParameterizedType p1 = t1 as ParameterizedType;
673
ParameterizedType p2 = t2 as ParameterizedType;
674
if (p1 != null && p2 != null && p1.TypeParameterCount == p2.TypeParameterCount) {
675
int r = MoreSpecificFormalParameters(p1.TypeArguments, p2.TypeArguments);
679
TypeWithElementType tew1 = t1 as TypeWithElementType;
680
TypeWithElementType tew2 = t2 as TypeWithElementType;
681
if (tew1 != null && tew2 != null) {
682
return MoreSpecificFormalParameter(tew1.ElementType, tew2.ElementType);
688
#region ConsiderIfNewCandidateIsBest
689
void ConsiderIfNewCandidateIsBest(Candidate candidate)
691
if (bestCandidate == null) {
692
bestCandidate = candidate;
694
switch (BetterFunctionMember(candidate, bestCandidate)) {
696
// Overwrite 'bestCandidateAmbiguousWith' so that API users can
697
// detect the set of all ambiguous methods if they look at
698
// bestCandidateAmbiguousWith after each step.
699
bestCandidateAmbiguousWith = candidate;
702
bestCandidate = candidate;
703
bestCandidateAmbiguousWith = null;
705
// case 2: best candidate stays best
711
public IParameterizedMember BestCandidate {
712
get { return bestCandidate != null ? bestCandidate.Member : null; }
715
public OverloadResolutionErrors BestCandidateErrors {
717
if (bestCandidate == null)
718
return OverloadResolutionErrors.None;
719
OverloadResolutionErrors err = bestCandidate.Errors;
720
if (bestCandidateAmbiguousWith != null)
721
err |= OverloadResolutionErrors.AmbiguousMatch;
726
public bool FoundApplicableCandidate {
727
get { return bestCandidate != null && bestCandidate.Errors == OverloadResolutionErrors.None; }
730
public IParameterizedMember BestCandidateAmbiguousWith {
731
get { return bestCandidateAmbiguousWith != null ? bestCandidateAmbiguousWith.Member : null; }
734
public bool BestCandidateIsExpandedForm {
735
get { return bestCandidate != null ? bestCandidate.IsExpandedForm : false; }
738
public bool IsAmbiguous {
739
get { return bestCandidateAmbiguousWith != null; }
742
public IList<IType> InferredTypeArguments {
744
if (bestCandidate != null && bestCandidate.InferredTypes != null)
745
return bestCandidate.InferredTypes;
747
return EmptyList<IType>.Instance;
752
/// Gets the implicit conversions that are being applied to the arguments.
754
public IList<Conversion> ArgumentConversions {
756
if (bestCandidate != null && bestCandidate.ArgumentConversions != null)
757
return bestCandidate.ArgumentConversions;
759
return Enumerable.Repeat(Conversion.None, arguments.Length).ToList();
764
/// Gets an array that maps argument indices to parameter indices.
765
/// For arguments that could not be mapped to any parameter, the value will be -1.
767
/// parameterIndex = GetArgumentToParameterMap()[argumentIndex]
769
public IList<int> GetArgumentToParameterMap()
771
if (bestCandidate != null)
772
return bestCandidate.ArgumentToParameterMap;
777
public IList<ResolveResult> GetArgumentsWithConversions()
779
if (bestCandidate == null)
782
return GetArgumentsWithConversions(null);
785
IList<ResolveResult> GetArgumentsWithConversions(ResolveResult targetResolveResult)
787
var conversions = this.ArgumentConversions;
788
ResolveResult[] args = new ResolveResult[arguments.Length];
789
for (int i = 0; i < args.Length; i++) {
790
var argument = arguments[i];
791
if (this.IsExtensionMethodInvocation && i == 0 && targetResolveResult != null)
792
argument = targetResolveResult;
793
if (conversions[i] == Conversion.IdentityConversion) {
796
int parameterIndex = bestCandidate.ArgumentToParameterMap[i];
798
if (parameterIndex >= 0) {
799
parameterType = bestCandidate.ParameterTypes[parameterIndex];
801
parameterType = SpecialType.UnknownType;
803
if (arguments[i].IsCompileTimeConstant && conversions[i] != Conversion.None) {
804
args[i] = new CSharpResolver(compilation).ResolveCast(parameterType, argument);
806
args[i] = new ConversionResolveResult(parameterType, argument, conversions[i]);
813
public IParameterizedMember GetBestCandidateWithSubstitutedTypeArguments()
815
if (bestCandidate == null)
817
IMethod method = bestCandidate.Member as IMethod;
818
if (method != null && method.TypeParameters.Count > 0) {
819
SpecializedMethod sm = method as SpecializedMethod;
821
// Do not compose the substitutions, but merge them.
822
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
823
return new SpecializedMethod(
824
(IMethod)method.MemberDefinition,
825
new TypeParameterSubstitution(sm.Substitution.ClassTypeArguments, bestCandidate.InferredTypes));
827
return new SpecializedMethod(method, new TypeParameterSubstitution(null, bestCandidate.InferredTypes));
830
return bestCandidate.Member;
835
/// Creates a ResolveResult representing the result of overload resolution.
837
/// <param name="targetResolveResult">
838
/// The target expression of the call. May be <c>null</c> for static methods/constructors.
840
/// <param name="initializerStatements">
841
/// Statements for Objects/Collections initializer.
842
/// <see cref="InvocationResolveResult.InitializerStatements"/>
844
public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null)
846
IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments();
848
throw new InvalidOperationException();
850
return new CSharpInvocationResolveResult(
851
this.IsExtensionMethodInvocation ? new TypeResolveResult(member.DeclaringType) : targetResolveResult,
853
GetArgumentsWithConversions(targetResolveResult),
854
this.BestCandidateErrors,
855
this.IsExtensionMethodInvocation,
856
this.BestCandidateIsExpandedForm,
857
isDelegateInvocation: false,
858
argumentToParameterMap: this.GetArgumentToParameterMap(),
859
initializerStatements: initializerStatements);