Skip to content

Commit ef2f24b

Browse files
committed
[ConstraintSystem] Save "too complex" source range if known
This would help to diagnose the initial point where constraint system has been determine to be "too complex"
1 parent 7dab90c commit ef2f24b

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ class ExpressionTimer {
194194

195195
AnchorType getAnchor() const { return Anchor; }
196196

197+
SourceRange getAffectedRange() const;
198+
197199
unsigned getWarnLimit() const {
198200
return Context.TypeCheckerOpts.WarnLongExpressionTypeChecking;
199201
}
@@ -5415,9 +5417,17 @@ class ConstraintSystem {
54155417

54165418
/// Determine if we've already explored too many paths in an
54175419
/// attempt to solve this expression.
5418-
bool isAlreadyTooComplex = false;
5420+
std::pair<bool, SourceRange> isAlreadyTooComplex = {false, SourceRange()};
5421+
5422+
/// If optional is not nil, result is guaranteed to point at a valid
5423+
/// location.
5424+
Optional<SourceRange> getTooComplexRange() const {
5425+
auto range = isAlreadyTooComplex.second;
5426+
return range.isValid() ? range : Optional<SourceRange>();
5427+
}
5428+
54195429
bool isTooComplex(size_t solutionMemory) {
5420-
if (isAlreadyTooComplex)
5430+
if (isAlreadyTooComplex.first)
54215431
return true;
54225432

54235433
auto CancellationFlag = getASTContext().CancellationFlag;
@@ -5428,7 +5438,9 @@ class ConstraintSystem {
54285438
MaxMemory = std::max(used, MaxMemory);
54295439
auto threshold = getASTContext().TypeCheckerOpts.SolverMemoryThreshold;
54305440
if (MaxMemory > threshold) {
5431-
return isAlreadyTooComplex= true;
5441+
// No particular location for OoM problems.
5442+
isAlreadyTooComplex.first = true;
5443+
return true;
54325444
}
54335445

54345446
if (Timer && Timer->isExpired()) {
@@ -5437,20 +5449,22 @@ class ConstraintSystem {
54375449
// emitting an error.
54385450
Timer->disableWarning();
54395451

5440-
return isAlreadyTooComplex = true;
5452+
isAlreadyTooComplex = {true, Timer->getAffectedRange()};
5453+
return true;
54415454
}
54425455

54435456
// Bail out once we've looked at a really large number of
54445457
// choices.
54455458
if (CountScopes > getASTContext().TypeCheckerOpts.SolverBindingThreshold) {
5446-
return isAlreadyTooComplex = true;
5459+
isAlreadyTooComplex.first = true;
5460+
return true;
54475461
}
54485462

54495463
return false;
54505464
}
54515465

54525466
bool isTooComplex(SmallVectorImpl<Solution> const &solutions) {
5453-
if (isAlreadyTooComplex)
5467+
if (isAlreadyTooComplex.first)
54545468
return true;
54555469

54565470
size_t solutionMemory = 0;

lib/Sema/ConstraintSystem.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ ExpressionTimer::ExpressionTimer(AnchorType Anchor, ConstraintSystem &CS,
5656
PrintDebugTiming(CS.getASTContext().TypeCheckerOpts.DebugTimeExpressions),
5757
PrintWarning(true) {}
5858

59+
SourceRange ExpressionTimer::getAffectedRange() const {
60+
ASTNode anchor;
61+
62+
if (auto *locator = Anchor.dyn_cast<ConstraintLocator *>()) {
63+
anchor = simplifyLocatorToAnchor(locator);
64+
// If locator couldn't be simplified down to a single AST
65+
// element, let's use its root.
66+
if (!anchor)
67+
anchor = locator->getAnchor();
68+
} else {
69+
anchor = Anchor.get<Expr *>();
70+
}
71+
72+
return anchor.getSourceRange();
73+
}
74+
5975
ExpressionTimer::~ExpressionTimer() {
6076
auto elapsed = getElapsedProcessTimeInFractionalSeconds();
6177
unsigned elapsedMS = static_cast<unsigned>(elapsed * 1000);
@@ -81,22 +97,13 @@ ExpressionTimer::~ExpressionTimer() {
8197
if (WarnLimit == 0 || elapsedMS < WarnLimit)
8298
return;
8399

84-
ASTNode anchor;
85-
if (auto *locator = Anchor.dyn_cast<ConstraintLocator *>()) {
86-
anchor = simplifyLocatorToAnchor(locator);
87-
// If locator couldn't be simplified down to a single AST
88-
// element, let's warn about its root.
89-
if (!anchor)
90-
anchor = locator->getAnchor();
91-
} else {
92-
anchor = Anchor.get<Expr *>();
93-
}
100+
auto sourceRange = getAffectedRange();
94101

95-
if (anchor.getStartLoc().isValid()) {
102+
if (sourceRange.Start.isValid()) {
96103
Context.Diags
97-
.diagnose(anchor.getStartLoc(), diag::debug_long_expression, elapsedMS,
104+
.diagnose(sourceRange.Start, diag::debug_long_expression, elapsedMS,
98105
WarnLimit)
99-
.highlight(anchor.getSourceRange());
106+
.highlight(sourceRange);
100107
}
101108
}
102109

0 commit comments

Comments
 (0)