Skip to content

Commit 6edab6a

Browse files
committed
[Diagnostics] Prevent fix-it for explicit existential erasure from suppressing opening at use site
If erased result is passed as an argument to a call that requires implicit opening, the fix-it should use parens to avoid suppressing the opening at that argument position.
1 parent ec0b836 commit 6edab6a

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8158,9 +8158,39 @@ bool MissingExplicitExistentialCoercion::diagnoseAsNote() {
81588158
return true;
81598159
}
81608160

8161+
bool MissingExplicitExistentialCoercion::fixItRequiresParens() const {
8162+
auto anchor = getAsExpr(getRawAnchor());
8163+
8164+
// If it's a member reference an an existential metatype, let's
8165+
// use the parent "call" expression.
8166+
if (auto *UDE = dyn_cast_or_null<UnresolvedDotExpr>(anchor))
8167+
anchor = findParentExpr(UDE);
8168+
8169+
if (!anchor)
8170+
return false;
8171+
8172+
const auto &solution = getSolution();
8173+
return llvm::any_of(
8174+
solution.OpenedExistentialTypes,
8175+
[&anchor](const auto &openedExistential) {
8176+
if (auto openedLoc = simplifyLocatorToAnchor(openedExistential.first)) {
8177+
return anchor == getAsExpr(openedLoc);
8178+
}
8179+
return false;
8180+
});
8181+
}
8182+
81618183
void MissingExplicitExistentialCoercion::fixIt(
81628184
InFlightDiagnostic &diagnostic) const {
8185+
bool requiresParens = fixItRequiresParens();
8186+
8187+
auto callRange = getSourceRange();
8188+
8189+
if (requiresParens)
8190+
diagnostic.fixItInsert(callRange.Start, "(");
8191+
81638192
auto printOpts = PrintOptions::forDiagnosticArguments();
8164-
diagnostic.fixItInsertAfter(getSourceRange().End,
8165-
"as " + ErasedResultType->getString(printOpts));
8193+
diagnostic.fixItInsertAfter(callRange.End,
8194+
"as " + ErasedResultType->getString(printOpts) +
8195+
(requiresParens ? ")" : ""));
81668196
}

lib/Sema/CSDiagnostics.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,6 +2755,13 @@ class MissingExplicitExistentialCoercion final : public FailureDiagnostic {
27552755

27562756
private:
27572757
void fixIt(InFlightDiagnostic &diagnostic) const;
2758+
2759+
/// Determine whether the fix-it to add `as any ...` requires parens.
2760+
///
2761+
/// Parens are required to avoid suppressing existential opening
2762+
/// if result of the call is passed as an argument to another call
2763+
/// that requires such opening.
2764+
bool fixItRequiresParens() const;
27582765
};
27592766

27602767
} // end namespace constraints

test/Constraints/opened_existentials.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,8 @@ func testExplicitCoercionRequirement(v: any B, otherV: any B & D) {
283283
func getBDSelf<T: D>(_: T) -> T { fatalError() }
284284
_ = getBDSelf(otherV) // expected-error {{inferred result type 'any B & D' requires explicit coercion due to loss of generic requirements}} {{24-24=as any B & D}}
285285
_ = getBDSelf(otherV) as any B & D // Ok
286+
287+
func getP<T: P>(_: T) {}
288+
getP(getC(v)) // expected-error {{inferred result type 'any P' requires explicit coercion due to loss of generic requirements}} {{8-8=(}} {{15-15=as any P)}}
289+
getP(v.getC()) // expected-error {{inferred result type 'any P' requires explicit coercion due to loss of generic requirements}} {{8-8=(}} {{14-14=as any P)}}
286290
}

0 commit comments

Comments
 (0)