Skip to content

Commit caae8d6

Browse files
authored
Merge pull request #38748 from hamishknight/a-better-precedent
2 parents d6c9bd3 + 21e8a32 commit caae8d6

File tree

5 files changed

+83
-46
lines changed

5 files changed

+83
-46
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5773,9 +5773,9 @@ bool exprNeedsParensBeforeAddingNilCoalescing(DeclContext *DC,
57735773
// Return true if, when replacing "<expr>" with "<expr> as T", parentheses need
57745774
// to be added around the new expression in order to maintain the correct
57755775
// precedence.
5776-
bool exprNeedsParensAfterAddingNilCoalescing(DeclContext *DC,
5777-
Expr *expr,
5778-
Expr *rootExpr);
5776+
bool exprNeedsParensAfterAddingNilCoalescing(
5777+
DeclContext *DC, Expr *expr,
5778+
llvm::function_ref<Expr *(const Expr *)> getParent);
57795779

57805780
/// Return true if, when replacing "<expr>" with "<expr> op <something>",
57815781
/// parentheses must be added around "<expr>" to allow the new operator
@@ -5784,13 +5784,12 @@ bool exprNeedsParensInsideFollowingOperator(DeclContext *DC,
57845784
Expr *expr,
57855785
PrecedenceGroupDecl *followingPG);
57865786

5787-
/// Return true if, when replacing "<expr>" with "<expr> op <something>"
5788-
/// within the given root expression, parentheses must be added around
5789-
/// the new operator to prevent it from binding incorrectly in the
5790-
/// surrounding context.
5787+
/// Return true if, when replacing "<expr>" with "<expr> op <something>",
5788+
/// parentheses must be added around the new operator to prevent it from binding
5789+
/// incorrectly in the surrounding context.
57915790
bool exprNeedsParensOutsideFollowingOperator(
5792-
DeclContext *DC, Expr *expr, Expr *rootExpr,
5793-
PrecedenceGroupDecl *followingPG);
5791+
DeclContext *DC, Expr *expr, PrecedenceGroupDecl *followingPG,
5792+
llvm::function_ref<Expr *(const Expr *)> getParent);
57945793

57955794
/// Determine whether this is a SIMD operator.
57965795
bool isSIMDOperator(ValueDecl *value);

lib/Sema/CSApply.cpp

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7908,23 +7908,21 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
79087908
// nearest ancestor of 'expr' which imposes a minimum precedence on 'expr'.
79097909
// Right now that just means skipping over TupleExpr instances that only exist
79107910
// to hold arguments to binary operators.
7911-
static std::pair<Expr *, unsigned> getPrecedenceParentAndIndex(Expr *expr,
7912-
Expr *rootExpr)
7913-
{
7914-
auto parentMap = rootExpr->getParentMap();
7915-
auto it = parentMap.find(expr);
7916-
if (it == parentMap.end()) {
7911+
static std::pair<Expr *, unsigned> getPrecedenceParentAndIndex(
7912+
Expr *expr, llvm::function_ref<Expr *(const Expr *)> getParent) {
7913+
auto *parent = getParent(expr);
7914+
if (!parent)
79177915
return { nullptr, 0 };
7918-
}
7919-
Expr *parent = it->second;
7920-
7921-
// Look through an unresolved chain wrapper expr, as it has no effect on
7922-
// precedence.
7923-
if (isa<UnresolvedMemberChainResultExpr>(parent)) {
7924-
it = parentMap.find(parent);
7925-
if (it == parentMap.end())
7926-
return {nullptr, 0};
7927-
parent = it->second;
7916+
7917+
// Look through an unresolved chain wrappers, try, and await exprs, as they
7918+
// have no effect on precedence; they will associate the same with any parent
7919+
// operator as their sub-expression would.
7920+
while (isa<UnresolvedMemberChainResultExpr>(parent) ||
7921+
isa<AnyTryExpr>(parent) || isa<AwaitExpr>(parent)) {
7922+
expr = parent;
7923+
parent = getParent(parent);
7924+
if (!parent)
7925+
return { nullptr, 0 };
79287926
}
79297927

79307928
// Handle all cases where the answer isn't just going to be { parent, 0 }.
@@ -7935,18 +7933,14 @@ static std::pair<Expr *, unsigned> getPrecedenceParentAndIndex(Expr *expr,
79357933
assert(elemIt != tupleElems.end() && "expr not found in parent TupleExpr");
79367934
unsigned index = elemIt - tupleElems.begin();
79377935

7938-
it = parentMap.find(parent);
7939-
if (it != parentMap.end()) {
7940-
Expr *gparent = it->second;
7941-
7942-
// Was this tuple just constructed for a binop?
7943-
if (isa<BinaryExpr>(gparent)) {
7936+
// Was this tuple just constructed for a binop?
7937+
if (auto *gparent = getParent(tuple)) {
7938+
if (isa<BinaryExpr>(gparent))
79447939
return { gparent, index };
7945-
}
79467940
}
79477941

79487942
// Must be a tuple literal, function arg list, collection, etc.
7949-
return { parent, index };
7943+
return { tuple, index };
79507944
} else if (auto ifExpr = dyn_cast<IfExpr>(parent)) {
79517945
unsigned index;
79527946
if (expr == ifExpr->getCondExpr()) {
@@ -8001,11 +7995,11 @@ bool swift::exprNeedsParensInsideFollowingOperator(
80017995
/// the new operator to prevent it from binding incorrectly in the
80027996
/// surrounding context.
80037997
bool swift::exprNeedsParensOutsideFollowingOperator(
8004-
DeclContext *DC, Expr *expr, Expr *rootExpr,
8005-
PrecedenceGroupDecl *followingPG) {
7998+
DeclContext *DC, Expr *expr, PrecedenceGroupDecl *followingPG,
7999+
llvm::function_ref<Expr *(const Expr *)> getParent) {
80068000
Expr *parent;
80078001
unsigned index;
8008-
std::tie(parent, index) = getPrecedenceParentAndIndex(expr, rootExpr);
8002+
std::tie(parent, index) = getPrecedenceParentAndIndex(expr, getParent);
80098003
if (!parent)
80108004
return false;
80118005

@@ -8014,6 +8008,9 @@ bool swift::exprNeedsParensOutsideFollowingOperator(
80148008
return false;
80158009
}
80168010

8011+
if (isa<ClosureExpr>(parent) || isa<CollectionExpr>(parent))
8012+
return false;
8013+
80178014
if (parent->isInfixOperator()) {
80188015
auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC,
80198016
parent);
@@ -8044,16 +8041,16 @@ bool swift::exprNeedsParensBeforeAddingNilCoalescing(DeclContext *DC,
80448041
return exprNeedsParensInsideFollowingOperator(DC, expr, asPG);
80458042
}
80468043

8047-
bool swift::exprNeedsParensAfterAddingNilCoalescing(DeclContext *DC,
8048-
Expr *expr,
8049-
Expr *rootExpr) {
8044+
bool swift::exprNeedsParensAfterAddingNilCoalescing(
8045+
DeclContext *DC, Expr *expr,
8046+
llvm::function_ref<Expr *(const Expr *)> getParent) {
80508047
auto &ctx = DC->getASTContext();
80518048
auto asPG = TypeChecker::lookupPrecedenceGroup(
80528049
DC, ctx.Id_NilCoalescingPrecedence, SourceLoc())
80538050
.getSingle();
80548051
if (!asPG)
80558052
return true;
8056-
return exprNeedsParensOutsideFollowingOperator(DC, expr, rootExpr, asPG);
8053+
return exprNeedsParensOutsideFollowingOperator(DC, expr, asPG, getParent);
80578054
}
80588055

80598056
namespace {

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,6 @@ ASTNode MissingExplicitConversionFailure::getAnchor() const {
11581158
bool MissingExplicitConversionFailure::diagnoseAsError() {
11591159
auto *DC = getDC();
11601160
auto *anchor = castToExpr(getAnchor());
1161-
auto *rawAnchor = castToExpr(getRawAnchor());
11621161

11631162
auto fromType = getFromType();
11641163
auto toType = getToType();
@@ -1184,7 +1183,7 @@ bool MissingExplicitConversionFailure::diagnoseAsError() {
11841183
}
11851184

11861185
bool needsParensInside = exprNeedsParensBeforeAddingAs(anchor);
1187-
bool needsParensOutside = exprNeedsParensAfterAddingAs(anchor, rawAnchor);
1186+
bool needsParensOutside = exprNeedsParensAfterAddingAs(anchor);
11881187

11891188
llvm::SmallString<2> insertBefore;
11901189
llvm::SmallString<32> insertAfter;
@@ -1324,7 +1323,7 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt(
13241323
bool needsParensInside =
13251324
exprNeedsParensBeforeAddingNilCoalescing(DC, const_cast<Expr *>(expr));
13261325
bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing(
1327-
DC, const_cast<Expr *>(expr), castToExpr(getRawAnchor()));
1326+
DC, const_cast<Expr *>(expr), [&](auto *E) { return findParentExpr(E); });
13281327

13291328
llvm::SmallString<2> insertBefore;
13301329
llvm::SmallString<32> insertAfter;

lib/Sema/CSDiagnostics.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,15 +903,16 @@ class MissingExplicitConversionFailure final : public ContextualFailure {
903903
asPG);
904904
}
905905

906-
bool exprNeedsParensAfterAddingAs(const Expr *expr, const Expr *rootExpr) {
906+
bool exprNeedsParensAfterAddingAs(const Expr *expr) {
907907
auto *DC = getDC();
908908
auto asPG = TypeChecker::lookupPrecedenceGroup(
909909
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc()).getSingle();
910910
if (!asPG)
911911
return true;
912912

913913
return exprNeedsParensOutsideFollowingOperator(
914-
DC, const_cast<Expr *>(expr), const_cast<Expr *>(rootExpr), asPG);
914+
DC, const_cast<Expr *>(expr), asPG,
915+
[&](auto *E) { return findParentExpr(E); });
915916
}
916917
};
917918

test/Constraints/diagnostics.swift

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1416,7 +1416,12 @@ func rdar74696023() {
14161416
}
14171417
}
14181418

1419-
func testUnwrapFixIts(x: Int?) {
1419+
extension Int {
1420+
static var optionalIntMember: Int? { 0 }
1421+
static var optionalThrowsMember: Int? { get throws { 0 } }
1422+
}
1423+
1424+
func testUnwrapFixIts(x: Int?) throws {
14201425
let _ = x + 2 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
14211426
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{11-11=(}} {{12-12= ?? <#default value#>)}}
14221427
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{12-12=!}}
@@ -1442,4 +1447,40 @@ func testUnwrapFixIts(x: Int?) {
14421447
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{16-16= ?? <#default value#>}}
14431448
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{16-16=!}}
14441449
let _ = 2 < x ?? 0
1450+
1451+
let _: Int = (.optionalIntMember) // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1452+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}}
1453+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}}
1454+
let _: Int = (.optionalIntMember ?? 0)
1455+
1456+
let _ = 1 + .optionalIntMember // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1457+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{15-15=(}} {{33-33= ?? <#default value#>)}}
1458+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{33-33=!}}
1459+
let _ = 1 + (.optionalIntMember ?? 0)
1460+
1461+
let _ = try .optionalThrowsMember + 1 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1462+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{15-15=(}} {{36-36= ?? <#default value#>)}}
1463+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{36-36=!}}
1464+
let _ = try (.optionalThrowsMember ?? 0) + 1
1465+
1466+
let _ = .optionalIntMember?.bitWidth > 0 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1467+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{39-39= ?? <#default value#>}}
1468+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{11-11=(}} {{39-39=)!}}
1469+
let _ = (.optionalIntMember?.bitWidth)! > 0
1470+
let _ = .optionalIntMember?.bitWidth ?? 0 > 0
1471+
1472+
let _ = .random() ? .optionalIntMember : 0 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1473+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{41-41= ?? <#default value#>}}
1474+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{41-41=!}}
1475+
let _ = .random() ? .optionalIntMember ?? 0 : 0
1476+
1477+
let _: Int = try try try .optionalThrowsMember // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1478+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}}
1479+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}}
1480+
let _: Int = try try try .optionalThrowsMember ?? 0
1481+
1482+
let _: Int = try! .optionalThrowsMember // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
1483+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{42-42= ?? <#default value#>}}
1484+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{42-42=!}}
1485+
let _: Int = try! .optionalThrowsMember ?? 0
14451486
}

0 commit comments

Comments
 (0)