~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
 
2
// 
 
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:
 
8
// 
 
9
// The above copyright notice and this permission notice shall be included in all copies or
 
10
// substantial portions of the Software.
 
11
// 
 
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.
 
18
 
 
19
using System;
 
20
using System.Collections.Generic;
 
21
using System.Diagnostics;
 
22
using System.Linq;
 
23
using System.Text;
 
24
 
 
25
using ICSharpCode.NRefactory.Semantics;
 
26
using ICSharpCode.NRefactory.TypeSystem;
 
27
using ICSharpCode.NRefactory.TypeSystem.Implementation;
 
28
 
 
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
30
{
 
31
        /// <summary>
 
32
        /// C# overload resolution (C# 4.0 spec: Ā§7.5).
 
33
        /// </summary>
 
34
        public class OverloadResolution
 
35
        {
 
36
                sealed class Candidate
 
37
                {
 
38
                        public readonly IParameterizedMember Member;
 
39
                        
 
40
                        /// <summary>
 
41
                        /// Returns the normal form candidate, if this is an expanded candidate.
 
42
                        /// </summary>
 
43
                        public readonly bool IsExpandedForm;
 
44
                        
 
45
                        /// <summary>
 
46
                        /// Gets the parameter types. In the first step, these are the types without any substition.
 
47
                        /// After type inference, substitutions will be performed.
 
48
                        /// </summary>
 
49
                        public readonly IType[] ParameterTypes;
 
50
                        
 
51
                        /// <summary>
 
52
                        /// argument index -> parameter index; -1 for arguments that could not be mapped
 
53
                        /// </summary>
 
54
                        public int[] ArgumentToParameterMap;
 
55
                        
 
56
                        public OverloadResolutionErrors Errors;
 
57
                        public int ErrorCount;
 
58
                        
 
59
                        public bool HasUnmappedOptionalParameters;
 
60
                        
 
61
                        public IType[] InferredTypes;
 
62
                        
 
63
                        /// <summary>
 
64
                        /// Gets the original member parameters (before any substitution!)
 
65
                        /// </summary>
 
66
                        public readonly IList<IParameter> Parameters;
 
67
                        
 
68
                        /// <summary>
 
69
                        /// Gets the original method type parameters (before any substitution!)
 
70
                        /// </summary>
 
71
                        public readonly IList<ITypeParameter> TypeParameters;
 
72
                        
 
73
                        /// <summary>
 
74
                        /// Conversions applied to the arguments.
 
75
                        /// This field is set by the CheckApplicability step.
 
76
                        /// </summary>
 
77
                        public Conversion[] ArgumentConversions;
 
78
                        
 
79
                        public bool IsGenericMethod {
 
80
                                get {
 
81
                                        IMethod method = Member as IMethod;
 
82
                                        return method != null && method.TypeParameters.Count > 0;
 
83
                                }
 
84
                        }
 
85
                        
 
86
                        public int ArgumentsPassedToParamsArray {
 
87
                                get {
 
88
                                        int count = 0;
 
89
                                        if (IsExpandedForm) {
 
90
                                                int paramsParameterIndex = this.Parameters.Count - 1;
 
91
                                                foreach (int parameterIndex in ArgumentToParameterMap) {
 
92
                                                        if (parameterIndex == paramsParameterIndex)
 
93
                                                                count++;
 
94
                                                }
 
95
                                        }
 
96
                                        return count;
 
97
                                }
 
98
                        }
 
99
                        
 
100
                        public Candidate(IParameterizedMember member, bool isExpanded)
 
101
                        {
 
102
                                this.Member = member;
 
103
                                this.IsExpandedForm = isExpanded;
 
104
                                IParameterizedMember memberDefinition = (IParameterizedMember)member.MemberDefinition;
 
105
                                // For specificialized methods, go back to the original parameters:
 
106
                                // (without any type parameter substitution, not even class type parameters)
 
107
                                // We'll re-substitute them as part of RunTypeInference().
 
108
                                this.Parameters = memberDefinition.Parameters;
 
109
                                IMethod methodDefinition = memberDefinition as IMethod;
 
110
                                if (methodDefinition != null && methodDefinition.TypeParameters.Count > 0) {
 
111
                                        this.TypeParameters = methodDefinition.TypeParameters;
 
112
                                }
 
113
                                this.ParameterTypes = new IType[this.Parameters.Count];
 
114
                        }
 
115
                        
 
116
                        public void AddError(OverloadResolutionErrors newError)
 
117
                        {
 
118
                                this.Errors |= newError;
 
119
                                if (!IsApplicable(newError))
 
120
                                        this.ErrorCount++;
 
121
                        }
 
122
                }
 
123
                
 
124
                readonly ICompilation compilation;
 
125
                readonly ResolveResult[] arguments;
 
126
                readonly string[] argumentNames;
 
127
                readonly CSharpConversions conversions;
 
128
                //List<Candidate> candidates = new List<Candidate>();
 
129
                Candidate bestCandidate;
 
130
                Candidate bestCandidateAmbiguousWith;
 
131
                IType[] explicitlyGivenTypeArguments;
 
132
                bool bestCandidateWasValidated;
 
133
                OverloadResolutionErrors bestCandidateValidationResult;
 
134
                
 
135
                #region Constructor
 
136
                public OverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null, CSharpConversions conversions = null)
 
137
                {
 
138
                        if (compilation == null)
 
139
                                throw new ArgumentNullException("compilation");
 
140
                        if (arguments == null)
 
141
                                throw new ArgumentNullException("arguments");
 
142
                        if (argumentNames == null)
 
143
                                argumentNames = new string[arguments.Length];
 
144
                        else if (argumentNames.Length != arguments.Length)
 
145
                                throw new ArgumentException("argumentsNames.Length must be equal to arguments.Length");
 
146
                        this.compilation = compilation;
 
147
                        this.arguments = arguments;
 
148
                        this.argumentNames = argumentNames;
 
149
                        
 
150
                        // keep explicitlyGivenTypeArguments==null when no type arguments were specified
 
151
                        if (typeArguments != null && typeArguments.Length > 0)
 
152
                                this.explicitlyGivenTypeArguments = typeArguments;
 
153
                        
 
154
                        this.conversions = conversions ?? CSharpConversions.Get(compilation);
 
155
                        this.AllowExpandingParams = true;
 
156
                        this.AllowOptionalParameters = true;
 
157
                }
 
158
                #endregion
 
159
                
 
160
                #region Input Properties
 
161
                /// <summary>
 
162
                /// Gets/Sets whether the methods are extension methods that are being called using extension method syntax.
 
163
                /// </summary>
 
164
                /// <remarks>
 
165
                /// Setting this property to true restricts the possible conversions on the first argument to
 
166
                /// implicit identity, reference, or boxing conversions.
 
167
                /// </remarks>
 
168
                public bool IsExtensionMethodInvocation { get; set; }
 
169
                
 
170
                /// <summary>
 
171
                /// Gets/Sets whether expanding 'params' into individual elements is allowed.
 
172
                /// The default value is true.
 
173
                /// </summary>
 
174
                public bool AllowExpandingParams { get; set; }
 
175
                
 
176
                /// <summary>
 
177
                /// Gets/Sets whether optional parameters may be left at their default value.
 
178
                /// The default value is true.
 
179
                /// If this property is set to false, optional parameters will be treated like regular parameters.
 
180
                /// </summary>
 
181
                public bool AllowOptionalParameters { get; set; }
 
182
                
 
183
                /// <summary>
 
184
                /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution
 
185
                /// instance apply overflow checking.
 
186
                /// The default value is false.
 
187
                /// </summary>
 
188
                public bool CheckForOverflow { get; set; }
 
189
                
 
190
                /// <summary>
 
191
                /// Gets the arguments for which this OverloadResolution instance was created.
 
192
                /// </summary>
 
193
                public IList<ResolveResult> Arguments {
 
194
                        get { return arguments; }
 
195
                }
 
196
                #endregion
 
197
                
 
198
                #region AddCandidate
 
199
                /// <summary>
 
200
                /// Adds a candidate to overload resolution.
 
201
                /// </summary>
 
202
                /// <param name="member">The candidate member to add.</param>
 
203
                /// <returns>The errors that prevent the member from being applicable, if any.
 
204
                /// Note: this method does not return errors that do not affect applicability.</returns>
 
205
                public OverloadResolutionErrors AddCandidate(IParameterizedMember member)
 
206
                {
 
207
                        return AddCandidate(member, OverloadResolutionErrors.None);
 
208
                }
 
209
                
 
210
                /// <summary>
 
211
                /// Adds a candidate to overload resolution.
 
212
                /// </summary>
 
213
                /// <param name="member">The candidate member to add.</param>
 
214
                /// <param name="additionalErrors">Additional errors that apply to the candidate.
 
215
                /// This is used to represent errors during member lookup (e.g. OverloadResolutionErrors.Inaccessible)
 
216
                /// in overload resolution.</param>
 
217
                /// <returns>The errors that prevent the member from being applicable, if any.
 
218
                /// Note: this method does not return errors that do not affect applicability.</returns>
 
219
                public OverloadResolutionErrors AddCandidate(IParameterizedMember member, OverloadResolutionErrors additionalErrors)
 
220
                {
 
221
                        if (member == null)
 
222
                                throw new ArgumentNullException("member");
 
223
                        
 
224
                        Candidate c = new Candidate(member, false);
 
225
                        c.AddError(additionalErrors);
 
226
                        if (CalculateCandidate(c)) {
 
227
                                //candidates.Add(c);
 
228
                        }
 
229
                        
 
230
                        if (this.AllowExpandingParams && member.Parameters.Count > 0
 
231
                            && member.Parameters[member.Parameters.Count - 1].IsParams)
 
232
                        {
 
233
                                Candidate expandedCandidate = new Candidate(member, true);
 
234
                                expandedCandidate.AddError(additionalErrors);
 
235
                                // consider expanded form only if it isn't obviously wrong
 
236
                                if (CalculateCandidate(expandedCandidate)) {
 
237
                                        //candidates.Add(expandedCandidate);
 
238
                                        
 
239
                                        if (expandedCandidate.ErrorCount < c.ErrorCount)
 
240
                                                return expandedCandidate.Errors;
 
241
                                }
 
242
                        }
 
243
                        return c.Errors;
 
244
                }
 
245
                
 
246
                /// <summary>
 
247
                /// Calculates applicability etc. for the candidate.
 
248
                /// </summary>
 
249
                /// <returns>True if the calculation was successful, false if the candidate should be removed without reporting an error</returns>
 
250
                bool CalculateCandidate(Candidate candidate)
 
251
                {
 
252
                        if (!ResolveParameterTypes(candidate, false))
 
253
                                return false;
 
254
                        MapCorrespondingParameters(candidate);
 
255
                        RunTypeInference(candidate);
 
256
                        CheckApplicability(candidate);
 
257
                        ConsiderIfNewCandidateIsBest(candidate);
 
258
                        return true;
 
259
                }
 
260
                
 
261
                bool ResolveParameterTypes(Candidate candidate, bool useSpecializedParameters)
 
262
                {
 
263
                        for (int i = 0; i < candidate.Parameters.Count; i++) {
 
264
                                IType type;
 
265
                                if (useSpecializedParameters) {
 
266
                                        // Use the parameter type of the specialized non-generic method or indexer
 
267
                                        Debug.Assert(!candidate.IsGenericMethod);
 
268
                                        type = candidate.Member.Parameters[i].Type;
 
269
                                } else {
 
270
                                        // Use the type of the original formal parameter
 
271
                                        type = candidate.Parameters[i].Type;
 
272
                                }
 
273
                                if (candidate.IsExpandedForm && i == candidate.Parameters.Count - 1) {
 
274
                                        ArrayType arrayType = type as ArrayType;
 
275
                                        if (arrayType != null && arrayType.Dimensions == 1)
 
276
                                                type = arrayType.ElementType;
 
277
                                        else
 
278
                                                return false; // error: cannot unpack params-array. abort considering the expanded form for this candidate
 
279
                                }
 
280
                                candidate.ParameterTypes[i] = type;
 
281
                        }
 
282
                        return true;
 
283
                }
 
284
                #endregion
 
285
                
 
286
                #region AddMethodLists
 
287
                /// <summary>
 
288
                /// Adds all candidates from the method lists.
 
289
                /// 
 
290
                /// This method implements the logic that causes applicable methods in derived types to hide
 
291
                /// all methods in base types.
 
292
                /// </summary>
 
293
                /// <param name="methodLists">The methods, grouped by declaring type. Base types must come first in the list.</param>
 
294
                public void AddMethodLists(IList<MethodListWithDeclaringType> methodLists)
 
295
                {
 
296
                        if (methodLists == null)
 
297
                                throw new ArgumentNullException("methodLists");
 
298
                        // Base types come first, so go through the list backwards (derived types first)
 
299
                        bool[] isHiddenByDerivedType;
 
300
                        if (methodLists.Count > 1)
 
301
                                isHiddenByDerivedType = new bool[methodLists.Count];
 
302
                        else
 
303
                                isHiddenByDerivedType = null;
 
304
                        for (int i = methodLists.Count - 1; i >= 0; i--) {
 
305
                                if (isHiddenByDerivedType != null && isHiddenByDerivedType[i]) {
 
306
                                        Log.WriteLine("  Skipping methods in {0} because they are hidden by an applicable method in a derived type", methodLists[i].DeclaringType);
 
307
                                        continue;
 
308
                                }
 
309
                                
 
310
                                MethodListWithDeclaringType methodList = methodLists[i];
 
311
                                bool foundApplicableCandidateInCurrentList = false;
 
312
                                
 
313
                                for (int j = 0; j < methodList.Count; j++) {
 
314
                                        IParameterizedMember method = methodList[j];
 
315
                                        Log.Indent();
 
316
                                        OverloadResolutionErrors errors = AddCandidate(method);
 
317
                                        Log.Unindent();
 
318
                                        LogCandidateAddingResult("  Candidate", method, errors);
 
319
                                        
 
320
                                        foundApplicableCandidateInCurrentList |= IsApplicable(errors);
 
321
                                }
 
322
                                
 
323
                                if (foundApplicableCandidateInCurrentList && i > 0) {
 
324
                                        foreach (IType baseType in methodList.DeclaringType.GetAllBaseTypes()) {
 
325
                                                for (int j = 0; j < i; j++) {
 
326
                                                        if (!isHiddenByDerivedType[j] && baseType.Equals(methodLists[j].DeclaringType))
 
327
                                                                isHiddenByDerivedType[j] = true;
 
328
                                                }
 
329
                                        }
 
330
                                }
 
331
                        }
 
332
                }
 
333
                
 
334
                [Conditional("DEBUG")]
 
335
                internal void LogCandidateAddingResult(string text, IParameterizedMember method, OverloadResolutionErrors errors)
 
336
                {
 
337
                        #if DEBUG
 
338
                        Log.WriteLine(string.Format("{0} {1} = {2}{3}",
 
339
                                                    text, method,
 
340
                                                    errors == OverloadResolutionErrors.None ? "Success" : errors.ToString(),
 
341
                                                    this.BestCandidate == method ? " (best candidate so far)" :
 
342
                                                    this.BestCandidateAmbiguousWith == method ? " (ambiguous)" : ""
 
343
                                                   ));
 
344
                        #endif
 
345
                }
 
346
                #endregion
 
347
                
 
348
                #region MapCorrespondingParameters
 
349
                void MapCorrespondingParameters(Candidate candidate)
 
350
                {
 
351
                        // C# 4.0 spec: Ā§7.5.1.1 Corresponding parameters
 
352
                        candidate.ArgumentToParameterMap = new int[arguments.Length];
 
353
                        for (int i = 0; i < arguments.Length; i++) {
 
354
                                candidate.ArgumentToParameterMap[i] = -1;
 
355
                                if (argumentNames[i] == null) {
 
356
                                        // positional argument
 
357
                                        if (i < candidate.ParameterTypes.Length) {
 
358
                                                candidate.ArgumentToParameterMap[i] = i;
 
359
                                        } else if (candidate.IsExpandedForm) {
 
360
                                                candidate.ArgumentToParameterMap[i] = candidate.ParameterTypes.Length - 1;
 
361
                                        } else {
 
362
                                                candidate.AddError(OverloadResolutionErrors.TooManyPositionalArguments);
 
363
                                        }
 
364
                                } else {
 
365
                                        // named argument
 
366
                                        for (int j = 0; j < candidate.Parameters.Count; j++) {
 
367
                                                if (argumentNames[i] == candidate.Parameters[j].Name) {
 
368
                                                        candidate.ArgumentToParameterMap[i] = j;
 
369
                                                }
 
370
                                        }
 
371
                                        if (candidate.ArgumentToParameterMap[i] < 0)
 
372
                                                candidate.AddError(OverloadResolutionErrors.NoParameterFoundForNamedArgument);
 
373
                                }
 
374
                        }
 
375
                }
 
376
                #endregion
 
377
                
 
378
                #region RunTypeInference
 
379
                void RunTypeInference(Candidate candidate)
 
380
                {
 
381
                        if (candidate.TypeParameters == null) {
 
382
                                if (explicitlyGivenTypeArguments != null) {
 
383
                                        // method does not expect type arguments, but was given some
 
384
                                        candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
 
385
                                }
 
386
                                // Grab new parameter types:
 
387
                                ResolveParameterTypes(candidate, true);
 
388
                                return;
 
389
                        }
 
390
                        ParameterizedType parameterizedDeclaringType = candidate.Member.DeclaringType as ParameterizedType;
 
391
                        IList<IType> classTypeArguments;
 
392
                        if (parameterizedDeclaringType != null) {
 
393
                                classTypeArguments = parameterizedDeclaringType.TypeArguments;
 
394
                        } else {
 
395
                                classTypeArguments = null;
 
396
                        }
 
397
                        // The method is generic:
 
398
                        if (explicitlyGivenTypeArguments != null) {
 
399
                                if (explicitlyGivenTypeArguments.Length == candidate.TypeParameters.Count) {
 
400
                                        candidate.InferredTypes = explicitlyGivenTypeArguments;
 
401
                                } else {
 
402
                                        candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
 
403
                                        // wrong number of type arguments given, so truncate the list or pad with UnknownType
 
404
                                        candidate.InferredTypes = new IType[candidate.TypeParameters.Count];
 
405
                                        for (int i = 0; i < candidate.InferredTypes.Length; i++) {
 
406
                                                if (i < explicitlyGivenTypeArguments.Length)
 
407
                                                        candidate.InferredTypes[i] = explicitlyGivenTypeArguments[i];
 
408
                                                else
 
409
                                                        candidate.InferredTypes[i] = SpecialType.UnknownType;
 
410
                                        }
 
411
                                }
 
412
                        } else {
 
413
                                TypeInference ti = new TypeInference(compilation, conversions);
 
414
                                bool success;
 
415
                                candidate.InferredTypes = ti.InferTypeArguments(candidate.TypeParameters, arguments, candidate.ParameterTypes, out success, classTypeArguments);
 
416
                                if (!success)
 
417
                                        candidate.AddError(OverloadResolutionErrors.TypeInferenceFailed);
 
418
                        }
 
419
                        // Now substitute in the formal parameters:
 
420
                        var substitution = new ConstraintValidatingSubstitution(classTypeArguments, candidate.InferredTypes, this);
 
421
                        for (int i = 0; i < candidate.ParameterTypes.Length; i++) {
 
422
                                candidate.ParameterTypes[i] = candidate.ParameterTypes[i].AcceptVisitor(substitution);
 
423
                        }
 
424
                        if (!substitution.ConstraintsValid)
 
425
                                candidate.AddError(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint);
 
426
                }
 
427
                
 
428
                sealed class ConstraintValidatingSubstitution : TypeParameterSubstitution
 
429
                {
 
430
                        readonly CSharpConversions conversions;
 
431
                        public bool ConstraintsValid = true;
 
432
                        
 
433
                        public ConstraintValidatingSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments, OverloadResolution overloadResolution)
 
434
                                : base(classTypeArguments, methodTypeArguments)
 
435
                        {
 
436
                                this.conversions = overloadResolution.conversions;
 
437
                        }
 
438
                        
 
439
                        public override IType VisitParameterizedType(ParameterizedType type)
 
440
                        {
 
441
                                IType newType = base.VisitParameterizedType(type);
 
442
                                if (newType != type && ConstraintsValid) {
 
443
                                        // something was changed, so we need to validate the constraints
 
444
                                        ParameterizedType newParameterizedType = newType as ParameterizedType;
 
445
                                        if (newParameterizedType != null) {
 
446
                                                // C# 4.0 spec: Ā§4.4.4 Satisfying constraints
 
447
                                                var typeParameters = newParameterizedType.GetDefinition().TypeParameters;
 
448
                                                var substitution = newParameterizedType.GetSubstitution();
 
449
                                                for (int i = 0; i < typeParameters.Count; i++) {
 
450
                                                        if (!ValidateConstraints(typeParameters[i], newParameterizedType.GetTypeArgument(i), substitution, conversions)) {
 
451
                                                                ConstraintsValid = false;
 
452
                                                                break;
 
453
                                                        }
 
454
                                                }
 
455
                                        }
 
456
                                }
 
457
                                return newType;
 
458
                        }
 
459
                }
 
460
                #endregion
 
461
                
 
462
                #region Validate Constraints
 
463
                OverloadResolutionErrors ValidateMethodConstraints(Candidate candidate)
 
464
                {
 
465
                        // If type inference already failed, we won't check the constraints:
 
466
                        if ((candidate.Errors & OverloadResolutionErrors.TypeInferenceFailed) != 0)
 
467
                                return OverloadResolutionErrors.None;
 
468
                        
 
469
                        IMethod method = candidate.Member as IMethod;
 
470
                        if (method == null || method.TypeParameters.Count == 0)
 
471
                                return OverloadResolutionErrors.None; // the method isn't generic
 
472
                        var substitution = GetSubstitution(candidate);
 
473
                        for (int i = 0; i < method.TypeParameters.Count; i++) {
 
474
                                if (!ValidateConstraints(method.TypeParameters[i], substitution.MethodTypeArguments[i], substitution))
 
475
                                        return OverloadResolutionErrors.MethodConstraintsNotSatisfied;
 
476
                        }
 
477
                        return OverloadResolutionErrors.None;
 
478
                }
 
479
                
 
480
                /// <summary>
 
481
                /// Validates whether the given type argument satisfies the constraints for the given type parameter.
 
482
                /// </summary>
 
483
                /// <param name="typeParameter">The type parameter.</param>
 
484
                /// <param name="typeArgument">The type argument.</param>
 
485
                /// <param name="substitution">The substitution that defines how type parameters are replaced with type arguments.
 
486
                /// The substitution is used to check constraints that depend on other type parameters (or recursively on the same type parameter).
 
487
                /// May be null if no substitution should be used.</param>
 
488
                /// <returns>True if the constraints are satisfied; false otherwise.</returns>
 
489
                public static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution = null)
 
490
                {
 
491
                        if (typeParameter == null)
 
492
                                throw new ArgumentNullException("typeParameter");
 
493
                        if (typeArgument == null)
 
494
                                throw new ArgumentNullException("typeArgument");
 
495
                        return ValidateConstraints(typeParameter, typeArgument, substitution, CSharpConversions.Get(typeParameter.Owner.Compilation));
 
496
                }
 
497
                
 
498
                internal static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution, CSharpConversions conversions)
 
499
                {
 
500
                        switch (typeArgument.Kind) { // void, null, and pointers cannot be used as type arguments
 
501
                                case TypeKind.Void:
 
502
                                case TypeKind.Null:
 
503
                                case TypeKind.Pointer:
 
504
                                        return false;
 
505
                        }
 
506
                        if (typeParameter.HasReferenceTypeConstraint) {
 
507
                                if (typeArgument.IsReferenceType != true)
 
508
                                        return false;
 
509
                        }
 
510
                        if (typeParameter.HasValueTypeConstraint) {
 
511
                                if (!NullableType.IsNonNullableValueType(typeArgument))
 
512
                                        return false;
 
513
                        }
 
514
                        if (typeParameter.HasDefaultConstructorConstraint) {
 
515
                                ITypeDefinition def = typeArgument.GetDefinition();
 
516
                                if (def != null && def.IsAbstract)
 
517
                                        return false;
 
518
                                var ctors = typeArgument.GetConstructors(
 
519
                                        m => m.Parameters.Count == 0 && m.Accessibility == Accessibility.Public,
 
520
                                        GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
 
521
                                );
 
522
                                if (!ctors.Any())
 
523
                                        return false;
 
524
                        }
 
525
                        foreach (IType constraintType in typeParameter.DirectBaseTypes) {
 
526
                                IType c = constraintType;
 
527
                                if (substitution != null)
 
528
                                        c = c.AcceptVisitor(substitution);
 
529
                                if (!conversions.IsConstraintConvertible(typeArgument, c))
 
530
                                        return false;
 
531
                        }
 
532
                        return true;
 
533
                }
 
534
                #endregion
 
535
                
 
536
                #region CheckApplicability
 
537
                /// <summary>
 
538
                /// Returns whether a candidate with the given errors is still considered to be applicable.
 
539
                /// </summary>
 
540
                public static bool IsApplicable(OverloadResolutionErrors errors)
 
541
                {
 
542
                        const OverloadResolutionErrors errorsThatDoNotMatterForApplicability =
 
543
                                OverloadResolutionErrors.AmbiguousMatch | OverloadResolutionErrors.MethodConstraintsNotSatisfied;
 
544
                        return (errors & ~errorsThatDoNotMatterForApplicability) == OverloadResolutionErrors.None;
 
545
                }
 
546
                
 
547
                void CheckApplicability(Candidate candidate)
 
548
                {
 
549
                        // C# 4.0 spec: Ā§7.5.3.1 Applicable function member
 
550
                        
 
551
                        // Test whether parameters were mapped the correct number of arguments:
 
552
                        int[] argumentCountPerParameter = new int[candidate.ParameterTypes.Length];
 
553
                        foreach (int parameterIndex in candidate.ArgumentToParameterMap) {
 
554
                                if (parameterIndex >= 0)
 
555
                                        argumentCountPerParameter[parameterIndex]++;
 
556
                        }
 
557
                        for (int i = 0; i < argumentCountPerParameter.Length; i++) {
 
558
                                if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1)
 
559
                                        continue; // any number of arguments is fine for the params-array
 
560
                                if (argumentCountPerParameter[i] == 0) {
 
561
                                        if (this.AllowOptionalParameters && candidate.Parameters[i].IsOptional)
 
562
                                                candidate.HasUnmappedOptionalParameters = true;
 
563
                                        else
 
564
                                                candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter);
 
565
                                } else if (argumentCountPerParameter[i] > 1) {
 
566
                                        candidate.AddError(OverloadResolutionErrors.MultipleArgumentsForSingleParameter);
 
567
                                }
 
568
                        }
 
569
                        
 
570
                        candidate.ArgumentConversions = new Conversion[arguments.Length];
 
571
                        // Test whether argument passing mode matches the parameter passing mode
 
572
                        for (int i = 0; i < arguments.Length; i++) {
 
573
                                int parameterIndex = candidate.ArgumentToParameterMap[i];
 
574
                                if (parameterIndex < 0) {
 
575
                                        candidate.ArgumentConversions[i] = Conversion.None;
 
576
                                        continue;
 
577
                                }
 
578
                                
 
579
                                ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
 
580
                                if (brrr != null) {
 
581
                                        if ((brrr.IsOut && !candidate.Parameters[parameterIndex].IsOut) || (brrr.IsRef && !candidate.Parameters[parameterIndex].IsRef))
 
582
                                                candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
 
583
                                } else {
 
584
                                        if (candidate.Parameters[parameterIndex].IsOut || candidate.Parameters[parameterIndex].IsRef)
 
585
                                                candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
 
586
                                }
 
587
                                IType parameterType = candidate.ParameterTypes[parameterIndex];
 
588
                                Conversion c = conversions.ImplicitConversion(arguments[i], parameterType);
 
589
                                candidate.ArgumentConversions[i] = c;
 
590
                                if (IsExtensionMethodInvocation && parameterIndex == 0) {
 
591
                                        // First parameter to extension method must be an identity, reference or boxing conversion
 
592
                                        if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
 
593
                                                candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
 
594
                                } else {
 
595
                                        if ((!c.IsValid && !c.IsUserDefined && !c.IsMethodGroupConversion) && parameterType.Kind != TypeKind.Unknown)
 
596
                                                candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
 
597
                                }
 
598
                        }
 
599
                }
 
600
                #endregion
 
601
                
 
602
                #region BetterFunctionMember
 
603
                /// <summary>
 
604
                /// Returns 1 if c1 is better than c2; 2 if c2 is better than c1; or 0 if neither is better.
 
605
                /// </summary>
 
606
                int BetterFunctionMember(Candidate c1, Candidate c2)
 
607
                {
 
608
                        // prefer applicable members (part of heuristic that produces a best candidate even if none is applicable)
 
609
                        if (c1.ErrorCount == 0 && c2.ErrorCount > 0)
 
610
                                return 1;
 
611
                        if (c1.ErrorCount > 0 && c2.ErrorCount == 0)
 
612
                                return 2;
 
613
                        
 
614
                        // C# 4.0 spec: Ā§7.5.3.2 Better function member
 
615
                        bool c1IsBetter = false;
 
616
                        bool c2IsBetter = false;
 
617
                        for (int i = 0; i < arguments.Length; i++) {
 
618
                                int p1 = c1.ArgumentToParameterMap[i];
 
619
                                int p2 = c2.ArgumentToParameterMap[i];
 
620
                                if (p1 >= 0 && p2 < 0) {
 
621
                                        c1IsBetter = true;
 
622
                                } else if (p1 < 0 && p2 >= 0) {
 
623
                                        c2IsBetter = true;
 
624
                                } else if (p1 >= 0 && p2 >= 0) {
 
625
                                        switch (conversions.BetterConversion(arguments[i], c1.ParameterTypes[p1], c2.ParameterTypes[p2])) {
 
626
                                                case 1:
 
627
                                                        c1IsBetter = true;
 
628
                                                        break;
 
629
                                                case 2:
 
630
                                                        c2IsBetter = true;
 
631
                                                        break;
 
632
                                        }
 
633
                                }
 
634
                        }
 
635
                        if (c1IsBetter && !c2IsBetter)
 
636
                                return 1;
 
637
                        if (!c1IsBetter && c2IsBetter)
 
638
                                return 2;
 
639
                        
 
640
                        // prefer members with less errors (part of heuristic that produces a best candidate even if none is applicable)
 
641
                        if (c1.ErrorCount < c2.ErrorCount) return 1;
 
642
                        if (c1.ErrorCount > c2.ErrorCount) return 2;
 
643
                        
 
644
                        if (!c1IsBetter && !c2IsBetter) {
 
645
                                // we need the tie-breaking rules
 
646
                                
 
647
                                // non-generic methods are better
 
648
                                if (!c1.IsGenericMethod && c2.IsGenericMethod)
 
649
                                        return 1;
 
650
                                else if (c1.IsGenericMethod && !c2.IsGenericMethod)
 
651
                                        return 2;
 
652
                                
 
653
                                // non-expanded members are better
 
654
                                if (!c1.IsExpandedForm && c2.IsExpandedForm)
 
655
                                        return 1;
 
656
                                else if (c1.IsExpandedForm && !c2.IsExpandedForm)
 
657
                                        return 2;
 
658
                                
 
659
                                // prefer the member with less arguments mapped to the params-array
 
660
                                int r = c1.ArgumentsPassedToParamsArray.CompareTo(c2.ArgumentsPassedToParamsArray);
 
661
                                if (r < 0) return 1;
 
662
                                else if (r > 0) return 2;
 
663
                                
 
664
                                // prefer the member where no default values need to be substituted
 
665
                                if (!c1.HasUnmappedOptionalParameters && c2.HasUnmappedOptionalParameters)
 
666
                                        return 1;
 
667
                                else if (c1.HasUnmappedOptionalParameters && !c2.HasUnmappedOptionalParameters)
 
668
                                        return 2;
 
669
                                
 
670
                                // compare the formal parameters
 
671
                                r = MoreSpecificFormalParameters(c1, c2);
 
672
                                if (r != 0)
 
673
                                        return r;
 
674
                                
 
675
                                // prefer non-lifted operators
 
676
                                ILiftedOperator lift1 = c1.Member as ILiftedOperator;
 
677
                                ILiftedOperator lift2 = c2.Member as ILiftedOperator;
 
678
                                if (lift1 == null && lift2 != null)
 
679
                                        return 1;
 
680
                                if (lift1 != null && lift2 == null)
 
681
                                        return 2;
 
682
                        }
 
683
                        return 0;
 
684
                }
 
685
                
 
686
                /// <summary>
 
687
                /// Implement this interface to give overload resolution a hint that the member represents a lifted operator,
 
688
                /// which is used in the tie-breaking rules.
 
689
                /// </summary>
 
690
                public interface ILiftedOperator : IParameterizedMember
 
691
                {
 
692
                        IList<IParameter> NonLiftedParameters { get; }
 
693
                }
 
694
                
 
695
                int MoreSpecificFormalParameters(Candidate c1, Candidate c2)
 
696
                {
 
697
                        // prefer the member with more formal parmeters (in case both have different number of optional parameters)
 
698
                        int r = c1.Parameters.Count.CompareTo(c2.Parameters.Count);
 
699
                        if (r > 0) return 1;
 
700
                        else if (r < 0) return 2;
 
701
                        
 
702
                        return MoreSpecificFormalParameters(c1.Parameters.Select(p => p.Type), c2.Parameters.Select(p => p.Type));
 
703
                }
 
704
                
 
705
                static int MoreSpecificFormalParameters(IEnumerable<IType> t1, IEnumerable<IType> t2)
 
706
                {
 
707
                        bool c1IsBetter = false;
 
708
                        bool c2IsBetter = false;
 
709
                        foreach (var pair in t1.Zip(t2, (a,b) => new { Item1 = a, Item2 = b })) {
 
710
                                switch (MoreSpecificFormalParameter(pair.Item1, pair.Item2)) {
 
711
                                        case 1:
 
712
                                                c1IsBetter = true;
 
713
                                                break;
 
714
                                        case 2:
 
715
                                                c2IsBetter = true;
 
716
                                                break;
 
717
                                }
 
718
                        }
 
719
                        if (c1IsBetter && !c2IsBetter)
 
720
                                return 1;
 
721
                        if (!c1IsBetter && c2IsBetter)
 
722
                                return 2;
 
723
                        return 0;
 
724
                }
 
725
                
 
726
                static int MoreSpecificFormalParameter(IType t1, IType t2)
 
727
                {
 
728
                        if ((t1 is ITypeParameter) && !(t2 is ITypeParameter))
 
729
                                return 2;
 
730
                        if ((t2 is ITypeParameter) && !(t1 is ITypeParameter))
 
731
                                return 1;
 
732
                        
 
733
                        ParameterizedType p1 = t1 as ParameterizedType;
 
734
                        ParameterizedType p2 = t2 as ParameterizedType;
 
735
                        if (p1 != null && p2 != null && p1.TypeParameterCount == p2.TypeParameterCount) {
 
736
                                int r = MoreSpecificFormalParameters(p1.TypeArguments, p2.TypeArguments);
 
737
                                if (r > 0)
 
738
                                        return r;
 
739
                        }
 
740
                        TypeWithElementType tew1 = t1 as TypeWithElementType;
 
741
                        TypeWithElementType tew2 = t2 as TypeWithElementType;
 
742
                        if (tew1 != null && tew2 != null) {
 
743
                                return MoreSpecificFormalParameter(tew1.ElementType, tew2.ElementType);
 
744
                        }
 
745
                        return 0;
 
746
                }
 
747
                #endregion
 
748
                
 
749
                #region ConsiderIfNewCandidateIsBest
 
750
                void ConsiderIfNewCandidateIsBest(Candidate candidate)
 
751
                {
 
752
                        if (bestCandidate == null) {
 
753
                                bestCandidate = candidate;
 
754
                                bestCandidateWasValidated = false;
 
755
                        } else {
 
756
                                switch (BetterFunctionMember(candidate, bestCandidate)) {
 
757
                                        case 0:
 
758
                                                // Overwrite 'bestCandidateAmbiguousWith' so that API users can
 
759
                                                // detect the set of all ambiguous methods if they look at
 
760
                                                // bestCandidateAmbiguousWith after each step.
 
761
                                                bestCandidateAmbiguousWith = candidate;
 
762
                                                break;
 
763
                                        case 1:
 
764
                                                bestCandidate = candidate;
 
765
                                                bestCandidateWasValidated = false;
 
766
                                                bestCandidateAmbiguousWith = null;
 
767
                                                break;
 
768
                                                // case 2: best candidate stays best
 
769
                                }
 
770
                        }
 
771
                }
 
772
                #endregion
 
773
                
 
774
                #region Output Properties
 
775
                public IParameterizedMember BestCandidate {
 
776
                        get { return bestCandidate != null ? bestCandidate.Member : null; }
 
777
                }
 
778
                
 
779
                /// <summary>
 
780
                /// Returns the errors that apply to the best candidate.
 
781
                /// This includes additional errors that do not affect applicability (e.g. AmbiguousMatch, MethodConstraintsNotSatisfied)
 
782
                /// </summary>
 
783
                public OverloadResolutionErrors BestCandidateErrors {
 
784
                        get {
 
785
                                if (bestCandidate == null)
 
786
                                        return OverloadResolutionErrors.None;
 
787
                                if (!bestCandidateWasValidated) {
 
788
                                        bestCandidateValidationResult = ValidateMethodConstraints(bestCandidate);
 
789
                                        bestCandidateWasValidated = true;
 
790
                                }
 
791
                                OverloadResolutionErrors err = bestCandidate.Errors | bestCandidateValidationResult;
 
792
                                if (bestCandidateAmbiguousWith != null)
 
793
                                        err |= OverloadResolutionErrors.AmbiguousMatch;
 
794
                                return err;
 
795
                        }
 
796
                }
 
797
                
 
798
                public bool FoundApplicableCandidate {
 
799
                        get { return bestCandidate != null && IsApplicable(bestCandidate.Errors); }
 
800
                }
 
801
                
 
802
                public IParameterizedMember BestCandidateAmbiguousWith {
 
803
                        get { return bestCandidateAmbiguousWith != null ? bestCandidateAmbiguousWith.Member : null; }
 
804
                }
 
805
                
 
806
                public bool BestCandidateIsExpandedForm {
 
807
                        get { return bestCandidate != null ? bestCandidate.IsExpandedForm : false; }
 
808
                }
 
809
                
 
810
                public bool IsAmbiguous {
 
811
                        get { return bestCandidateAmbiguousWith != null; }
 
812
                }
 
813
                
 
814
                public IList<IType> InferredTypeArguments {
 
815
                        get {
 
816
                                if (bestCandidate != null && bestCandidate.InferredTypes != null)
 
817
                                        return bestCandidate.InferredTypes;
 
818
                                else
 
819
                                        return EmptyList<IType>.Instance;
 
820
                        }
 
821
                }
 
822
                
 
823
                /// <summary>
 
824
                /// Gets the implicit conversions that are being applied to the arguments.
 
825
                /// </summary>
 
826
                public IList<Conversion> ArgumentConversions {
 
827
                        get {
 
828
                                if (bestCandidate != null && bestCandidate.ArgumentConversions != null)
 
829
                                        return bestCandidate.ArgumentConversions;
 
830
                                else
 
831
                                        return Enumerable.Repeat(Conversion.None, arguments.Length).ToList();
 
832
                        }
 
833
                }
 
834
                
 
835
                /// <summary>
 
836
                /// Gets an array that maps argument indices to parameter indices.
 
837
                /// For arguments that could not be mapped to any parameter, the value will be -1.
 
838
                /// 
 
839
                /// parameterIndex = GetArgumentToParameterMap()[argumentIndex]
 
840
                /// </summary>
 
841
                public IList<int> GetArgumentToParameterMap()
 
842
                {
 
843
                        if (bestCandidate != null)
 
844
                                return bestCandidate.ArgumentToParameterMap;
 
845
                        else
 
846
                                return null;
 
847
                }
 
848
                
 
849
                /// <summary>
 
850
                /// Returns the arguments for the method call in the order they were provided (not in the order of the parameters).
 
851
                /// Arguments are wrapped in a <see cref="ConversionResolveResult"/> if an implicit conversion is being applied
 
852
                /// to them when calling the method.
 
853
                /// </summary>
 
854
                public IList<ResolveResult> GetArgumentsWithConversions()
 
855
                {
 
856
                        if (bestCandidate == null)
 
857
                                return arguments;
 
858
                        else
 
859
                                return GetArgumentsWithConversions(null, null);
 
860
                }
 
861
                
 
862
                /// <summary>
 
863
                /// Returns the arguments for the method call in the order they were provided (not in the order of the parameters).
 
864
                /// Arguments are wrapped in a <see cref="ConversionResolveResult"/> if an implicit conversion is being applied
 
865
                /// to them when calling the method.
 
866
                /// For arguments where an explicit argument name was provided, the argument will
 
867
                /// be wrapped in a <see cref="NamedArgumentResolveResult"/>.
 
868
                /// </summary>
 
869
                public IList<ResolveResult> GetArgumentsWithConversionsAndNames()
 
870
                {
 
871
                        if (bestCandidate == null)
 
872
                                return arguments;
 
873
                        else
 
874
                                return GetArgumentsWithConversions(null, GetBestCandidateWithSubstitutedTypeArguments());
 
875
                }
 
876
                
 
877
                IList<ResolveResult> GetArgumentsWithConversions(ResolveResult targetResolveResult, IParameterizedMember bestCandidateForNamedArguments)
 
878
                {
 
879
                        var conversions = this.ArgumentConversions;
 
880
                        ResolveResult[] args = new ResolveResult[arguments.Length];
 
881
                        for (int i = 0; i < args.Length; i++) {
 
882
                                var argument = arguments[i];
 
883
                                if (this.IsExtensionMethodInvocation && i == 0 && targetResolveResult != null)
 
884
                                        argument = targetResolveResult;
 
885
                                int parameterIndex = bestCandidate.ArgumentToParameterMap[i];
 
886
                                if (parameterIndex >= 0 && conversions[i] != Conversion.IdentityConversion) {
 
887
                                        // Wrap argument in ConversionResolveResult
 
888
                                        IType parameterType = bestCandidate.ParameterTypes[parameterIndex];
 
889
                                        if (parameterType.Kind != TypeKind.Unknown) {
 
890
                                                if (arguments[i].IsCompileTimeConstant && conversions[i] != Conversion.None) {
 
891
                                                        argument = new CSharpResolver(compilation).WithCheckForOverflow(CheckForOverflow).ResolveCast(parameterType, argument);
 
892
                                                } else {
 
893
                                                        argument = new ConversionResolveResult(parameterType, argument, conversions[i], CheckForOverflow);
 
894
                                                }
 
895
                                        }
 
896
                                }
 
897
                                if (bestCandidateForNamedArguments != null && argumentNames[i] != null) {
 
898
                                        // Wrap argument in NamedArgumentResolveResult
 
899
                                        if (parameterIndex >= 0) {
 
900
                                                argument = new NamedArgumentResolveResult(bestCandidateForNamedArguments.Parameters[parameterIndex], argument, bestCandidateForNamedArguments);
 
901
                                        } else {
 
902
                                                argument = new NamedArgumentResolveResult(argumentNames[i], argument);
 
903
                                        }
 
904
                                }
 
905
                                args[i] = argument;
 
906
                        }
 
907
                        return args;
 
908
                }
 
909
                
 
910
                public IParameterizedMember GetBestCandidateWithSubstitutedTypeArguments()
 
911
                {
 
912
                        if (bestCandidate == null)
 
913
                                return null;
 
914
                        IMethod method = bestCandidate.Member as IMethod;
 
915
                        if (method != null && method.TypeParameters.Count > 0) {
 
916
                                return ((IMethod)method.MemberDefinition).Specialize(GetSubstitution(bestCandidate));
 
917
                        } else {
 
918
                                return bestCandidate.Member;
 
919
                        }
 
920
                }
 
921
                
 
922
                TypeParameterSubstitution GetSubstitution(Candidate candidate)
 
923
                {
 
924
                        // Do not compose the substitutions, but merge them.
 
925
                        // This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
 
926
                        return new TypeParameterSubstitution(candidate.Member.Substitution.ClassTypeArguments, candidate.InferredTypes);
 
927
                }
 
928
                
 
929
                /// <summary>
 
930
                /// Creates a ResolveResult representing the result of overload resolution.
 
931
                /// </summary>
 
932
                /// <param name="targetResolveResult">
 
933
                /// The target expression of the call. May be <c>null</c> for static methods/constructors.
 
934
                /// </param>
 
935
                /// <param name="initializerStatements">
 
936
                /// Statements for Objects/Collections initializer.
 
937
                /// <see cref="InvocationResolveResult.InitializerStatements"/>
 
938
                /// <param name="returnTypeOverride">
 
939
                /// If not null, use this instead of the ReturnType of the member as the type of the created resolve result.
 
940
                /// </param>
 
941
                /// </param>
 
942
                public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null, IType returnTypeOverride = null)
 
943
                {
 
944
                        IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments();
 
945
                        if (member == null)
 
946
                                throw new InvalidOperationException();
 
947
 
 
948
                        return new CSharpInvocationResolveResult(
 
949
                                this.IsExtensionMethodInvocation ? new TypeResolveResult(member.DeclaringType) : targetResolveResult,
 
950
                                member,
 
951
                                GetArgumentsWithConversions(targetResolveResult, member),
 
952
                                this.BestCandidateErrors,
 
953
                                this.IsExtensionMethodInvocation,
 
954
                                this.BestCandidateIsExpandedForm,
 
955
                                isDelegateInvocation: false,
 
956
                                argumentToParameterMap: this.GetArgumentToParameterMap(),
 
957
                                initializerStatements: initializerStatements,
 
958
                                returnTypeOverride: returnTypeOverride);
 
959
                }
 
960
                #endregion
 
961
        }
 
962
}