-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Constraint solver] Improve fix behaviors for better concurrency-related recovery and overloading #59958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Constraint solver] Improve fix behaviors for better concurrency-related recovery and overloading #59958
Changes from all commits
c564698
2e3aa67
c2f88ab
6cab661
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
#include "swift/AST/Types.h" | ||
#include "swift/Basic/Debug.h" | ||
#include "swift/Sema/ConstraintLocator.h" | ||
#include "swift/Sema/FixBehavior.h" | ||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
#include "llvm/Support/TrailingObjects.h" | ||
|
@@ -45,6 +46,7 @@ class ConstraintSystem; | |
class ConstraintLocator; | ||
class ConstraintLocatorBuilder; | ||
enum class ConversionRestrictionKind; | ||
enum ScoreKind: unsigned int; | ||
class Solution; | ||
struct MemberLookupResult; | ||
|
||
|
@@ -410,13 +412,12 @@ class ConstraintFix { | |
ConstraintLocator *Locator; | ||
|
||
/// The behavior limit to apply to the diagnostics emitted. | ||
DiagnosticBehavior behaviorLimit; | ||
FixBehavior fixBehavior; | ||
|
||
public: | ||
ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit = | ||
DiagnosticBehavior::Unspecified) | ||
: CS(cs), Kind(kind), Locator(locator), behaviorLimit(behaviorLimit) {} | ||
FixBehavior fixBehavior = FixBehavior::Error) | ||
: CS(cs), Kind(kind), Locator(locator), fixBehavior(fixBehavior) {} | ||
|
||
virtual ~ConstraintFix(); | ||
|
||
|
@@ -427,14 +428,27 @@ class ConstraintFix { | |
|
||
FixKind getKind() const { return Kind; } | ||
|
||
bool isWarning() const { | ||
return behaviorLimit == DiagnosticBehavior::Warning || | ||
behaviorLimit == DiagnosticBehavior::Ignore; | ||
/// Whether it is still possible to "apply" a solution containing this kind | ||
/// of fix to get a usable AST. | ||
bool canApplySolution() const { | ||
switch (fixBehavior) { | ||
case FixBehavior::AlwaysWarning: | ||
case FixBehavior::DowngradeToWarning: | ||
case FixBehavior::Suppress: | ||
return true; | ||
|
||
case FixBehavior::Error: | ||
return false; | ||
} | ||
} | ||
|
||
/// Whether this kind of fix affects the solution score, and which score | ||
/// it affects. | ||
Optional<ScoreKind> affectsSolutionScore() const; | ||
DougGregor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// The diagnostic behavior limit that will be applied to any emitted | ||
/// diagnostics. | ||
DiagnosticBehavior diagBehaviorLimit() const { return behaviorLimit; } | ||
FixBehavior diagfixBehavior() const { return fixBehavior; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it might make sense to turn this into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to keep around the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see my comment about this attached to |
||
|
||
virtual std::string getName() const = 0; | ||
|
||
|
@@ -680,16 +694,15 @@ class ContextualMismatch : public ConstraintFix { | |
|
||
ContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs, | ||
ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit) | ||
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, behaviorLimit), | ||
FixBehavior fixBehavior) | ||
: ConstraintFix(cs, FixKind::ContextualMismatch, locator, fixBehavior), | ||
LHS(lhs), RHS(rhs) {} | ||
|
||
protected: | ||
ContextualMismatch(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs, | ||
ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit = | ||
DiagnosticBehavior::Unspecified) | ||
: ConstraintFix(cs, kind, locator, behaviorLimit), LHS(lhs), RHS(rhs) {} | ||
FixBehavior fixBehavior = FixBehavior::Error) | ||
: ConstraintFix(cs, kind, locator, fixBehavior), LHS(lhs), RHS(rhs) {} | ||
|
||
public: | ||
std::string getName() const override { return "fix contextual mismatch"; } | ||
|
@@ -777,9 +790,9 @@ class MarkExplicitlyEscaping final : public ContextualMismatch { | |
class MarkGlobalActorFunction final : public ContextualMismatch { | ||
MarkGlobalActorFunction(ConstraintSystem &cs, Type lhs, Type rhs, | ||
ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit) | ||
FixBehavior fixBehavior) | ||
: ContextualMismatch(cs, FixKind::MarkGlobalActorFunction, lhs, rhs, | ||
locator, behaviorLimit) { | ||
locator, fixBehavior) { | ||
} | ||
|
||
public: | ||
|
@@ -789,7 +802,7 @@ class MarkGlobalActorFunction final : public ContextualMismatch { | |
|
||
static MarkGlobalActorFunction *create(ConstraintSystem &cs, Type lhs, | ||
Type rhs, ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit); | ||
FixBehavior fixBehavior); | ||
|
||
static bool classof(ConstraintFix *fix) { | ||
return fix->getKind() == FixKind::MarkGlobalActorFunction; | ||
|
@@ -825,9 +838,9 @@ class ForceOptional final : public ContextualMismatch { | |
class AddSendableAttribute final : public ContextualMismatch { | ||
AddSendableAttribute(ConstraintSystem &cs, FunctionType *fromType, | ||
FunctionType *toType, ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit) | ||
FixBehavior fixBehavior) | ||
: ContextualMismatch(cs, FixKind::AddSendableAttribute, fromType, toType, | ||
locator, behaviorLimit) { | ||
locator, fixBehavior) { | ||
assert(fromType->isSendable() != toType->isSendable()); | ||
} | ||
|
||
|
@@ -840,7 +853,7 @@ class AddSendableAttribute final : public ContextualMismatch { | |
FunctionType *fromType, | ||
FunctionType *toType, | ||
ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit); | ||
FixBehavior fixBehavior); | ||
|
||
static bool classof(ConstraintFix *fix) { | ||
return fix->getKind() == FixKind::AddSendableAttribute; | ||
|
@@ -1403,11 +1416,14 @@ class AllowTypeOrInstanceMember final : public AllowInvalidMemberRef { | |
}; | ||
|
||
class AllowInvalidPartialApplication final : public ConstraintFix { | ||
bool isWarning; | ||
|
||
AllowInvalidPartialApplication(bool isWarning, ConstraintSystem &cs, | ||
ConstraintLocator *locator) | ||
: ConstraintFix(cs, FixKind::AllowInvalidPartialApplication, locator, | ||
isWarning ? DiagnosticBehavior::Warning | ||
: DiagnosticBehavior::Unspecified) {} | ||
isWarning ? FixBehavior::AlwaysWarning | ||
: FixBehavior::Error), | ||
isWarning(isWarning) {} | ||
|
||
public: | ||
std::string getName() const override { | ||
|
@@ -2141,10 +2157,9 @@ class AllowArgumentMismatch : public ContextualMismatch { | |
|
||
AllowArgumentMismatch(ConstraintSystem &cs, FixKind kind, Type argType, | ||
Type paramType, ConstraintLocator *locator, | ||
DiagnosticBehavior behaviorLimit = | ||
DiagnosticBehavior::Unspecified) | ||
FixBehavior fixBehavior = FixBehavior::Error) | ||
: ContextualMismatch( | ||
cs, kind, argType, paramType, locator, behaviorLimit) {} | ||
cs, kind, argType, paramType, locator, fixBehavior) {} | ||
|
||
public: | ||
std::string getName() const override { | ||
|
@@ -2292,9 +2307,9 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch { | |
TreatEphemeralAsNonEphemeral(ConstraintSystem &cs, ConstraintLocator *locator, | ||
Type srcType, Type dstType, | ||
ConversionRestrictionKind conversionKind, | ||
DiagnosticBehavior behaviorLimit) | ||
FixBehavior fixBehavior) | ||
: AllowArgumentMismatch(cs, FixKind::TreatEphemeralAsNonEphemeral, | ||
srcType, dstType, locator, behaviorLimit), | ||
srcType, dstType, locator, fixBehavior), | ||
ConversionKind(conversionKind) {} | ||
|
||
public: | ||
|
@@ -2458,7 +2473,7 @@ class AllowCoercionToForceCast final : public ContextualMismatch { | |
AllowCoercionToForceCast(ConstraintSystem &cs, Type fromType, Type toType, | ||
ConstraintLocator *locator) | ||
: ContextualMismatch(cs, FixKind::AllowCoercionToForceCast, fromType, | ||
toType, locator, DiagnosticBehavior::Warning) {} | ||
toType, locator, FixBehavior::AlwaysWarning) {} | ||
|
||
public: | ||
std::string getName() const override { | ||
|
@@ -2572,7 +2587,7 @@ class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { | |
SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs, | ||
ConstraintLocator *locator) | ||
: ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure, | ||
locator, DiagnosticBehavior::Warning) {} | ||
locator, FixBehavior::AlwaysWarning) {} | ||
|
||
public: | ||
std::string getName() const override { | ||
|
@@ -2742,7 +2757,7 @@ class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix { | |
DeclNameRef memberName, | ||
ConstraintLocator *locator) | ||
: ConstraintFix(cs, FixKind::SpecifyBaseTypeForOptionalUnresolvedMember, | ||
locator, DiagnosticBehavior::Warning), | ||
locator, FixBehavior::AlwaysWarning), | ||
MemberName(memberName) {} | ||
DeclNameRef MemberName; | ||
|
||
|
@@ -2773,7 +2788,7 @@ class CheckedCastContextualMismatchWarning : public ContextualMismatch { | |
CheckedCastKind kind, | ||
ConstraintLocator *locator) | ||
: ContextualMismatch(cs, fixKind, fromType, toType, locator, | ||
DiagnosticBehavior::Warning), | ||
FixBehavior::AlwaysWarning), | ||
CastKind(kind) {} | ||
CheckedCastKind CastKind; | ||
}; | ||
|
@@ -2932,7 +2947,7 @@ class AllowTupleLabelMismatch final : public ContextualMismatch { | |
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType, | ||
ConstraintLocator *locator) | ||
: ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType, | ||
toType, locator, DiagnosticBehavior::Warning) {} | ||
toType, locator, FixBehavior::AlwaysWarning) {} | ||
|
||
public: | ||
std::string getName() const override { return "allow tuple label mismatch"; } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//===--- FixBehavior.h - Constraint Fix Behavior --------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file provides information about how a constraint fix should behavior. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef SWIFT_SEMA_FIXBEHAVIOR_H | ||
#define SWIFT_SEMA_FIXBEHAVIOR_H | ||
|
||
namespace swift { | ||
namespace constraints { | ||
|
||
/// Describes the behavior of the diagnostic corresponding to a given fix. | ||
enum class FixBehavior { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my comment about |
||
/// The diagnostic is an error, and should prevent constraint application. | ||
Error, | ||
/// The diagnostic is always a warning, which should not prevent constraint | ||
/// application. | ||
AlwaysWarning, | ||
/// The diagnostic should be downgraded to a warning, and not prevent | ||
/// constraint application. | ||
DowngradeToWarning, | ||
/// The diagnostic should be suppressed, and not prevent constraint | ||
/// application. | ||
Suppress | ||
}; | ||
|
||
} | ||
} | ||
|
||
#endif // SWIFT_SEMA_FIXBEHAVIOR_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8480,7 +8480,7 @@ bool ConstraintSystem::applySolutionFixes(const Solution &solution) { | |
|
||
auto diagnosed = | ||
primaryFix->coalesceAndDiagnose(solution, secondaryFixes); | ||
if (primaryFix->isWarning()) { | ||
if (primaryFix->canApplySolution()) { | ||
assert(diagnosed && "warnings should always be diagnosed"); | ||
(void)diagnosed; | ||
} else { | ||
|
@@ -9132,16 +9132,23 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution( | |
Solution &solution, SolutionApplicationTarget target) { | ||
// If any fixes needed to be applied to arrive at this solution, resolve | ||
// them to specific expressions. | ||
unsigned numResolvableFixes = 0; | ||
if (!solution.Fixes.empty()) { | ||
if (shouldSuppressDiagnostics()) | ||
return None; | ||
|
||
bool diagnosedErrorsViaFixes = applySolutionFixes(solution); | ||
bool canApplySolution = true; | ||
for (const auto fix : solution.Fixes) { | ||
if (!fix->canApplySolution()) | ||
canApplySolution = false; | ||
if (fix->affectsSolutionScore() == SK_Fix && fix->canApplySolution()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems odd to me because anything which sets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, this change became unnecessary with my last commit, because we no longer increase There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, but I've been thinking about adding a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It sounds like we need to split SK_Fix into SK_FatalFix and SK_RecoverableFIx or something like that. |
||
++numResolvableFixes; | ||
} | ||
|
||
// If all of the available fixes would result in a warning, | ||
// we can go ahead and apply this solution to AST. | ||
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) { | ||
return fix->isWarning(); | ||
})) { | ||
if (!canApplySolution) { | ||
// If we already diagnosed any errors via fixes, that's it. | ||
if (diagnosedErrorsViaFixes) | ||
return None; | ||
|
@@ -9158,7 +9165,7 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution( | |
// produce a fallback diagnostic to highlight the problem. | ||
{ | ||
const auto &score = solution.getFixedScore(); | ||
if (score.Data[SK_Fix] > 0 || score.Data[SK_Hole] > 0) { | ||
if (score.Data[SK_Fix] > numResolvableFixes || score.Data[SK_Hole] > 0) { | ||
maybeProduceFallbackDiagnostic(target); | ||
return None; | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.