[CS] Don't consider implicit TupleExprs in exprNeedsParensOutsideFollowingOperator

Such implicit tuples may be used to represent
argument lists for e.g binary expressions, and as
such shouldn't be considered as parent exprs that
satisfy the role of parentheses.

Also fix the callers to use the raw anchor as the
root expression they pass to provide an accurate
parent map. This requires sinking the
UnresolvedMemberChainResultExpr handling logic into
`getPrecedenceParentAndIndex`.

rdar://81109287
This commit is contained in:
Hamish Knight
2021-07-26 18:17:01 +01:00
parent 41a1761bde
commit 5d1fea24ad
4 changed files with 46 additions and 11 deletions

View File

@@ -7891,6 +7891,15 @@ static std::pair<Expr *, unsigned> getPrecedenceParentAndIndex(Expr *expr,
}
Expr *parent = it->second;
// Look through an unresolved chain wrapper expr, as it has no effect on
// precedence.
if (isa<UnresolvedMemberChainResultExpr>(parent)) {
it = parentMap.find(parent);
if (it == parentMap.end())
return {nullptr, 0};
parent = it->second;
}
// Handle all cases where the answer isn't just going to be { parent, 0 }.
if (auto tuple = dyn_cast<TupleExpr>(parent)) {
// Get index of expression in tuple.
@@ -7970,13 +7979,13 @@ bool swift::exprNeedsParensOutsideFollowingOperator(
Expr *parent;
unsigned index;
std::tie(parent, index) = getPrecedenceParentAndIndex(expr, rootExpr);
if (!parent || isa<TupleExpr>(parent)) {
if (!parent)
return false;
}
if (auto parenExp = dyn_cast<ParenExpr>(parent))
if (!parenExp->isImplicit())
if (isa<ParenExpr>(parent) || isa<TupleExpr>(parent)) {
if (!parent->isImplicit())
return false;
}
if (parent->isInfixOperator()) {
auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC,

View File

@@ -1146,6 +1146,7 @@ ASTNode MissingExplicitConversionFailure::getAnchor() const {
bool MissingExplicitConversionFailure::diagnoseAsError() {
auto *DC = getDC();
auto *anchor = castToExpr(getAnchor());
auto *rawAnchor = castToExpr(getRawAnchor());
auto fromType = getFromType();
auto toType = getToType();
@@ -1171,7 +1172,7 @@ bool MissingExplicitConversionFailure::diagnoseAsError() {
}
bool needsParensInside = exprNeedsParensBeforeAddingAs(anchor);
bool needsParensOutside = exprNeedsParensAfterAddingAs(anchor, expr);
bool needsParensOutside = exprNeedsParensAfterAddingAs(anchor, rawAnchor);
llvm::SmallString<2> insertBefore;
llvm::SmallString<32> insertAfter;
@@ -1310,11 +1311,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt(
// Figure out what we need to parenthesize.
bool needsParensInside =
exprNeedsParensBeforeAddingNilCoalescing(DC, const_cast<Expr *>(expr));
auto parentExpr = findParentExpr(anchor);
if (parentExpr && isa<UnresolvedMemberChainResultExpr>(parentExpr))
parentExpr = findParentExpr(parentExpr);
bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing(
DC, const_cast<Expr *>(expr), parentExpr);
DC, const_cast<Expr *>(expr), castToExpr(getRawAnchor()));
llvm::SmallString<2> insertBefore;
llvm::SmallString<32> insertAfter;

View File

@@ -258,9 +258,9 @@ func rdar19770981(_ s: String, ns: NSString) {
_ = ns as String > s
// 'as' has lower precedence than '+' so add parens with the fixit:
s + ns // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}}{{9-9= as String}}
s + ns // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}} {{7-7=(}} {{9-9= as String)}}
_ = s + (ns as String)
ns + s // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}}{{5-5= as String}}
ns + s // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}} {{3-3=(}} {{5-5= as String)}}
_ = (ns as String) + s
}

View File

@@ -1415,3 +1415,31 @@ func rdar74696023() {
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
}
}
func testUnwrapFixIts(x: Int?) {
let _ = x + 2 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{11-11=(}} {{12-12= ?? <#default value#>)}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{12-12=!}}
let _ = (x ?? 0) + 2
let _ = 2 + x // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{15-15=(}} {{16-16= ?? <#default value#>)}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{16-16=!}}
let _ = 2 + (x ?? 0)
func foo(y: Int) {}
foo(y: x) // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{11-11= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{11-11=!}}
foo(y: x ?? 0)
let _ = x < 2 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{12-12= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{12-12=!}}
let _ = x ?? 0 < 2
let _ = 2 < x // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{16-16= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{16-16=!}}
let _ = 2 < x ?? 0
}