Skip to content

Commit fe1cd74

Browse files
authored
Merge pull request #5808 from xedin/r28051973
2 parents 386b4b4 + 2707a9c commit fe1cd74

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,13 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
20652065
CalleeCandidateInfo &calleeInfo,
20662066
SourceLoc applyLoc);
20672067

2068+
/// Produce diagnostic for failures related to attributes associated with
2069+
/// candidate functions/methods e.g. mutability.
2070+
bool diagnoseMethodAttributeFailures(ApplyExpr *expr,
2071+
ArrayRef<Identifier> argLabels,
2072+
bool hasTrailingClosure,
2073+
CalleeCandidateInfo &candidates);
2074+
20682075
bool visitExpr(Expr *E);
20692076
bool visitIdentityExpr(IdentityExpr *E);
20702077
bool visitTryExpr(TryExpr *E);
@@ -5272,6 +5279,87 @@ bool FailureDiagnosis::diagnoseNilLiteralComparison(
52725279
return true;
52735280
}
52745281

5282+
bool FailureDiagnosis::diagnoseMethodAttributeFailures(
5283+
swift::ApplyExpr *callExpr, ArrayRef<Identifier> argLabels,
5284+
bool hasTrailingClosure, CalleeCandidateInfo &candidates) {
5285+
auto UDE = dyn_cast<UnresolvedDotExpr>(callExpr->getFn());
5286+
if (!UDE)
5287+
return false;
5288+
5289+
auto argExpr = callExpr->getArg();
5290+
auto argType = argExpr->getType();
5291+
5292+
// If type of the argument hasn't been established yet, we can't diagnose.
5293+
if (!argType || isUnresolvedOrTypeVarType(argType))
5294+
return false;
5295+
5296+
// Let's filter our candidate list based on that type.
5297+
candidates.filterList(argType, argLabels);
5298+
5299+
if (candidates.closeness == CC_ExactMatch)
5300+
return false;
5301+
5302+
// And if filtering didn't give an exact match, such means that problem
5303+
// might be related to function attributes which is best diagnosed by
5304+
// unviable member candidates, if any.
5305+
auto base = UDE->getBase();
5306+
auto baseType = base->getType();
5307+
5308+
// This handles following situation:
5309+
// struct S {
5310+
// mutating func f(_ i: Int) {}
5311+
// func f(_ f: Float) {}
5312+
// }
5313+
//
5314+
// Given struct has an overloaded method "f" with a single argument of
5315+
// multiple different types, one of the overloads is marked as
5316+
// "mutating", which means it can only be applied on LValue base type.
5317+
// So when struct is used like this:
5318+
//
5319+
// let answer: Int = 42
5320+
// S().f(answer)
5321+
//
5322+
// Constraint system generator is going to pick `f(_ f: Float)` as
5323+
// only possible overload candidate because "base" of the call is immutable
5324+
// and contextual information about argument type is not available yet.
5325+
// Such leads to incorrect contextual conversion failure diagnostic because
5326+
// type of the argument is going to resolved as (Int) no matter what.
5327+
// To workaround that fact and improve diagnostic of such cases we are going
5328+
// to try and collect all unviable candidates for a given call and check if
5329+
// at least one of them matches established argument type before even trying
5330+
// to re-check argument expression.
5331+
auto results = CS->performMemberLookup(
5332+
ConstraintKind::ValueMember, UDE->getName(), baseType,
5333+
UDE->getFunctionRefKind(), CS->getConstraintLocator(UDE),
5334+
/*includeInaccessibleMembers=*/false);
5335+
5336+
if (results.UnviableCandidates.empty())
5337+
return false;
5338+
5339+
SmallVector<OverloadChoice, 2> choices;
5340+
for (auto &unviable : results.UnviableCandidates)
5341+
choices.push_back(OverloadChoice(baseType, unviable.first,
5342+
/*isSpecialized=*/false,
5343+
UDE->getFunctionRefKind()));
5344+
5345+
CalleeCandidateInfo unviableCandidates(baseType, choices, hasTrailingClosure,
5346+
CS);
5347+
5348+
// Filter list of the unviable candidates based on the
5349+
// already established type of the argument expression.
5350+
unviableCandidates.filterList(argType, argLabels);
5351+
5352+
// If one of the unviable candidates matches arguments exactly,
5353+
// that means that actual problem is related to function attributes.
5354+
if (unviableCandidates.closeness == CC_ExactMatch) {
5355+
diagnoseUnviableLookupResults(results, baseType, base, UDE->getName(),
5356+
UDE->getNameLoc(), UDE->getLoc());
5357+
return true;
5358+
}
5359+
5360+
return false;
5361+
}
5362+
52755363
/// When initializing Unsafe[Mutable]Pointer<T> from Unsafe[Mutable]RawPointer,
52765364
/// issue a diagnostic that refers to the API for binding memory to a type.
52775365
static bool isCastToTypedPointer(ASTContext &Ctx, const Expr *Fn,
@@ -5445,7 +5533,15 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
54455533
if (diagnoseParameterErrors(calleeInfo, callExpr->getFn(),
54465534
callExpr->getArg(), argLabels))
54475535
return true;
5448-
5536+
5537+
// There might be a candidate with correct argument types but it's not
5538+
// used by constraint solver because it doesn't have correct attributes,
5539+
// let's try to diagnose such situation there right before type checking
5540+
// argument expression, because that would overwrite original argument types.
5541+
if (diagnoseMethodAttributeFailures(callExpr, argLabels, hasTrailingClosure,
5542+
calleeInfo))
5543+
return true;
5544+
54495545
Type argType; // Type of the argument list, if knowable.
54505546
if (auto FTy = fnType->getAs<AnyFunctionType>())
54515547
argType = FTy->getInput();

test/Constraints/overload.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,13 @@ struct X2 {
165165

166166
let x2 = X2(Int.self)
167167
let x2check: X2 = x2 // expected-error{{value of optional type 'X2?' not unwrapped; did you mean to use '!' or '?'?}}
168+
169+
// rdar://problem/28051973
170+
struct R_28051973 {
171+
mutating func f(_ i: Int) {}
172+
@available(*, deprecated, message: "deprecated")
173+
func f(_ f: Float) {}
174+
}
175+
176+
let r28051973: Int = 42
177+
R_28051973().f(r28051973) // expected-error {{cannot use mutating member on immutable value: function call returns immutable value}}

0 commit comments

Comments
 (0)