Skip to content

Commit fcd0a6d

Browse files
authored
Merge pull request #24644 from xedin/assorted-diagnostics-imporovements-5.1
[5.1][Diagnostics] Assorted diagnostics imporovements
2 parents 17f2bda + b3db3e4 commit fcd0a6d

File tree

11 files changed

+230
-32
lines changed

11 files changed

+230
-32
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ namespace swift {
8888
class UnboundGenericType;
8989
class ValueDecl;
9090
class VarDecl;
91+
class OpaqueReturnTypeRepr;
9192

9293
enum class DeclKind : uint8_t {
9394
#define DECL(Id, Parent) Id,
@@ -2677,7 +2678,10 @@ class ValueDecl : public Decl {
26772678

26782679
/// Get the decl for this value's opaque result type, if it has one.
26792680
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;
2680-
2681+
2682+
/// Get the representative for this value's opaque result type, if it has one.
2683+
OpaqueReturnTypeRepr *getOpaqueResultTypeRepr() const;
2684+
26812685
/// Set the opaque return type decl for this decl.
26822686
///
26832687
/// `this` must be of a decl type that supports opaque return types, and

lib/AST/Decl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,6 +2381,19 @@ void ValueDecl::setOverriddenDecls(ArrayRef<ValueDecl *> overridden) {
23812381
request.cacheResult(overriddenVec);
23822382
}
23832383

2384+
OpaqueReturnTypeRepr *ValueDecl::getOpaqueResultTypeRepr() const {
2385+
TypeLoc returnLoc;
2386+
if (auto *VD = dyn_cast<VarDecl>(this)) {
2387+
returnLoc = VD->getTypeLoc();
2388+
} else if (auto *FD = dyn_cast<FuncDecl>(this)) {
2389+
returnLoc = FD->getBodyResultTypeLoc();
2390+
} else if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
2391+
returnLoc = SD->getElementTypeLoc();
2392+
}
2393+
2394+
return dyn_cast_or_null<OpaqueReturnTypeRepr>(returnLoc.getTypeRepr());
2395+
}
2396+
23842397
OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const {
23852398
if (auto func = dyn_cast<FuncDecl>(this)) {
23862399
return func->getOpaqueResultTypeDecl();

lib/Sema/CSDiagnostics.cpp

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,9 @@ bool RequirementFailure::diagnoseAsError() {
278278
anchor->getLoc(), diag::type_does_not_conform_in_opaque_return,
279279
namingDecl->getDescriptiveKind(), namingDecl->getFullName(), lhs, rhs);
280280

281-
TypeLoc returnLoc;
282-
if (auto *VD = dyn_cast<VarDecl>(namingDecl)) {
283-
returnLoc = VD->getTypeLoc();
284-
} else if (auto *FD = dyn_cast<FuncDecl>(namingDecl)) {
285-
returnLoc = FD->getBodyResultTypeLoc();
286-
} else if (auto *SD = dyn_cast<SubscriptDecl>(namingDecl)) {
287-
returnLoc = SD->getElementTypeLoc();
288-
}
289-
290-
if (returnLoc.hasLocation()) {
291-
emitDiagnostic(returnLoc.getLoc(), diag::opaque_return_type_declared_here)
292-
.highlight(returnLoc.getSourceRange());
281+
if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) {
282+
emitDiagnostic(repr->getLoc(), diag::opaque_return_type_declared_here)
283+
.highlight(repr->getSourceRange());
293284
}
294285
return true;
295286
}
@@ -1697,6 +1688,33 @@ bool MissingCallFailure::diagnoseAsError() {
16971688
if (isa<KeyPathExpr>(baseExpr))
16981689
return false;
16991690

1691+
auto path = getLocator()->getPath();
1692+
if (!path.empty()) {
1693+
const auto &last = path.back();
1694+
1695+
switch (last.getKind()) {
1696+
case ConstraintLocator::ContextualType:
1697+
case ConstraintLocator::ApplyArgToParam: {
1698+
auto fnType = getType(baseExpr)->castTo<FunctionType>();
1699+
assert(fnType->getNumParams() == 0);
1700+
emitDiagnostic(baseExpr->getLoc(), diag::missing_nullary_call,
1701+
fnType->getResult())
1702+
.fixItInsertAfter(baseExpr->getEndLoc(), "()");
1703+
return true;
1704+
}
1705+
1706+
case ConstraintLocator::AutoclosureResult: {
1707+
auto &cs = getConstraintSystem();
1708+
auto loc = cs.getConstraintLocator(getRawAnchor(), path.drop_back(),
1709+
/*summaryFlags=*/0);
1710+
AutoClosureForwardingFailure failure(cs, loc);
1711+
return failure.diagnoseAsError();
1712+
}
1713+
default:
1714+
break;
1715+
}
1716+
}
1717+
17001718
if (auto *DRE = dyn_cast<DeclRefExpr>(baseExpr)) {
17011719
emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_function,
17021720
DRE->getDecl()->getBaseName().getIdentifier())
@@ -2679,3 +2697,15 @@ bool InvalidMethodRefInKeyPath::diagnoseAsError() {
26792697
getName(), isForKeyPathDynamicMemberLookup());
26802698
return true;
26812699
}
2700+
2701+
bool InvalidUseOfAddressOf::diagnoseAsError() {
2702+
auto *anchor = cast<AssignExpr>(getAnchor());
2703+
emitDiagnostic(anchor->getSrc()->getLoc(), diag::extraneous_address_of);
2704+
return true;
2705+
}
2706+
2707+
bool ExtraneousReturnFailure::diagnoseAsError() {
2708+
auto *anchor = getAnchor();
2709+
emitDiagnostic(anchor->getLoc(), diag::cannot_return_value_from_void_func);
2710+
return true;
2711+
}

lib/Sema/CSDiagnostics.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,41 @@ class InvalidMethodRefInKeyPath final : public InvalidMemberRefInKeyPath {
11381138
bool diagnoseAsError() override;
11391139
};
11401140

1141+
/// Diagnose extraneous use of address of (`&`) which could only be
1142+
/// associated with arguments to inout parameters e.g.
1143+
///
1144+
/// ```swift
1145+
/// struct S {}
1146+
///
1147+
/// var a: S = ...
1148+
/// var b: S = ...
1149+
///
1150+
/// a = &b
1151+
/// ```
1152+
class InvalidUseOfAddressOf final : public FailureDiagnostic {
1153+
public:
1154+
InvalidUseOfAddressOf(Expr *root, ConstraintSystem &cs,
1155+
ConstraintLocator *locator)
1156+
: FailureDiagnostic(root, cs, locator) {}
1157+
1158+
bool diagnoseAsError() override;
1159+
};
1160+
1161+
/// Diagnose an attempt return something from a function which
1162+
/// doesn't have a return type specified e.g.
1163+
///
1164+
/// ```swift
1165+
/// func foo() { return 42 }
1166+
/// ```
1167+
class ExtraneousReturnFailure final : public FailureDiagnostic {
1168+
public:
1169+
ExtraneousReturnFailure(Expr *root, ConstraintSystem &cs,
1170+
ConstraintLocator *locator)
1171+
: FailureDiagnostic(root, cs, locator) {}
1172+
1173+
bool diagnoseAsError() override;
1174+
};
1175+
11411176
} // end namespace constraints
11421177
} // end namespace swift
11431178

lib/Sema/CSFix.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,3 +484,23 @@ KeyPathContextualMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs,
484484
return new (cs.getAllocator())
485485
KeyPathContextualMismatch(cs, lhs, rhs, locator);
486486
}
487+
488+
bool RemoveAddressOf::diagnose(Expr *root, bool asNote) const {
489+
InvalidUseOfAddressOf failure(root, getConstraintSystem(), getLocator());
490+
return failure.diagnose(asNote);
491+
}
492+
493+
RemoveAddressOf *RemoveAddressOf::create(ConstraintSystem &cs,
494+
ConstraintLocator *locator) {
495+
return new (cs.getAllocator()) RemoveAddressOf(cs, locator);
496+
}
497+
498+
bool RemoveReturn::diagnose(Expr *root, bool asNote) const {
499+
ExtraneousReturnFailure failure(root, getConstraintSystem(), getLocator());
500+
return failure.diagnose(asNote);
501+
}
502+
503+
RemoveReturn *RemoveReturn::create(ConstraintSystem &cs,
504+
ConstraintLocator *locator) {
505+
return new (cs.getAllocator()) RemoveReturn(cs, locator);
506+
}

lib/Sema/CSFix.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ enum class FixKind : uint8_t {
5757

5858
/// Introduce a '&' to take the address of an lvalue.
5959
AddressOf,
60+
/// Remove extraneous use of `&`.
61+
RemoveAddressOf,
6062

6163
/// Replace a coercion ('as') with a forced checked cast ('as!').
6264
CoerceToCheckedCast,
@@ -147,6 +149,10 @@ enum class FixKind : uint8_t {
147149
/// Allow an invalid reference to a member declaration as part
148150
/// of a key path component.
149151
AllowInvalidRefInKeyPath,
152+
153+
/// Remove `return` or default last expression of single expression
154+
/// function to `Void` to conform to expected result type.
155+
RemoveReturn,
150156
};
151157

152158
class ConstraintFix {
@@ -853,6 +859,33 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
853859
ConstraintLocator *locator);
854860
};
855861

862+
class RemoveAddressOf final : public ConstraintFix {
863+
RemoveAddressOf(ConstraintSystem &cs, ConstraintLocator *locator)
864+
: ConstraintFix(cs, FixKind::RemoveAddressOf, locator) {}
865+
866+
public:
867+
std::string getName() const override {
868+
return "remove extraneous use of `&`";
869+
}
870+
871+
bool diagnose(Expr *root, bool asNote = false) const override;
872+
873+
static RemoveAddressOf *create(ConstraintSystem &cs,
874+
ConstraintLocator *locator);
875+
};
876+
877+
class RemoveReturn final : public ConstraintFix {
878+
RemoveReturn(ConstraintSystem &cs, ConstraintLocator *locator)
879+
: ConstraintFix(cs, FixKind::RemoveReturn, locator) {}
880+
881+
public:
882+
std::string getName() const override { return "remove or omit return type"; }
883+
884+
bool diagnose(Expr *root, bool asNote = false) const override;
885+
886+
static RemoveReturn *create(ConstraintSystem &cs, ConstraintLocator *locator);
887+
};
888+
856889
} // end namespace constraints
857890
} // end namespace swift
858891

lib/Sema/CSSimplify.cpp

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,51 @@ bool ConstraintSystem::repairFailures(
19781978
SmallVector<LocatorPathElt, 4> path;
19791979
auto *anchor = locator.getLocatorParts(path);
19801980

1981+
// If there is a missing explicit call it could be:
1982+
//
1983+
// a). Contextual e.g. `let _: R = foo`
1984+
// b). Argument is a function value passed to parameter
1985+
// which expects its result type e.g. `foo(bar)`
1986+
// c). Assigment destination type matches return type of
1987+
// of the function value e.g. `foo = bar` or `foo = .bar`
1988+
auto repairByInsertingExplicitCall = [&](Type srcType, Type dstType) -> bool {
1989+
auto fnType = srcType->getAs<FunctionType>();
1990+
if (!fnType || fnType->getNumParams() > 0)
1991+
return false;
1992+
1993+
auto resultType = fnType->getResult();
1994+
// If this is situation like `x = { ... }` where closure results in
1995+
// `Void`, let's not suggest to call the closure, because it's most
1996+
// likely not intended.
1997+
if (anchor && isa<AssignExpr>(anchor)) {
1998+
auto *assignment = cast<AssignExpr>(anchor);
1999+
if (isa<ClosureExpr>(assignment->getSrc()) && resultType->isVoid())
2000+
return false;
2001+
}
2002+
2003+
// If left-hand side is a function type but right-hand
2004+
// side isn't, let's check it would be possible to fix
2005+
// this by forming an explicit call.
2006+
auto convertTo = dstType->lookThroughAllOptionalTypes();
2007+
// Right-hand side can't be - a function, a type variable or dependent
2008+
// member, or `Any` (if function conversion to `Any` didn't succeed there
2009+
// is something else going on e.g. problem with escapiness).
2010+
if (convertTo->is<FunctionType>() || convertTo->isTypeVariableOrMember() ||
2011+
convertTo->isAny())
2012+
return false;
2013+
2014+
auto result = matchTypes(resultType, dstType, ConstraintKind::Conversion,
2015+
TypeMatchFlags::TMF_ApplyingFix, locator);
2016+
2017+
if (result.isSuccess()) {
2018+
conversionsOrFixes.push_back(
2019+
InsertExplicitCall::create(*this, getConstraintLocator(locator)));
2020+
return true;
2021+
}
2022+
2023+
return false;
2024+
};
2025+
19812026
if (path.empty()) {
19822027
if (!anchor)
19832028
return false;
@@ -1993,21 +2038,14 @@ bool ConstraintSystem::repairFailures(
19932038
return true;
19942039
}
19952040

1996-
if (isa<AssignExpr>(anchor)) {
1997-
if (auto *fnType = lhs->getAs<FunctionType>()) {
1998-
// If left-hand side is a function type but right-hand
1999-
// side isn't, let's check it would be possible to fix
2000-
// this by forming an explicit call.
2001-
auto convertTo = rhs->lookThroughAllOptionalTypes();
2002-
if (!convertTo->is<FunctionType>() && !convertTo->isVoid() &&
2003-
fnType->getNumParams() == 0 &&
2004-
matchTypes(fnType->getResult(), rhs, ConstraintKind::Conversion,
2005-
TypeMatchFlags::TMF_ApplyingFix, locator)
2006-
.isSuccess()) {
2007-
conversionsOrFixes.push_back(
2008-
InsertExplicitCall::create(*this, getConstraintLocator(locator)));
2009-
return true;
2010-
}
2041+
if (auto *AE = dyn_cast<AssignExpr>(anchor)) {
2042+
if (repairByInsertingExplicitCall(lhs, rhs))
2043+
return true;
2044+
2045+
if (isa<InOutExpr>(AE->getSrc())) {
2046+
conversionsOrFixes.push_back(
2047+
RemoveAddressOf::create(*this, getConstraintLocator(locator)));
2048+
return true;
20112049
}
20122050
}
20132051

@@ -2018,6 +2056,9 @@ bool ConstraintSystem::repairFailures(
20182056
switch (elt.getKind()) {
20192057
case ConstraintLocator::LValueConversion:
20202058
case ConstraintLocator::ApplyArgToParam: {
2059+
if (repairByInsertingExplicitCall(lhs, rhs))
2060+
return true;
2061+
20212062
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
20222063
conversionsOrFixes.push_back(
20232064
ForceOptional::create(*this, lhs, lhs->getOptionalObjectType(),
@@ -2081,6 +2122,17 @@ bool ConstraintSystem::repairFailures(
20812122
}
20822123

20832124
case ConstraintLocator::ContextualType: {
2125+
auto purpose = getContextualTypePurpose();
2126+
if (rhs->isVoid() &&
2127+
(purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr)) {
2128+
conversionsOrFixes.push_back(
2129+
RemoveReturn::create(*this, getConstraintLocator(locator)));
2130+
return true;
2131+
}
2132+
2133+
if (repairByInsertingExplicitCall(lhs, rhs))
2134+
return true;
2135+
20842136
// If both types are key path, the only differences
20852137
// between them are mutability and/or root, value type mismatch.
20862138
if (isKnownKeyPathType(lhs) && isKnownKeyPathType(rhs)) {
@@ -2098,6 +2150,12 @@ bool ConstraintSystem::repairFailures(
20982150
break;
20992151
}
21002152

2153+
case ConstraintLocator::AutoclosureResult: {
2154+
if (repairByInsertingExplicitCall(lhs, rhs))
2155+
return true;
2156+
break;
2157+
}
2158+
21012159
default:
21022160
break;
21032161
}
@@ -6476,6 +6534,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
64766534
}
64776535

64786536
case FixKind::InsertCall:
6537+
case FixKind::RemoveReturn:
6538+
case FixKind::RemoveAddressOf:
64796539
case FixKind::SkipSameTypeRequirement:
64806540
case FixKind::SkipSuperclassRequirement:
64816541
case FixKind::ContextualMismatch:

test/Constraints/closures.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func inoutToSharedConversions() {
5555
// Autoclosure
5656
func f1(f: @autoclosure () -> Int) { }
5757
func f2() -> Int { }
58-
f1(f: f2) // expected-error{{function produces expected type 'Int'; did you mean to call it with '()'?}}{{9-9=()}}
58+
f1(f: f2) // expected-error{{add () to forward @autoclosure parameter}}{{9-9=()}}
5959
f1(f: 5)
6060

6161
// Ternary in closure
@@ -268,7 +268,7 @@ func someFunc(_ foo: ((String) -> String)?,
268268

269269
func verify_NotAC_to_AC_failure(_ arg: () -> ()) {
270270
func takesAC(_ arg: @autoclosure () -> ()) {}
271-
takesAC(arg) // expected-error {{function produces expected type '()'; did you mean to call it with '()'?}}
271+
takesAC(arg) // expected-error {{add () to forward @autoclosure parameter}} {{14-14=()}}
272272
}
273273

274274
// SR-1069 - Error diagnostic refers to wrong argument

test/Constraints/fixes.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func forgotCall() {
3939
// With overloading: only one succeeds.
4040
a = createB // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}
4141

42+
let _: A = createB // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}} {{21-21=()}}
43+
let _: B = createB // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}} {{21-21=()}}
44+
4245
// With overloading, pick the fewest number of fixes.
4346
var b = f7(f4, f1) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}
4447
b.iAmAB()

0 commit comments

Comments
 (0)