// Takes a list of candidates and mutates the list to throw out the ones that are worse than // another applicable candidate. private void UnaryOperatorOverloadResolution( BoundExpression operand, UnaryOperatorOverloadResolutionResult result, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { // SPEC: Given the set of applicable candidate function members, the best function member in that set is located. // SPEC: If the set contains only one function member, then that function member is the best function member. if (result.SingleValid()) { return; } // SPEC: Otherwise, the best function member is the one function member that is better than all other function // SPEC: members with respect to the given argument list, provided that each function member is compared to all // SPEC: other function members using the rules in 7.5.3.2. If there is not exactly one function member that is // SPEC: better than all other function members, then the function member invocation is ambiguous and a binding-time // SPEC: error occurs. var candidates = result.Results; // Try to find a single best candidate int bestIndex = GetTheBestCandidateIndex(operand, candidates, ref useSiteDiagnostics); if (bestIndex != -1) { // Mark all other candidates as worse for (int index = 0; index < candidates.Count; ++index) { if (candidates[index].Kind != OperatorAnalysisResultKind.Inapplicable && index != bestIndex) { candidates[index] = candidates[index].Worse(); } } return; } for (int i = 1; i < candidates.Count; ++i) { if (candidates[i].Kind != OperatorAnalysisResultKind.Applicable) { continue; } // Is this applicable operator better than every other applicable method? for (int j = 0; j < i; ++j) { if (candidates[j].Kind == OperatorAnalysisResultKind.Inapplicable) { continue; } var better = BetterOperator(candidates[i].Signature, candidates[j].Signature, operand, ref useSiteDiagnostics); if (better == BetterResult.Left) { candidates[j] = candidates[j].Worse(); } else if (better == BetterResult.Right) { candidates[i] = candidates[i].Worse(); } } } }
private void UnaryOperatorEasyOut(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result) { var operandType = operand.Type; if ((object)operandType == null) { return; } var easyOut = UnopEasyOut.OpKind(kind, operandType); if (easyOut == UnaryOperatorKind.Error) { return; } UnaryOperatorSignature signature = this.Compilation.builtInOperators.GetSignature(easyOut); Conversion?conversion = Conversions.FastClassifyConversion(operandType, signature.OperandType); Debug.Assert(conversion.HasValue && conversion.Value.IsImplicit); result.Results.Add(UnaryOperatorAnalysisResult.Applicable(signature, conversion.Value)); }
public void UnaryOperatorOverloadResolution(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(operand != null); Debug.Assert(result.Results.Count == 0); // We can do a table lookup for well-known problems in overload resolution. UnaryOperatorEasyOut(kind, operand, result); if (result.Results.Count > 0) { return; } // SPEC: An operation of the form op x or x op, where op is an overloadable unary operator, // SPEC: and x is an expression of type X, is processed as follows: // SPEC: The set of candidate user-defined operators provided by X for the operation operator // SPEC: op(x) is determined using the rules of 7.3.5. bool hadUserDefinedCandidate = GetUserDefinedOperators(kind, operand, result.Results, ref useSiteDiagnostics); // SPEC: If the set of candidate user-defined operators is not empty, then this becomes the // SPEC: set of candidate operators for the operation. Otherwise, the predefined unary operator // SPEC: implementations, including their lifted forms, become the set of candidate operators // SPEC: for the operation. if (!hadUserDefinedCandidate) { result.Results.Clear(); GetAllBuiltInOperators(kind, operand, result.Results, ref useSiteDiagnostics); } // SPEC: The overload resolution rules of 7.5.3 are applied to the set of candidate operators // SPEC: to select the best operator with respect to the argument list (x), and this operator // SPEC: becomes the result of the overload resolution process. If overload resolution fails // SPEC: to select a single best operator, a binding-time error occurs. UnaryOperatorOverloadResolution(operand, result, ref useSiteDiagnostics); }