/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs
467 строк
18 KB
Julien Couvreur
Extensions: Resolve classic and new extension methods together (#77343)
03 мар 2025, 21:31
Не верифицирован
03 мар 2025, 21:31
7ca8f26
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { [SuppressMessage("Performance", "CA1067", Justification = "Equality not actually implemented")] internal #if !DEBUG readonly #endif struct MemberAnalysisResult { #if DEBUG private readonly ImmutableArray<Conversion> _conversionsOpt; public ImmutableArray<Conversion> ConversionsOpt { get { Debug.Assert(!_argumentsCoerced); return _conversionsOpt; } private init { _conversionsOpt = value; } } /// <summary> /// A bit vector representing whose true bits indicate indices of bad arguments /// </summary> /// <remarks> /// The capacity of this BitVector might not match the parameter count of the method overload being resolved. /// For example, if a method overload has 5 parameters and the second parameter is the only bad parameter, then this /// BitVector could end up with Capacity being 2 where BadArguments[0] is false and BadArguments[1] is true. /// </remarks> private readonly BitVector _badArgumentsOpt; public BitVector BadArgumentsOpt { get { Debug.Assert(!_argumentsCoerced); return _badArgumentsOpt; } private init { _badArgumentsOpt = value; } } private readonly ImmutableArray<int> _argsToParamsOpt; public ImmutableArray<int> ArgsToParamsOpt { get { Debug.Assert(!_argumentsCoerced); return _argsToParamsOpt; } private init { _argsToParamsOpt = value; } } private readonly ImmutableArray<TypeParameterDiagnosticInfo> _constraintFailureDiagnostics; public ImmutableArray<TypeParameterDiagnosticInfo> ConstraintFailureDiagnostics { get { Debug.Assert(!_argumentsCoerced); return _constraintFailureDiagnostics; } private init { _constraintFailureDiagnostics = value; } } private bool _argumentsCoerced; #else // put these first for better packing public readonly ImmutableArray<Conversion> ConversionsOpt; /// <summary> /// A bit vector representing whose true bits indicate indices of bad arguments /// </summary> /// <remarks> /// The capacity of this BitVector might not match the parameter count of the method overload being resolved. /// For example, if a method overload has 5 parameters and the second parameter is the only bad parameter, then this /// BitVector could end up with Capacity being 2 where BadArguments[0] is false and BadArguments[1] is true. /// </remarks> public readonly BitVector BadArgumentsOpt; public readonly ImmutableArray<int> ArgsToParamsOpt; public readonly ImmutableArray<TypeParameterDiagnosticInfo> ConstraintFailureDiagnostics; #endif public readonly int BadParameter; public readonly MemberResolutionKind Kind; public readonly TypeWithAnnotations DefinitionParamsElementTypeOpt; public readonly TypeWithAnnotations ParamsElementTypeOpt; /// <summary> /// Omit ref feature for COM interop: We can pass arguments by value for ref parameters if we are invoking a method/property on an instance of a COM imported type. /// This property returns a flag indicating whether we had any ref omitted argument for the given call. /// </summary> public readonly bool HasAnyRefOmittedArgument; private MemberAnalysisResult( MemberResolutionKind kind, BitVector badArgumentsOpt = default, ImmutableArray<int> argsToParamsOpt = default, ImmutableArray<Conversion> conversionsOpt = default, int missingParameter = -1, bool hasAnyRefOmittedArgument = false, ImmutableArray<TypeParameterDiagnosticInfo> constraintFailureDiagnosticsOpt = default, TypeWithAnnotations definitionParamsElementTypeOpt = default, TypeWithAnnotations paramsElementTypeOpt = default) { Debug.Assert(kind != MemberResolutionKind.ApplicableInExpandedForm || definitionParamsElementTypeOpt.HasType); Debug.Assert(kind != MemberResolutionKind.ApplicableInExpandedForm || paramsElementTypeOpt.HasType); this.Kind = kind; this.DefinitionParamsElementTypeOpt = definitionParamsElementTypeOpt; this.ParamsElementTypeOpt = paramsElementTypeOpt; this.BadArgumentsOpt = badArgumentsOpt; this.ArgsToParamsOpt = argsToParamsOpt; this.ConversionsOpt = conversionsOpt; this.BadParameter = missingParameter; this.HasAnyRefOmittedArgument = hasAnyRefOmittedArgument; this.ConstraintFailureDiagnostics = constraintFailureDiagnosticsOpt.NullToEmpty(); } public override bool Equals(object obj) { throw ExceptionUtilities.Unreachable(); } public override int GetHashCode() { throw ExceptionUtilities.Unreachable(); } public Conversion ConversionForArg(int arg) { if (this.ConversionsOpt.IsDefault) { return Conversion.Identity; } return this.ConversionsOpt[arg]; } public int ParameterFromArgument(int arg) { Debug.Assert(arg >= 0); if (ArgsToParamsOpt.IsDefault) { return arg; } Debug.Assert(arg < ArgsToParamsOpt.Length); return ArgsToParamsOpt[arg]; } public int FirstBadArgument => BadArgumentsOpt.TrueBits().First(); // A method may be applicable, but worse than another method. public bool IsApplicable { get { switch (this.Kind) { case MemberResolutionKind.ApplicableInNormalForm: case MemberResolutionKind.ApplicableInExpandedForm: case MemberResolutionKind.Worse: case MemberResolutionKind.Worst: return true; default: return false; } } } public bool IsValid { get { switch (this.Kind) { case MemberResolutionKind.ApplicableInNormalForm: case MemberResolutionKind.ApplicableInExpandedForm: return true; default: return false; } } } /// <remarks> /// Returns false for <see cref="MemberResolutionKind.UnsupportedMetadata"/> /// because those diagnostics are only reported if no other candidates are /// available. /// </remarks> internal bool HasUseSiteDiagnosticToReportFor(Symbol symbol) { // There is a use site diagnostic to report here, but it is not reported // just because this member was a candidate - only if it "wins". return !SuppressUseSiteDiagnosticsForKind(this.Kind) && (object)symbol != null && symbol.GetUseSiteInfo().DiagnosticInfo != null; } private static bool SuppressUseSiteDiagnosticsForKind(MemberResolutionKind kind) { switch (kind) { case MemberResolutionKind.UnsupportedMetadata: return true; case MemberResolutionKind.NoCorrespondingParameter: case MemberResolutionKind.NoCorrespondingNamedParameter: case MemberResolutionKind.DuplicateNamedArgument: case MemberResolutionKind.NameUsedForPositional: case MemberResolutionKind.RequiredParameterMissing: case MemberResolutionKind.LessDerived: // Dev12 checks all of these things before considering use site diagnostics. // That is, use site diagnostics are suppressed for candidates rejected for these reasons. return true; default: return false; } } public static MemberAnalysisResult ArgumentParameterMismatch(ArgumentAnalysisResult argAnalysis) { switch (argAnalysis.Kind) { case ArgumentAnalysisResultKind.NoCorrespondingParameter: return NoCorrespondingParameter(argAnalysis.ArgumentPosition); case ArgumentAnalysisResultKind.NoCorrespondingNamedParameter: return NoCorrespondingNamedParameter(argAnalysis.ArgumentPosition); case ArgumentAnalysisResultKind.DuplicateNamedArgument: return DuplicateNamedArgument(argAnalysis.ArgumentPosition); case ArgumentAnalysisResultKind.RequiredParameterMissing: return RequiredParameterMissing(argAnalysis.ParameterPosition); case ArgumentAnalysisResultKind.NameUsedForPositional: return NameUsedForPositional(argAnalysis.ArgumentPosition); case ArgumentAnalysisResultKind.BadNonTrailingNamedArgument: return BadNonTrailingNamedArgument(argAnalysis.ArgumentPosition); default: throw ExceptionUtilities.UnexpectedValue(argAnalysis.Kind); } } public static MemberAnalysisResult NameUsedForPositional(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NameUsedForPositional, badArgumentsOpt: CreateBadArgumentsWithPosition(argumentPosition)); } public static MemberAnalysisResult BadNonTrailingNamedArgument(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.BadNonTrailingNamedArgument, badArgumentsOpt: CreateBadArgumentsWithPosition(argumentPosition)); } public static MemberAnalysisResult NoCorrespondingParameter(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NoCorrespondingParameter, badArgumentsOpt: CreateBadArgumentsWithPosition(argumentPosition)); } public static MemberAnalysisResult NoCorrespondingNamedParameter(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NoCorrespondingNamedParameter, badArgumentsOpt: CreateBadArgumentsWithPosition(argumentPosition)); } public static MemberAnalysisResult DuplicateNamedArgument(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.DuplicateNamedArgument, badArgumentsOpt: CreateBadArgumentsWithPosition(argumentPosition)); } internal static BitVector CreateBadArgumentsWithPosition(int argumentPosition) { var badArguments = BitVector.Create(argumentPosition + 1); badArguments[argumentPosition] = true; return badArguments; } public static MemberAnalysisResult RequiredParameterMissing(int parameterPosition) { return new MemberAnalysisResult( MemberResolutionKind.RequiredParameterMissing, missingParameter: parameterPosition); } public static MemberAnalysisResult UseSiteError() { return new MemberAnalysisResult(MemberResolutionKind.UseSiteError); } public static MemberAnalysisResult UnsupportedMetadata() { return new MemberAnalysisResult(MemberResolutionKind.UnsupportedMetadata); } public static MemberAnalysisResult BadArgumentConversions(ImmutableArray<int> argsToParamsOpt, BitVector badArguments, ImmutableArray<Conversion> conversions, TypeWithAnnotations definitionParamsElementTypeOpt, TypeWithAnnotations paramsElementTypeOpt) { Debug.Assert(conversions.Length != 0); Debug.Assert(badArguments.TrueBits().Any()); return new MemberAnalysisResult( MemberResolutionKind.BadArgumentConversion, badArguments, argsToParamsOpt, conversions, definitionParamsElementTypeOpt: definitionParamsElementTypeOpt, paramsElementTypeOpt: paramsElementTypeOpt); } public static MemberAnalysisResult InaccessibleTypeArgument() { return new MemberAnalysisResult(MemberResolutionKind.InaccessibleTypeArgument); } public static MemberAnalysisResult TypeInferenceFailed() { return new MemberAnalysisResult(MemberResolutionKind.TypeInferenceFailed); } public static MemberAnalysisResult TypeInferenceExtensionInstanceArgumentFailed() { return new MemberAnalysisResult(MemberResolutionKind.TypeInferenceExtensionInstanceArgument); } public static MemberAnalysisResult StaticInstanceMismatch() { return new MemberAnalysisResult(MemberResolutionKind.StaticInstanceMismatch); } public static MemberAnalysisResult ConstructedParameterFailedConstraintsCheck(int parameterPosition) { return new MemberAnalysisResult( MemberResolutionKind.ConstructedParameterFailedConstraintCheck, missingParameter: parameterPosition); } public static MemberAnalysisResult WrongRefKind() { return new MemberAnalysisResult(MemberResolutionKind.WrongRefKind); } public static MemberAnalysisResult WrongReturnType() { return new MemberAnalysisResult(MemberResolutionKind.WrongReturnType); } public static MemberAnalysisResult LessDerived() { return new MemberAnalysisResult(MemberResolutionKind.LessDerived); } public static MemberAnalysisResult NormalForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyRefOmittedArgument) { return new MemberAnalysisResult(MemberResolutionKind.ApplicableInNormalForm, BitVector.Null, argsToParamsOpt, conversions, hasAnyRefOmittedArgument: hasAnyRefOmittedArgument); } public static MemberAnalysisResult ExpandedForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyRefOmittedArgument, TypeWithAnnotations definitionParamsElementType, TypeWithAnnotations paramsElementType) { return new MemberAnalysisResult( MemberResolutionKind.ApplicableInExpandedForm, BitVector.Null, argsToParamsOpt, conversions, hasAnyRefOmittedArgument: hasAnyRefOmittedArgument, definitionParamsElementTypeOpt: definitionParamsElementType, paramsElementTypeOpt: paramsElementType); } public static MemberAnalysisResult Worse() { return new MemberAnalysisResult(MemberResolutionKind.Worse); } public static MemberAnalysisResult Worst() { return new MemberAnalysisResult(MemberResolutionKind.Worst); } internal static MemberAnalysisResult ConstraintFailure(ImmutableArray<TypeParameterDiagnosticInfo> constraintFailureDiagnostics) { return new MemberAnalysisResult(MemberResolutionKind.ConstraintFailure, constraintFailureDiagnosticsOpt: constraintFailureDiagnostics); } internal static MemberAnalysisResult WrongCallingConvention() { return new MemberAnalysisResult(MemberResolutionKind.WrongCallingConvention); } [Conditional("DEBUG")] public void ArgumentsWereCoerced() { #if DEBUG _argumentsCoerced = true; #endif } internal MemberAnalysisResult WithoutReceiverArgument() { var badArguments = shift(BadArgumentsOpt); var argsToParams = adjustArgsToParams(ArgsToParamsOpt); var conversions = adjustConversions(ConversionsOpt); // We only need HasAnyRefOmittedArgument as part of overload resolution, so we don't need to adjust it post-overload resolution. return new MemberAnalysisResult(Kind, badArguments, argsToParams, conversions, BadParameter - 1, HasAnyRefOmittedArgument, ConstraintFailureDiagnostics, DefinitionParamsElementTypeOpt, ParamsElementTypeOpt); static BitVector shift(BitVector badArguments) { if (badArguments.IsNull) { return badArguments; } var result = BitVector.Create(badArguments.Capacity); foreach (int setIndex in badArguments.TrueBits()) { result[setIndex] = true; } return result; } static ImmutableArray<int> adjustArgsToParams(ImmutableArray<int> argsToParams) { if (argsToParams.IsDefault) { return argsToParams; } var builder = ArrayBuilder<int>.GetInstance(); builder.AddRange(argsToParams, 1, argsToParams.Length - 1); for (int i = 0; i < builder.Count; i++) { builder[i]--; } return builder.ToImmutableAndFree(); } static ImmutableArray<Conversion> adjustConversions(ImmutableArray<Conversion> conversions) { return conversions.IsDefaultOrEmpty ? conversions : conversions.RemoveAt(0); } } } }