Skip to content

Commit 4d981e3

Browse files
Merge pull request #63904 from LucianoPAlmeida/ambiguous-overload
[Sema] Diagnose function coercion ambiguity
2 parents 4700f81 + b375c09 commit 4d981e3

File tree

10 files changed

+233
-120
lines changed

10 files changed

+233
-120
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,10 +1403,13 @@ WARNING(unlabeled_trailing_closure_deprecated,Deprecation,
14031403
NOTE(decl_multiple_defaulted_closure_parameters,none,
14041404
"%0 contains defaulted closure parameters %1 and %2",
14051405
(DeclName, Identifier, Identifier))
1406+
NOTE(candidate_with_extraneous_args_closure,none,
1407+
"candidate %0 requires %1 argument%s1, "
1408+
"but %2 %select{were|was}3 used in closure body",
1409+
(Type, unsigned, unsigned, bool))
14061410
NOTE(candidate_with_extraneous_args,none,
1407-
"candidate %0 requires %1 argument%s1, "
1408-
"but %2 %select{were|was}3 %select{provided|used in closure body}4",
1409-
(Type, unsigned, unsigned, bool, bool))
1411+
"candidate %0 has %1 parameter%s1, but context %2 has %3",
1412+
(Type, unsigned, Type, unsigned))
14101413

14111414
ERROR(no_accessible_initializers,none,
14121415
"%0 cannot be constructed because it has no accessible initializers",

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ ABSTRACT_LOCATOR_PATH_ELT(PatternDecl)
265265
/// A function type global actor.
266266
SIMPLE_LOCATOR_PATH_ELT(GlobalActorType)
267267

268+
/// A type coercion operand.
269+
SIMPLE_LOCATOR_PATH_ELT(CoercionOperand)
270+
268271
#undef LOCATOR_PATH_ELT
269272
#undef CUSTOM_LOCATOR_PATH_ELT
270273
#undef SIMPLE_LOCATOR_PATH_ELT

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4349,7 +4349,8 @@ namespace {
43494349
// If we weren't explicitly told by the caller which disjunction choice,
43504350
// get it from the solution to determine whether we've picked a coercion
43514351
// or a bridging conversion.
4352-
auto *locator = cs.getConstraintLocator(expr);
4352+
auto *locator =
4353+
cs.getConstraintLocator(expr, ConstraintLocator::CoercionOperand);
43534354
auto choice = solution.getDisjunctionChoice(locator);
43544355

43554356
// Handle the coercion/bridging of the underlying subexpression, where

lib/Sema/CSDiagnostics.cpp

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ ValueDecl *RequirementFailure::getDeclRef() const {
282282
return getAffectedDeclFromType(contextualTy);
283283
}
284284

285+
if (getLocator()->isFirstElement<LocatorPathElt::CoercionOperand>())
286+
return getAffectedDeclFromType(getOwnerType());
287+
285288
if (auto overload = getCalleeOverloadChoiceIfAvailable(getLocator())) {
286289
// If there is a declaration associated with this
287290
// failure e.g. an overload choice of the call
@@ -786,7 +789,8 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
786789
//
787790
// `value` has to get implicitly wrapped into 2 optionals
788791
// before pointer types could be compared.
789-
auto path = getLocator()->getPath();
792+
auto locator = getLocator();
793+
auto path = locator->getPath();
790794
unsigned toDrop = 0;
791795
for (const auto &elt : llvm::reverse(path)) {
792796
if (!elt.is<LocatorPathElt::OptionalPayload>())
@@ -802,7 +806,7 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
802806
if (path.empty()) {
803807
if (isExpr<AssignExpr>(anchor)) {
804808
diagnostic = getDiagnosticFor(CTP_AssignSource);
805-
} else if (isExpr<CoerceExpr>(anchor)) {
809+
} else if (locator->isForCoercion()) {
806810
diagnostic = getDiagnosticFor(CTP_CoerceOperand);
807811
} else {
808812
return false;
@@ -887,6 +891,11 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
887891
break;
888892
}
889893

894+
case ConstraintLocator::CoercionOperand: {
895+
diagnostic = getDiagnosticFor(CTP_CoerceOperand);
896+
break;
897+
}
898+
890899
default:
891900
break;
892901
}
@@ -1219,6 +1228,14 @@ ASTNode InvalidCoercionFailure::getAnchor() const {
12191228
return anchor;
12201229
}
12211230

1231+
SourceLoc InvalidCoercionFailure::getLoc() const {
1232+
if (getLocator()->isForCoercion()) {
1233+
auto *CE = castToExpr<CoerceExpr>(getRawAnchor());
1234+
return CE->getAsLoc();
1235+
}
1236+
return FailureDiagnostic::getLoc();
1237+
}
1238+
12221239
bool InvalidCoercionFailure::diagnoseAsError() {
12231240
auto fromType = getFromType();
12241241
auto toType = getToType();
@@ -2487,7 +2504,7 @@ bool ContextualFailure::diagnoseAsError() {
24872504
diagnostic = diag::cannot_convert_condition_value;
24882505
break;
24892506
}
2490-
2507+
case ConstraintLocator::CoercionOperand:
24912508
case ConstraintLocator::InstanceType: {
24922509
if (diagnoseCoercionToUnrelatedType())
24932510
return true;
@@ -2809,7 +2826,7 @@ bool ContextualFailure::diagnoseConversionToNil() const {
28092826
emitDiagnostic(diag::unresolved_nil_literal);
28102827
return true;
28112828
}
2812-
} else if (isa<CoerceExpr>(parentExpr)) {
2829+
} else if (locator->isForCoercion()) {
28132830
// `nil` is passed as a left-hand side of the coercion
28142831
// operator e.g. `nil as Foo`
28152832
CTP = CTP_CoerceOperand;
@@ -2891,23 +2908,23 @@ bool ContextualFailure::diagnoseExtraneousAssociatedValues() const {
28912908
}
28922909

28932910
bool ContextualFailure::diagnoseCoercionToUnrelatedType() const {
2894-
auto anchor = getAnchor();
2911+
auto anchor = getRawAnchor();
2912+
auto *coerceExpr = getAsExpr<CoerceExpr>(anchor);
2913+
if (!coerceExpr) {
2914+
return false;
2915+
}
28952916

2896-
if (auto *coerceExpr = getAsExpr<CoerceExpr>(anchor)) {
2897-
const auto fromType = getType(coerceExpr->getSubExpr());
2898-
const auto toType = getType(coerceExpr->getCastTypeRepr());
2917+
const auto fromType = getType(coerceExpr->getSubExpr());
2918+
const auto toType = getType(coerceExpr->getCastTypeRepr());
28992919

2900-
auto diagnostic = getDiagnosticFor(CTP_CoerceOperand, toType);
2920+
auto diagnostic = getDiagnosticFor(CTP_CoerceOperand, toType);
29012921

2902-
auto diag = emitDiagnostic(*diagnostic, fromType, toType);
2903-
diag.highlight(getSourceRange());
2922+
auto diag = emitDiagnostic(*diagnostic, fromType, toType);
2923+
diag.highlight(getSourceRange());
29042924

2905-
(void)tryFixIts(diag);
2906-
2907-
return true;
2908-
}
2925+
(void)tryFixIts(diag);
29092926

2910-
return false;
2927+
return true;
29112928
}
29122929

29132930
bool ContextualFailure::diagnoseConversionToBool() const {
@@ -3178,9 +3195,6 @@ bool ContextualFailure::trySequenceSubsequenceFixIts(
31783195
if (getFromType()->isSubstring()) {
31793196
if (getToType()->isString()) {
31803197
auto *anchor = castToExpr(getAnchor())->getSemanticsProvidingExpr();
3181-
if (auto *CE = dyn_cast<CoerceExpr>(anchor)) {
3182-
anchor = CE->getSubExpr();
3183-
}
31843198

31853199
if (auto *call = dyn_cast<CallExpr>(anchor)) {
31863200
auto *fnExpr = call->getFn();
@@ -5860,9 +5874,15 @@ bool ExtraneousArgumentsFailure::diagnoseAsNote() {
58605874

58615875
auto *decl = overload->choice.getDecl();
58625876
auto numArgs = getTotalNumArguments();
5863-
emitDiagnosticAt(decl, diag::candidate_with_extraneous_args, ContextualType,
5864-
ContextualType->getNumParams(), numArgs, (numArgs == 1),
5865-
isExpr<ClosureExpr>(getAnchor()));
5877+
if (isExpr<ClosureExpr>(getAnchor())) {
5878+
emitDiagnosticAt(decl, diag::candidate_with_extraneous_args_closure,
5879+
ContextualType, ContextualType->getNumParams(), numArgs,
5880+
(numArgs == 1));
5881+
} else {
5882+
emitDiagnosticAt(decl, diag::candidate_with_extraneous_args,
5883+
overload->adjustedOpenedType, numArgs, ContextualType,
5884+
ContextualType->getNumParams());
5885+
}
58665886
return true;
58675887
}
58685888

@@ -8878,12 +8898,7 @@ GlobalActorFunctionMismatchFailure::getDiagnosticMessage() const {
88788898
auto path = locator->getPath();
88798899

88808900
if (path.empty()) {
8881-
auto anchor = getAnchor();
8882-
if (isExpr<CoerceExpr>(anchor)) {
8883-
return diag::cannot_convert_global_actor_coercion;
8884-
} else {
8885-
return diag::cannot_convert_global_actor;
8886-
}
8901+
return diag::cannot_convert_global_actor;
88878902
}
88888903

88898904
auto last = path.back();
@@ -8901,6 +8916,9 @@ GlobalActorFunctionMismatchFailure::getDiagnosticMessage() const {
89018916
case ConstraintLocator::TernaryBranch: {
89028917
return diag::ternary_expr_cases_global_actor_mismatch;
89038918
}
8919+
case ConstraintLocator::CoercionOperand: {
8920+
return diag::cannot_convert_global_actor_coercion;
8921+
}
89048922
default:
89058923
break;
89068924
}

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,6 +2177,8 @@ class InvalidCoercionFailure final : public ContextualFailure {
21772177

21782178
ASTNode getAnchor() const override;
21792179

2180+
SourceLoc getLoc() const override;
2181+
21802182
bool diagnoseAsError() override;
21812183
};
21822184

lib/Sema/CSGen.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,7 +3307,8 @@ namespace {
33073307
if (repr) CS.setType(repr, toType);
33083308

33093309
auto fromType = CS.getType(expr->getSubExpr());
3310-
auto locator = CS.getConstraintLocator(expr);
3310+
auto locator =
3311+
CS.getConstraintLocator(expr, ConstraintLocator::CoercionOperand);
33113312

33123313
// Literal initialization (e.g. `UInt32(0)`) doesn't require
33133314
// a conversion because the literal is supposed to assume the
@@ -3327,8 +3328,11 @@ namespace {
33273328

33283329
// If the result type was declared IUO, add a disjunction for
33293330
// bindings for the result of the coercion.
3330-
if (repr && repr->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional)
3331-
return createTypeVariableAndDisjunctionForIUOCoercion(toType, locator);
3331+
if (repr &&
3332+
repr->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) {
3333+
return createTypeVariableAndDisjunctionForIUOCoercion(
3334+
toType, CS.getConstraintLocator(expr));
3335+
}
33323336

33333337
return toType;
33343338
}

lib/Sema/CSSimplify.cpp

Lines changed: 61 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5058,63 +5058,6 @@ bool ConstraintSystem::repairFailures(
50585058
if (!anchor)
50595059
return false;
50605060

5061-
if (auto *coercion = getAsExpr<CoerceExpr>(anchor)) {
5062-
// Coercion from T.Type to T.Protocol.
5063-
if (hasConversionOrRestriction(
5064-
ConversionRestrictionKind::MetatypeToExistentialMetatype))
5065-
return false;
5066-
5067-
if (hasConversionOrRestriction(ConversionRestrictionKind::Superclass))
5068-
return false;
5069-
5070-
// Let's check whether the sub-expression is an optional type which
5071-
// is possible to unwrap (either by force or `??`) to satisfy the cast,
5072-
// otherwise we'd have to fallback to force downcast.
5073-
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
5074-
conversionsOrFixes,
5075-
getConstraintLocator(coercion->getSubExpr())))
5076-
return true;
5077-
5078-
// If the result type of the coercion has an value to optional conversion
5079-
// we can instead suggest the conditional downcast as it is safer in
5080-
// situations like conditional binding.
5081-
auto useConditionalCast =
5082-
llvm::any_of(ConstraintRestrictions, [&](const auto &restriction) {
5083-
Type type1, type2;
5084-
std::tie(type1, type2) = restriction.first;
5085-
auto restrictionKind = restriction.second;
5086-
5087-
if (restrictionKind != ConversionRestrictionKind::ValueToOptional)
5088-
return false;
5089-
5090-
return rhs->isEqual(type1);
5091-
});
5092-
5093-
// Repair a coercion ('as') with a runtime checked cast ('as!' or 'as?').
5094-
if (auto *coerceToCheckCastFix =
5095-
CoerceToCheckedCast::attempt(*this, lhs, rhs, useConditionalCast,
5096-
getConstraintLocator(locator))) {
5097-
conversionsOrFixes.push_back(coerceToCheckCastFix);
5098-
return true;
5099-
}
5100-
5101-
// If it has a deep equality restriction, defer the diagnostic to
5102-
// GenericMismatch.
5103-
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) &&
5104-
!hasConversionOrRestriction(
5105-
ConversionRestrictionKind::OptionalToOptional)) {
5106-
return false;
5107-
}
5108-
5109-
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
5110-
return false;
5111-
5112-
auto *fix = ContextualMismatch::create(*this, lhs, rhs,
5113-
getConstraintLocator(locator));
5114-
conversionsOrFixes.push_back(fix);
5115-
return true;
5116-
}
5117-
51185061
// This could be:
51195062
// - `InOutExpr` used with r-value e.g. `foo(&x)` where `x` is a `let`.
51205063
// - `ForceValueExpr` e.g. `foo.bar! = 42` where `bar` or `foo` are
@@ -6449,6 +6392,64 @@ bool ConstraintSystem::repairFailures(
64496392
break;
64506393
}
64516394

6395+
case ConstraintLocator::CoercionOperand: {
6396+
auto *coercion = castToExpr<CoerceExpr>(anchor);
6397+
6398+
// Coercion from T.Type to T.Protocol.
6399+
if (hasConversionOrRestriction(
6400+
ConversionRestrictionKind::MetatypeToExistentialMetatype))
6401+
return false;
6402+
6403+
if (hasConversionOrRestriction(ConversionRestrictionKind::Superclass))
6404+
return false;
6405+
6406+
// Let's check whether the sub-expression is an optional type which
6407+
// is possible to unwrap (either by force or `??`) to satisfy the cast,
6408+
// otherwise we'd have to fallback to force downcast.
6409+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
6410+
conversionsOrFixes,
6411+
getConstraintLocator(coercion->getSubExpr())))
6412+
return true;
6413+
6414+
// If the result type of the coercion has an value to optional conversion
6415+
// we can instead suggest the conditional downcast as it is safer in
6416+
// situations like conditional binding.
6417+
auto useConditionalCast =
6418+
llvm::any_of(ConstraintRestrictions, [&](const auto &restriction) {
6419+
Type type1, type2;
6420+
std::tie(type1, type2) = restriction.first;
6421+
auto restrictionKind = restriction.second;
6422+
6423+
if (restrictionKind != ConversionRestrictionKind::ValueToOptional)
6424+
return false;
6425+
6426+
return rhs->isEqual(type1);
6427+
});
6428+
6429+
// Repair a coercion ('as') with a runtime checked cast ('as!' or 'as?').
6430+
if (auto *coerceToCheckCastFix =
6431+
CoerceToCheckedCast::attempt(*this, lhs, rhs, useConditionalCast,
6432+
getConstraintLocator(locator))) {
6433+
conversionsOrFixes.push_back(coerceToCheckCastFix);
6434+
return true;
6435+
}
6436+
6437+
// If it has a deep equality restriction, defer the diagnostic to
6438+
// GenericMismatch.
6439+
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) &&
6440+
!hasConversionOrRestriction(
6441+
ConversionRestrictionKind::OptionalToOptional)) {
6442+
return false;
6443+
}
6444+
6445+
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
6446+
return false;
6447+
6448+
auto *fix = ContextualMismatch::create(*this, lhs, rhs,
6449+
getConstraintLocator(locator));
6450+
conversionsOrFixes.push_back(fix);
6451+
return true;
6452+
}
64526453
default:
64536454
break;
64546455
}
@@ -6963,7 +6964,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
69636964
ArrayRef<LocatorPathElt> path) {
69646965
// E.g. contextual conversion from coercion/cast
69656966
// to some other type.
6966-
if (!path.empty())
6967+
if (!(path.empty() ||
6968+
path.back().is<LocatorPathElt::CoercionOperand>()))
69676969
return false;
69686970

69696971
return isExpr<CoerceExpr>(anchor) || isExpr<IsExpr>(anchor) ||
@@ -11328,7 +11330,7 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
1132811330

1132911331
SmallVector<LocatorPathElt, 4> elts;
1133011332
auto anchor = locator.getLocatorParts(elts);
11331-
if (!elts.empty())
11333+
if (elts.empty() || !elts.back().is<LocatorPathElt::CoercionOperand>())
1133211334
return false;
1133311335

1133411336
auto *coercion = getAsExpr<CoerceExpr>(anchor);

0 commit comments

Comments
 (0)