Skip to content

Commit 32ff69e

Browse files
committed
[Constraint solver] Improve modeling of fix behavior.
Rather than re-using `DiagnosticBehavior` to describe how a fix should act, introduce `FixBehavior` to cover the differences between (e.g.) always-as-awarning and downgrade-to-warning. While here, split the `isWarning` predicate into two different predicates: * `canApplySolution`: Whether we can still apply a solution when it contains this particular fix. * `affectsSolutionScore`: Whether These two predicates are currently tied together, because that's the existing behavior, but we don't necessarily want them to stay that way.
1 parent 91732b2 commit 32ff69e

File tree

8 files changed

+161
-83
lines changed

8 files changed

+161
-83
lines changed

include/swift/Sema/CSFix.h

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/Types.h"
2626
#include "swift/Basic/Debug.h"
2727
#include "swift/Sema/ConstraintLocator.h"
28+
#include "swift/Sema/FixBehavior.h"
2829
#include "llvm/ADT/ArrayRef.h"
2930
#include "llvm/ADT/SmallVector.h"
3031
#include "llvm/Support/TrailingObjects.h"
@@ -402,13 +403,12 @@ class ConstraintFix {
402403
ConstraintLocator *Locator;
403404

404405
/// The behavior limit to apply to the diagnostics emitted.
405-
DiagnosticBehavior behaviorLimit;
406+
FixBehavior fixBehavior;
406407

407408
public:
408409
ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator,
409-
DiagnosticBehavior behaviorLimit =
410-
DiagnosticBehavior::Unspecified)
411-
: CS(cs), Kind(kind), Locator(locator), behaviorLimit(behaviorLimit) {}
410+
FixBehavior fixBehavior = FixBehavior::Error)
411+
: CS(cs), Kind(kind), Locator(locator), fixBehavior(fixBehavior) {}
412412

413413
virtual ~ConstraintFix();
414414

@@ -419,14 +419,36 @@ class ConstraintFix {
419419

420420
FixKind getKind() const { return Kind; }
421421

422-
bool isWarning() const {
423-
return behaviorLimit == DiagnosticBehavior::Warning ||
424-
behaviorLimit == DiagnosticBehavior::Ignore;
422+
/// Whether it is still possible to "apply" a solution containing this kind
423+
/// of fix to get a usable AST.
424+
bool canApplySolution() const {
425+
switch (fixBehavior) {
426+
case FixBehavior::AlwaysWarning:
427+
case FixBehavior::DowngradeToWarning:
428+
case FixBehavior::Suppress:
429+
return true;
430+
431+
case FixBehavior::Error:
432+
return false;
433+
}
434+
}
435+
436+
/// Whether this kind of fix affects the solution score.
437+
bool affectsSolutionScore() const {
438+
switch (fixBehavior) {
439+
case FixBehavior::AlwaysWarning:
440+
case FixBehavior::DowngradeToWarning:
441+
case FixBehavior::Suppress:
442+
return false;
443+
444+
case FixBehavior::Error:
445+
return true;
446+
}
425447
}
426448

427449
/// The diagnostic behavior limit that will be applied to any emitted
428450
/// diagnostics.
429-
DiagnosticBehavior diagBehaviorLimit() const { return behaviorLimit; }
451+
FixBehavior diagfixBehavior() const { return fixBehavior; }
430452

431453
virtual std::string getName() const = 0;
432454

@@ -672,16 +694,15 @@ class ContextualMismatch : public ConstraintFix {
672694

673695
ContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs,
674696
ConstraintLocator *locator,
675-
DiagnosticBehavior behaviorLimit)
676-
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, behaviorLimit),
697+
FixBehavior fixBehavior)
698+
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, fixBehavior),
677699
LHS(lhs), RHS(rhs) {}
678700

679701
protected:
680702
ContextualMismatch(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs,
681703
ConstraintLocator *locator,
682-
DiagnosticBehavior behaviorLimit =
683-
DiagnosticBehavior::Unspecified)
684-
: ConstraintFix(cs, kind, locator, behaviorLimit), LHS(lhs), RHS(rhs) {}
704+
FixBehavior fixBehavior = FixBehavior::Error)
705+
: ConstraintFix(cs, kind, locator, fixBehavior), LHS(lhs), RHS(rhs) {}
685706

686707
public:
687708
std::string getName() const override { return "fix contextual mismatch"; }
@@ -766,9 +787,9 @@ class MarkExplicitlyEscaping final : public ContextualMismatch {
766787
class MarkGlobalActorFunction final : public ContextualMismatch {
767788
MarkGlobalActorFunction(ConstraintSystem &cs, Type lhs, Type rhs,
768789
ConstraintLocator *locator,
769-
DiagnosticBehavior behaviorLimit)
790+
FixBehavior fixBehavior)
770791
: ContextualMismatch(cs, FixKind::MarkGlobalActorFunction, lhs, rhs,
771-
locator, behaviorLimit) {
792+
locator, fixBehavior) {
772793
}
773794

774795
public:
@@ -778,7 +799,7 @@ class MarkGlobalActorFunction final : public ContextualMismatch {
778799

779800
static MarkGlobalActorFunction *create(ConstraintSystem &cs, Type lhs,
780801
Type rhs, ConstraintLocator *locator,
781-
DiagnosticBehavior behaviorLimit);
802+
FixBehavior fixBehavior);
782803

783804
static bool classof(ConstraintFix *fix) {
784805
return fix->getKind() == FixKind::MarkGlobalActorFunction;
@@ -814,9 +835,9 @@ class ForceOptional final : public ContextualMismatch {
814835
class AddSendableAttribute final : public ContextualMismatch {
815836
AddSendableAttribute(ConstraintSystem &cs, FunctionType *fromType,
816837
FunctionType *toType, ConstraintLocator *locator,
817-
DiagnosticBehavior behaviorLimit)
838+
FixBehavior fixBehavior)
818839
: ContextualMismatch(cs, FixKind::AddSendableAttribute, fromType, toType,
819-
locator, behaviorLimit) {
840+
locator, fixBehavior) {
820841
assert(fromType->isSendable() != toType->isSendable());
821842
}
822843

@@ -829,7 +850,7 @@ class AddSendableAttribute final : public ContextualMismatch {
829850
FunctionType *fromType,
830851
FunctionType *toType,
831852
ConstraintLocator *locator,
832-
DiagnosticBehavior behaviorLimit);
853+
FixBehavior fixBehavior);
833854

834855
static bool classof(ConstraintFix *fix) {
835856
return fix->getKind() == FixKind::AddSendableAttribute;
@@ -1392,11 +1413,14 @@ class AllowTypeOrInstanceMember final : public AllowInvalidMemberRef {
13921413
};
13931414

13941415
class AllowInvalidPartialApplication final : public ConstraintFix {
1416+
bool isWarning;
1417+
13951418
AllowInvalidPartialApplication(bool isWarning, ConstraintSystem &cs,
13961419
ConstraintLocator *locator)
13971420
: ConstraintFix(cs, FixKind::AllowInvalidPartialApplication, locator,
1398-
isWarning ? DiagnosticBehavior::Warning
1399-
: DiagnosticBehavior::Unspecified) {}
1421+
isWarning ? FixBehavior::AlwaysWarning
1422+
: FixBehavior::Error),
1423+
isWarning(isWarning) {}
14001424

14011425
public:
14021426
std::string getName() const override {
@@ -2130,10 +2154,9 @@ class AllowArgumentMismatch : public ContextualMismatch {
21302154

21312155
AllowArgumentMismatch(ConstraintSystem &cs, FixKind kind, Type argType,
21322156
Type paramType, ConstraintLocator *locator,
2133-
DiagnosticBehavior behaviorLimit =
2134-
DiagnosticBehavior::Unspecified)
2157+
FixBehavior fixBehavior = FixBehavior::Error)
21352158
: ContextualMismatch(
2136-
cs, kind, argType, paramType, locator, behaviorLimit) {}
2159+
cs, kind, argType, paramType, locator, fixBehavior) {}
21372160

21382161
public:
21392162
std::string getName() const override {
@@ -2281,9 +2304,9 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch {
22812304
TreatEphemeralAsNonEphemeral(ConstraintSystem &cs, ConstraintLocator *locator,
22822305
Type srcType, Type dstType,
22832306
ConversionRestrictionKind conversionKind,
2284-
DiagnosticBehavior behaviorLimit)
2307+
FixBehavior fixBehavior)
22852308
: AllowArgumentMismatch(cs, FixKind::TreatEphemeralAsNonEphemeral,
2286-
srcType, dstType, locator, behaviorLimit),
2309+
srcType, dstType, locator, fixBehavior),
22872310
ConversionKind(conversionKind) {}
22882311

22892312
public:
@@ -2447,7 +2470,7 @@ class AllowCoercionToForceCast final : public ContextualMismatch {
24472470
AllowCoercionToForceCast(ConstraintSystem &cs, Type fromType, Type toType,
24482471
ConstraintLocator *locator)
24492472
: ContextualMismatch(cs, FixKind::AllowCoercionToForceCast, fromType,
2450-
toType, locator, DiagnosticBehavior::Warning) {}
2473+
toType, locator, FixBehavior::AlwaysWarning) {}
24512474

24522475
public:
24532476
std::string getName() const override {
@@ -2561,7 +2584,7 @@ class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix {
25612584
SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs,
25622585
ConstraintLocator *locator)
25632586
: ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure,
2564-
locator, DiagnosticBehavior::Warning) {}
2587+
locator, FixBehavior::AlwaysWarning) {}
25652588

25662589
public:
25672590
std::string getName() const override {
@@ -2731,7 +2754,7 @@ class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix {
27312754
DeclNameRef memberName,
27322755
ConstraintLocator *locator)
27332756
: ConstraintFix(cs, FixKind::SpecifyBaseTypeForOptionalUnresolvedMember,
2734-
locator, DiagnosticBehavior::Warning),
2757+
locator, FixBehavior::AlwaysWarning),
27352758
MemberName(memberName) {}
27362759
DeclNameRef MemberName;
27372760

@@ -2762,7 +2785,7 @@ class CheckedCastContextualMismatchWarning : public ContextualMismatch {
27622785
CheckedCastKind kind,
27632786
ConstraintLocator *locator)
27642787
: ContextualMismatch(cs, fixKind, fromType, toType, locator,
2765-
DiagnosticBehavior::Warning),
2788+
FixBehavior::AlwaysWarning),
27662789
CastKind(kind) {}
27672790
CheckedCastKind CastKind;
27682791
};
@@ -2873,7 +2896,7 @@ class AllowTupleLabelMismatch final : public ContextualMismatch {
28732896
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType,
28742897
ConstraintLocator *locator)
28752898
: ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType,
2876-
toType, locator, DiagnosticBehavior::Warning) {}
2899+
toType, locator, FixBehavior::AlwaysWarning) {}
28772900

28782901
public:
28792902
std::string getName() const override { return "allow tuple label mismatch"; }

include/swift/Sema/FixBehavior.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===--- FixBehavior.h - Constraint Fix Behavior --------------------------===//
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 provides information about how a constraint fix should behavior.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SEMA_FIXBEHAVIOR_H
18+
#define SWIFT_SEMA_FIXBEHAVIOR_H
19+
20+
namespace swift {
21+
namespace constraints {
22+
23+
/// Describes the behavior of the diagnostic corresponding to a given fix.
24+
enum class FixBehavior {
25+
/// The diagnostic is an error, and should prevent constraint application.
26+
Error,
27+
/// The diagnostic is always a warning, which should not prevent constraint
28+
/// application.
29+
AlwaysWarning,
30+
/// The diagnostic should be downgraded to a warning, and not prevent
31+
/// constraint application.
32+
DowngradeToWarning,
33+
/// The diagnostic should be suppressed, and not prevent constraint
34+
/// application.
35+
Suppress
36+
};
37+
38+
}
39+
}
40+
41+
#endif // SWIFT_SEMA_FIXBEHAVIOR_H

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8480,7 +8480,7 @@ bool ConstraintSystem::applySolutionFixes(const Solution &solution) {
84808480

84818481
auto diagnosed =
84828482
primaryFix->coalesceAndDiagnose(solution, secondaryFixes);
8483-
if (primaryFix->isWarning()) {
8483+
if (primaryFix->canApplySolution()) {
84848484
assert(diagnosed && "warnings should always be diagnosed");
84858485
(void)diagnosed;
84868486
} else {
@@ -9113,7 +9113,7 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
91139113
// If all of the available fixes would result in a warning,
91149114
// we can go ahead and apply this solution to AST.
91159115
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
9116-
return fix->isWarning();
9116+
return fix->canApplySolution();
91179117
})) {
91189118
// If we already diagnosed any errors via fixes, that's it.
91199119
if (diagnosedErrorsViaFixes)

lib/Sema/CSDiagnostics.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ template <typename... ArgTypes>
103103
InFlightDiagnostic
104104
FailureDiagnostic::emitDiagnosticAt(ArgTypes &&... Args) const {
105105
auto &DE = getASTContext().Diags;
106+
DiagnosticBehavior behaviorLimit;
107+
switch (fixBehavior) {
108+
case FixBehavior::Error:
109+
case FixBehavior::AlwaysWarning:
110+
behaviorLimit = DiagnosticBehavior::Unspecified;
111+
break;
112+
113+
case FixBehavior::DowngradeToWarning:
114+
behaviorLimit = DiagnosticBehavior::Warning;
115+
break;
116+
117+
case FixBehavior::Suppress:
118+
behaviorLimit = DiagnosticBehavior::Ignore;
119+
break;
120+
}
121+
106122
return std::move(DE.diagnose(std::forward<ArgTypes>(Args)...)
107123
.limitBehavior(behaviorLimit));
108124
}

0 commit comments

Comments
 (0)