Skip to content

Commit 0bd682e

Browse files
authored
Merge pull request swiftlang#18512 from xedin/refactor-fix-diagnostics-into-class
[ConstraintSystem] Add new FailureDiagnostic abstraction
2 parents 4d35d5e + 7764858 commit 0bd682e

File tree

5 files changed

+357
-115
lines changed

5 files changed

+357
-115
lines changed

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_swift_library(swiftSema STATIC
1111
CSRanking.cpp
1212
CSSimplify.cpp
1313
CSSolver.cpp
14+
CSDiagnostics.cpp
1415
CalleeCandidateInfo.cpp
1516
CodeSynthesis.cpp
1617
Constraint.cpp

lib/Sema/CSApply.cpp

Lines changed: 18 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//===----------------------------------------------------------------------===//
1818

1919
#include "ConstraintSystem.h"
20+
#include "CSDiagnostics.h"
2021
#include "MiscDiagnostics.h"
2122
#include "TypeCheckProtocol.h"
2223
#include "swift/AST/ASTVisitor.h"
@@ -1278,23 +1279,6 @@ namespace {
12781279
ConstraintLocatorBuilder locator);
12791280

12801281
private:
1281-
/// \brief Retrieve the overload choice associated with the given
1282-
/// locator.
1283-
SelectedOverload getOverloadChoice(ConstraintLocator *locator) {
1284-
return *getOverloadChoiceIfAvailable(locator);
1285-
}
1286-
1287-
/// \brief Retrieve the overload choice associated with the given
1288-
/// locator.
1289-
Optional<SelectedOverload>
1290-
getOverloadChoiceIfAvailable(ConstraintLocator *locator) {
1291-
auto known = solution.overloadChoices.find(locator);
1292-
if (known != solution.overloadChoices.end())
1293-
return known->second;
1294-
1295-
return None;
1296-
}
1297-
12981282
/// \brief Simplify the given type by substituting all occurrences of
12991283
/// type variables for their fixed types.
13001284
Type simplifyType(Type type) {
@@ -1395,7 +1379,7 @@ namespace {
13951379

13961380
// Determine the declaration selected for this subscript operation.
13971381
if (!selected)
1398-
selected = getOverloadChoiceIfAvailable(
1382+
selected = solution.getOverloadChoiceIfAvailable(
13991383
cs.getConstraintLocator(
14001384
locator.withPathElement(
14011385
ConstraintLocator::SubscriptMember)));
@@ -2505,7 +2489,7 @@ namespace {
25052489
auto locator = cs.getConstraintLocator(expr);
25062490

25072491
// Find the overload choice used for this declaration reference.
2508-
auto selected = getOverloadChoiceIfAvailable(locator);
2492+
auto selected = solution.getOverloadChoiceIfAvailable(locator);
25092493
if (!selected.hasValue()) {
25102494
auto *varDecl = cast<VarDecl>(expr->getDecl());
25112495
assert(varDecl->getType()->is<UnresolvedType>() &&
@@ -2544,7 +2528,7 @@ namespace {
25442528
Expr *visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *expr) {
25452529
// Determine the declaration selected for this overloaded reference.
25462530
auto locator = cs.getConstraintLocator(expr);
2547-
auto selected = getOverloadChoice(locator);
2531+
auto selected = solution.getOverloadChoice(locator);
25482532
auto choice = selected.choice;
25492533

25502534
return buildDeclRef(choice, expr->getNameLoc(), selected.openedFullType,
@@ -2567,7 +2551,7 @@ namespace {
25672551
Expr *visitMemberRefExpr(MemberRefExpr *expr) {
25682552
auto memberLocator = cs.getConstraintLocator(expr,
25692553
ConstraintLocator::Member);
2570-
auto selected = getOverloadChoice(memberLocator);
2554+
auto selected = solution.getOverloadChoice(memberLocator);
25712555
bool isDynamic
25722556
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
25732557
return buildMemberRef(
@@ -2599,7 +2583,7 @@ namespace {
25992583
// Find the selected member.
26002584
auto memberLocator = cs.getConstraintLocator(
26012585
expr, ConstraintLocator::UnresolvedMember);
2602-
auto selected = getOverloadChoice(memberLocator);
2586+
auto selected = solution.getOverloadChoice(memberLocator);
26032587

26042588
// If the member came by optional unwrapping, then unwrap the base type.
26052589
if (selected.choice.getKind()
@@ -2740,7 +2724,7 @@ namespace {
27402724
auto ctorLocator = cs.getConstraintLocator(
27412725
expr,
27422726
ConstraintLocator::ConstructorMember);
2743-
if (auto selected = getOverloadChoiceIfAvailable(ctorLocator)) {
2727+
if (auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator)) {
27442728
auto choice = selected->choice;
27452729
return applyCtorRefExpr(
27462730
expr, base, dotLoc, nameLoc, implicit, ctorLocator, choice,
@@ -2750,7 +2734,7 @@ namespace {
27502734
// Determine the declaration selected for this overloaded reference.
27512735
auto memberLocator = cs.getConstraintLocator(expr,
27522736
ConstraintLocator::Member);
2753-
auto selectedElt = getOverloadChoiceIfAvailable(memberLocator);
2737+
auto selectedElt = solution.getOverloadChoiceIfAvailable(memberLocator);
27542738

27552739
if (!selectedElt) {
27562740
// If constraint solving resolved this to an UnresolvedType, then we're
@@ -4360,7 +4344,7 @@ namespace {
43604344
// If this is an unresolved link, make sure we resolved it.
43614345
if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty ||
43624346
kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
4363-
foundDecl = getOverloadChoiceIfAvailable(locator);
4347+
foundDecl = solution.getOverloadChoiceIfAvailable(locator);
43644348
// Leave the component unresolved if the overload was not resolved.
43654349
if (foundDecl) {
43664350
// If this was a @dynamicMemberLookup property, then we actually
@@ -7589,7 +7573,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
75897573
auto ctorLocator = cs.getConstraintLocator(
75907574
locator.withPathElement(ConstraintLocator::ApplyFunction)
75917575
.withPathElement(ConstraintLocator::ConstructorMember));
7592-
auto selected = getOverloadChoiceIfAvailable(ctorLocator);
7576+
auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator);
75937577
if (!selected) {
75947578
assert(ty->hasError() || ty->hasUnresolvedType());
75957579
cs.setType(apply, ty);
@@ -8124,99 +8108,18 @@ bool ConstraintSystem::applySolutionFix(
81248108
}
81258109

81268110
case FixKind::RelabelArguments: {
8127-
auto *call = cast<CallExpr>(locator->getAnchor());
8128-
return diagnoseArgumentLabelError(getASTContext(), call->getArg(),
8129-
fix.first.getArgumentLabels(*this),
8130-
isa<SubscriptExpr>(call->getFn()));
8111+
LabelingFailure failure(solution, fix.second,
8112+
fix.first.getArgumentLabels(*this));
8113+
return failure.diagnose();
81318114
}
81328115

81338116
case FixKind::AddConformance: {
8134-
auto getMissingConformance = [&](ConstraintLocator *locator) {
8135-
auto *anchor = locator->getAnchor();
8136-
auto &requirement = locator->getPath().back();
8137-
auto result = MissingConformances.find({anchor, requirement.getValue()});
8138-
assert(result != MissingConformances.end());
8139-
return result->getSecond();
8140-
};
8141-
8142-
auto conformance = getMissingConformance(locator);
8143-
81448117
auto *anchor = locator->getAnchor();
8145-
auto owner = solution.simplifyType(getType(anchor))->getRValueInstanceType();
8146-
8147-
auto type = conformance.first;
8148-
auto protocolType = conformance.second->getDeclaredType();
8149-
8150-
// Find `ApplyExpr` based on a function expression attached to it.
8151-
auto findApplyExpr = [](Expr *parent, Expr *fnExpr) -> ApplyExpr * {
8152-
ApplyExpr *applyExpr = nullptr;
8153-
parent->forEachChildExpr([&applyExpr, &fnExpr](Expr *subExpr) -> Expr * {
8154-
auto *AE = dyn_cast<ApplyExpr>(subExpr);
8155-
if (!AE || AE->getFn() != fnExpr)
8156-
return subExpr;
8157-
8158-
applyExpr = AE;
8159-
return nullptr;
8160-
});
8161-
return applyExpr;
8162-
};
8163-
8164-
auto getArgumentAt = [](ApplyExpr *AE, unsigned index) -> Expr * {
8165-
assert(AE);
8166-
8167-
auto *arg = AE->getArg();
8168-
if (auto *TE = dyn_cast<TupleExpr>(arg))
8169-
return TE->getElement(index);
8170-
8171-
assert(index == 0);
8172-
if (auto *PE = dyn_cast<ParenExpr>(arg))
8173-
return PE->getSubExpr();
8174-
8175-
return arg;
8176-
};
8177-
8178-
auto *applyExpr = findApplyExpr(expr, anchor);
8179-
8180-
Optional<unsigned> atParameterPos;
8181-
// Sometimes fix is recorded by type-checking sub-expression
8182-
// during normal diagnostics, in such case call expression
8183-
// is unavailable.
8184-
if (applyExpr) {
8185-
// If this is a static, initializer or operator call,
8186-
// let's not try to diagnose it here, but refer to expression
8187-
// diagnostics.
8188-
if (isa<BinaryExpr>(applyExpr) || isa<TypeExpr>(anchor))
8189-
return false;
8190-
8191-
if (auto *fnType = owner->getAs<AnyFunctionType>()) {
8192-
auto parameters = fnType->getParams();
8193-
for (auto index : indices(parameters)) {
8194-
if (parameters[index].getType()->isEqual(type)) {
8195-
atParameterPos = index;
8196-
break;
8197-
}
8198-
}
8199-
}
8200-
}
8201-
8202-
if (type->isExistentialType()) {
8203-
auto diagnostic = diag::protocol_does_not_conform_objc;
8204-
if (type->isObjCExistentialType())
8205-
diagnostic = diag::protocol_does_not_conform_static;
8206-
8207-
TC.diagnose(anchor->getLoc(), diagnostic, type, protocolType);
8208-
} else if (atParameterPos) {
8209-
// Requirement comes from one of the parameter types,
8210-
// let's try to point diagnostic to the argument expression.
8211-
auto *argExpr = getArgumentAt(applyExpr, *atParameterPos);
8212-
TC.diagnose(argExpr->getLoc(),
8213-
diag::cannot_convert_argument_value_protocol, type,
8214-
protocolType);
8215-
} else {
8216-
TC.diagnose(anchor->getLoc(), diag::type_does_not_conform_owner, owner,
8217-
type, protocolType);
8218-
}
8219-
return true;
8118+
auto &reqLoc = locator->getPath().back();
8119+
MissingConformanceFailure failure(
8120+
expr, solution, fix.second,
8121+
MissingConformances[{anchor, reqLoc.getValue()}]);
8122+
return failure.diagnose();
82208123
}
82218124
}
82228125

lib/Sema/CSDiagnostics.cpp

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//===--- CSDiagnostics.cpp - Constraint Diagnostics -----------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements diagnostics for constraint system.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "ConstraintSystem.h"
18+
#include "CSDiagnostics.h"
19+
#include "MiscDiagnostics.h"
20+
#include "swift/AST/Expr.h"
21+
#include "swift/AST/Types.h"
22+
#include "llvm/ADT/ArrayRef.h"
23+
24+
using namespace swift;
25+
using namespace constraints;
26+
27+
FailureDiagnostic::~FailureDiagnostic() {}
28+
29+
Type FailureDiagnostic::getType(Expr *expr) const {
30+
auto &cs = getConstraintSystem();
31+
return solution.simplifyType(cs.getType(expr));
32+
}
33+
34+
template <typename... ArgTypes>
35+
InFlightDiagnostic
36+
FailureDiagnostic::emitDiagnostic(ArgTypes &&... Args) const {
37+
auto &cs = getConstraintSystem();
38+
return cs.TC.diagnose(std::forward<ArgTypes>(Args)...);
39+
}
40+
41+
Type RequirementFailure::getOwnerType() const {
42+
return getType(getAnchor())->getRValueInstanceType();
43+
}
44+
45+
const Requirement &RequirementFailure::getRequirement() {
46+
auto *genericCtx = AffectedDecl->getAsGenericContext();
47+
return genericCtx->getGenericRequirements()[getRequirementIndex()];
48+
}
49+
50+
ValueDecl *RequirementFailure::getDeclRef() const {
51+
auto &cs = getConstraintSystem();
52+
53+
auto *anchor = getAnchor();
54+
auto *locator = cs.getConstraintLocator(anchor);
55+
if (auto *AE = dyn_cast<CallExpr>(anchor)) {
56+
assert(isa<TypeExpr>(AE->getFn()));
57+
ConstraintLocatorBuilder ctor(locator);
58+
locator = cs.getConstraintLocator(
59+
ctor.withPathElement(PathEltKind::ApplyFunction)
60+
.withPathElement(PathEltKind::ConstructorMember));
61+
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
62+
ConstraintLocatorBuilder member(locator);
63+
locator =
64+
cs.getConstraintLocator(member.withPathElement(PathEltKind::Member));
65+
}
66+
67+
auto overload = getOverloadChoiceIfAvailable(locator);
68+
if (overload)
69+
return overload->choice.getDecl();
70+
71+
auto ownerType = getOwnerType();
72+
if (auto *NA = dyn_cast<NameAliasType>(ownerType.getPointer()))
73+
return NA->getDecl();
74+
75+
return ownerType->getAnyGeneric();
76+
}
77+
78+
bool MissingConformanceFailure::diagnose() {
79+
auto *anchor = getAnchor();
80+
auto ownerType = getOwnerType();
81+
auto type = getNonConformingType();
82+
auto protocolType = getProtocolType();
83+
84+
// Find `ApplyExpr` based on a function expression attached to it.
85+
auto findApplyExpr = [](Expr *parent, Expr *fnExpr) -> ApplyExpr * {
86+
ApplyExpr *applyExpr = nullptr;
87+
parent->forEachChildExpr([&applyExpr, &fnExpr](Expr *subExpr) -> Expr * {
88+
auto *AE = dyn_cast<ApplyExpr>(subExpr);
89+
if (!AE || AE->getFn() != fnExpr)
90+
return subExpr;
91+
92+
applyExpr = AE;
93+
return nullptr;
94+
});
95+
return applyExpr;
96+
};
97+
98+
auto getArgumentAt = [](ApplyExpr *AE, unsigned index) -> Expr * {
99+
assert(AE);
100+
101+
auto *arg = AE->getArg();
102+
if (auto *TE = dyn_cast<TupleExpr>(arg))
103+
return TE->getElement(index);
104+
105+
assert(index == 0);
106+
if (auto *PE = dyn_cast<ParenExpr>(arg))
107+
return PE->getSubExpr();
108+
109+
return arg;
110+
};
111+
112+
auto *applyExpr = findApplyExpr(getParentExpr(), anchor);
113+
114+
Optional<unsigned> atParameterPos;
115+
// Sometimes fix is recorded by type-checking sub-expression
116+
// during normal diagnostics, in such case call expression
117+
// is unavailable.
118+
if (applyExpr) {
119+
// If this is a static, initializer or operator call,
120+
// let's not try to diagnose it here, but refer to expression
121+
// diagnostics.
122+
if (isa<BinaryExpr>(applyExpr) || isa<TypeExpr>(anchor))
123+
return false;
124+
125+
if (auto *fnType = ownerType->getAs<AnyFunctionType>()) {
126+
auto parameters = fnType->getParams();
127+
for (auto index : indices(parameters)) {
128+
if (parameters[index].getType()->isEqual(type)) {
129+
atParameterPos = index;
130+
break;
131+
}
132+
}
133+
}
134+
}
135+
136+
if (type->isExistentialType()) {
137+
auto diagnostic = diag::protocol_does_not_conform_objc;
138+
if (type->isObjCExistentialType())
139+
diagnostic = diag::protocol_does_not_conform_static;
140+
141+
emitDiagnostic(anchor->getLoc(), diagnostic, type, protocolType);
142+
} else if (atParameterPos) {
143+
// Requirement comes from one of the parameter types,
144+
// let's try to point diagnostic to the argument expression.
145+
auto *argExpr = getArgumentAt(applyExpr, *atParameterPos);
146+
emitDiagnostic(argExpr->getLoc(),
147+
diag::cannot_convert_argument_value_protocol, type,
148+
protocolType);
149+
} else {
150+
emitDiagnostic(anchor->getLoc(), diag::type_does_not_conform_owner,
151+
ownerType, type, protocolType);
152+
}
153+
return true;
154+
}
155+
156+
bool LabelingFailure::diagnose() {
157+
auto &cs = getConstraintSystem();
158+
auto *call = cast<CallExpr>(getAnchor());
159+
return diagnoseArgumentLabelError(cs.getASTContext(), call->getArg(),
160+
CorrectLabels,
161+
isa<SubscriptExpr>(call->getFn()));
162+
}

0 commit comments

Comments
 (0)