Skip to content

Commit c564698

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 aa2270a commit c564698

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"
@@ -410,13 +411,12 @@ class ConstraintFix {
410411
ConstraintLocator *Locator;
411412

412413
/// The behavior limit to apply to the diagnostics emitted.
413-
DiagnosticBehavior behaviorLimit;
414+
FixBehavior fixBehavior;
414415

415416
public:
416417
ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator,
417-
DiagnosticBehavior behaviorLimit =
418-
DiagnosticBehavior::Unspecified)
419-
: CS(cs), Kind(kind), Locator(locator), behaviorLimit(behaviorLimit) {}
418+
FixBehavior fixBehavior = FixBehavior::Error)
419+
: CS(cs), Kind(kind), Locator(locator), fixBehavior(fixBehavior) {}
420420

421421
virtual ~ConstraintFix();
422422

@@ -427,14 +427,36 @@ class ConstraintFix {
427427

428428
FixKind getKind() const { return Kind; }
429429

430-
bool isWarning() const {
431-
return behaviorLimit == DiagnosticBehavior::Warning ||
432-
behaviorLimit == DiagnosticBehavior::Ignore;
430+
/// Whether it is still possible to "apply" a solution containing this kind
431+
/// of fix to get a usable AST.
432+
bool canApplySolution() const {
433+
switch (fixBehavior) {
434+
case FixBehavior::AlwaysWarning:
435+
case FixBehavior::DowngradeToWarning:
436+
case FixBehavior::Suppress:
437+
return true;
438+
439+
case FixBehavior::Error:
440+
return false;
441+
}
442+
}
443+
444+
/// Whether this kind of fix affects the solution score.
445+
bool affectsSolutionScore() const {
446+
switch (fixBehavior) {
447+
case FixBehavior::AlwaysWarning:
448+
case FixBehavior::DowngradeToWarning:
449+
case FixBehavior::Suppress:
450+
return false;
451+
452+
case FixBehavior::Error:
453+
return true;
454+
}
433455
}
434456

435457
/// The diagnostic behavior limit that will be applied to any emitted
436458
/// diagnostics.
437-
DiagnosticBehavior diagBehaviorLimit() const { return behaviorLimit; }
459+
FixBehavior diagfixBehavior() const { return fixBehavior; }
438460

439461
virtual std::string getName() const = 0;
440462

@@ -680,16 +702,15 @@ class ContextualMismatch : public ConstraintFix {
680702

681703
ContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs,
682704
ConstraintLocator *locator,
683-
DiagnosticBehavior behaviorLimit)
684-
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, behaviorLimit),
705+
FixBehavior fixBehavior)
706+
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, fixBehavior),
685707
LHS(lhs), RHS(rhs) {}
686708

687709
protected:
688710
ContextualMismatch(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs,
689711
ConstraintLocator *locator,
690-
DiagnosticBehavior behaviorLimit =
691-
DiagnosticBehavior::Unspecified)
692-
: ConstraintFix(cs, kind, locator, behaviorLimit), LHS(lhs), RHS(rhs) {}
712+
FixBehavior fixBehavior = FixBehavior::Error)
713+
: ConstraintFix(cs, kind, locator, fixBehavior), LHS(lhs), RHS(rhs) {}
693714

694715
public:
695716
std::string getName() const override { return "fix contextual mismatch"; }
@@ -777,9 +798,9 @@ class MarkExplicitlyEscaping final : public ContextualMismatch {
777798
class MarkGlobalActorFunction final : public ContextualMismatch {
778799
MarkGlobalActorFunction(ConstraintSystem &cs, Type lhs, Type rhs,
779800
ConstraintLocator *locator,
780-
DiagnosticBehavior behaviorLimit)
801+
FixBehavior fixBehavior)
781802
: ContextualMismatch(cs, FixKind::MarkGlobalActorFunction, lhs, rhs,
782-
locator, behaviorLimit) {
803+
locator, fixBehavior) {
783804
}
784805

785806
public:
@@ -789,7 +810,7 @@ class MarkGlobalActorFunction final : public ContextualMismatch {
789810

790811
static MarkGlobalActorFunction *create(ConstraintSystem &cs, Type lhs,
791812
Type rhs, ConstraintLocator *locator,
792-
DiagnosticBehavior behaviorLimit);
813+
FixBehavior fixBehavior);
793814

794815
static bool classof(ConstraintFix *fix) {
795816
return fix->getKind() == FixKind::MarkGlobalActorFunction;
@@ -825,9 +846,9 @@ class ForceOptional final : public ContextualMismatch {
825846
class AddSendableAttribute final : public ContextualMismatch {
826847
AddSendableAttribute(ConstraintSystem &cs, FunctionType *fromType,
827848
FunctionType *toType, ConstraintLocator *locator,
828-
DiagnosticBehavior behaviorLimit)
849+
FixBehavior fixBehavior)
829850
: ContextualMismatch(cs, FixKind::AddSendableAttribute, fromType, toType,
830-
locator, behaviorLimit) {
851+
locator, fixBehavior) {
831852
assert(fromType->isSendable() != toType->isSendable());
832853
}
833854

@@ -840,7 +861,7 @@ class AddSendableAttribute final : public ContextualMismatch {
840861
FunctionType *fromType,
841862
FunctionType *toType,
842863
ConstraintLocator *locator,
843-
DiagnosticBehavior behaviorLimit);
864+
FixBehavior fixBehavior);
844865

845866
static bool classof(ConstraintFix *fix) {
846867
return fix->getKind() == FixKind::AddSendableAttribute;
@@ -1403,11 +1424,14 @@ class AllowTypeOrInstanceMember final : public AllowInvalidMemberRef {
14031424
};
14041425

14051426
class AllowInvalidPartialApplication final : public ConstraintFix {
1427+
bool isWarning;
1428+
14061429
AllowInvalidPartialApplication(bool isWarning, ConstraintSystem &cs,
14071430
ConstraintLocator *locator)
14081431
: ConstraintFix(cs, FixKind::AllowInvalidPartialApplication, locator,
1409-
isWarning ? DiagnosticBehavior::Warning
1410-
: DiagnosticBehavior::Unspecified) {}
1432+
isWarning ? FixBehavior::AlwaysWarning
1433+
: FixBehavior::Error),
1434+
isWarning(isWarning) {}
14111435

14121436
public:
14131437
std::string getName() const override {
@@ -2141,10 +2165,9 @@ class AllowArgumentMismatch : public ContextualMismatch {
21412165

21422166
AllowArgumentMismatch(ConstraintSystem &cs, FixKind kind, Type argType,
21432167
Type paramType, ConstraintLocator *locator,
2144-
DiagnosticBehavior behaviorLimit =
2145-
DiagnosticBehavior::Unspecified)
2168+
FixBehavior fixBehavior = FixBehavior::Error)
21462169
: ContextualMismatch(
2147-
cs, kind, argType, paramType, locator, behaviorLimit) {}
2170+
cs, kind, argType, paramType, locator, fixBehavior) {}
21482171

21492172
public:
21502173
std::string getName() const override {
@@ -2292,9 +2315,9 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch {
22922315
TreatEphemeralAsNonEphemeral(ConstraintSystem &cs, ConstraintLocator *locator,
22932316
Type srcType, Type dstType,
22942317
ConversionRestrictionKind conversionKind,
2295-
DiagnosticBehavior behaviorLimit)
2318+
FixBehavior fixBehavior)
22962319
: AllowArgumentMismatch(cs, FixKind::TreatEphemeralAsNonEphemeral,
2297-
srcType, dstType, locator, behaviorLimit),
2320+
srcType, dstType, locator, fixBehavior),
22982321
ConversionKind(conversionKind) {}
22992322

23002323
public:
@@ -2458,7 +2481,7 @@ class AllowCoercionToForceCast final : public ContextualMismatch {
24582481
AllowCoercionToForceCast(ConstraintSystem &cs, Type fromType, Type toType,
24592482
ConstraintLocator *locator)
24602483
: ContextualMismatch(cs, FixKind::AllowCoercionToForceCast, fromType,
2461-
toType, locator, DiagnosticBehavior::Warning) {}
2484+
toType, locator, FixBehavior::AlwaysWarning) {}
24622485

24632486
public:
24642487
std::string getName() const override {
@@ -2572,7 +2595,7 @@ class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix {
25722595
SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs,
25732596
ConstraintLocator *locator)
25742597
: ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure,
2575-
locator, DiagnosticBehavior::Warning) {}
2598+
locator, FixBehavior::AlwaysWarning) {}
25762599

25772600
public:
25782601
std::string getName() const override {
@@ -2742,7 +2765,7 @@ class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix {
27422765
DeclNameRef memberName,
27432766
ConstraintLocator *locator)
27442767
: ConstraintFix(cs, FixKind::SpecifyBaseTypeForOptionalUnresolvedMember,
2745-
locator, DiagnosticBehavior::Warning),
2768+
locator, FixBehavior::AlwaysWarning),
27462769
MemberName(memberName) {}
27472770
DeclNameRef MemberName;
27482771

@@ -2773,7 +2796,7 @@ class CheckedCastContextualMismatchWarning : public ContextualMismatch {
27732796
CheckedCastKind kind,
27742797
ConstraintLocator *locator)
27752798
: ContextualMismatch(cs, fixKind, fromType, toType, locator,
2776-
DiagnosticBehavior::Warning),
2799+
FixBehavior::AlwaysWarning),
27772800
CastKind(kind) {}
27782801
CheckedCastKind CastKind;
27792802
};
@@ -2932,7 +2955,7 @@ class AllowTupleLabelMismatch final : public ContextualMismatch {
29322955
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType,
29332956
ConstraintLocator *locator)
29342957
: ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType,
2935-
toType, locator, DiagnosticBehavior::Warning) {}
2958+
toType, locator, FixBehavior::AlwaysWarning) {}
29362959

29372960
public:
29382961
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 {
@@ -9140,7 +9140,7 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
91409140
// If all of the available fixes would result in a warning,
91419141
// we can go ahead and apply this solution to AST.
91429142
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
9143-
return fix->isWarning();
9143+
return fix->canApplySolution();
91449144
})) {
91459145
// If we already diagnosed any errors via fixes, that's it.
91469146
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)