Skip to content

Cleanup after recent refactoring for fix behaviors #59975

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

Merged
merged 5 commits into from
Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,10 @@ class ConstraintFix {
FixKind Kind;
ConstraintLocator *Locator;

public:
/// The behavior limit to apply to the diagnostics emitted.
FixBehavior fixBehavior;
const FixBehavior fixBehavior;

public:
ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator,
FixBehavior fixBehavior = FixBehavior::Error)
: CS(cs), Kind(kind), Locator(locator), fixBehavior(fixBehavior) {}
Expand All @@ -428,27 +428,22 @@ class ConstraintFix {

FixKind getKind() const { return Kind; }

/// Whether it is still possible to "apply" a solution containing this kind
/// of fix to get a usable AST.
bool canApplySolution() const {
/// Whether this fix fatal for the constraint solver, meaning that it cannot
/// produce a usable type-checked AST.
bool isFatal() const {
switch (fixBehavior) {
case FixBehavior::AlwaysWarning:
case FixBehavior::DowngradeToWarning:
case FixBehavior::Suppress:
return true;
return false;

case FixBehavior::Error:
return false;
return true;
}
}

/// Whether this kind of fix affects the solution score, and which score
/// it affects.
Optional<ScoreKind> affectsSolutionScore() const;

/// The diagnostic behavior limit that will be applied to any emitted
/// diagnostics.
FixBehavior diagfixBehavior() const { return fixBehavior; }
/// Determine the impact of this fix on the solution score, if any.
Optional<ScoreKind> impact() const;

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

Expand Down Expand Up @@ -804,6 +799,16 @@ class MarkGlobalActorFunction final : public ContextualMismatch {
Type rhs, ConstraintLocator *locator,
FixBehavior fixBehavior);

/// Try to apply this fix to the given types.
///
/// \returns \c true if the fix cannot be applied and the solver must fail,
/// or \c false if the fix has been applied and the solver can continue.
static bool attempt(ConstraintSystem &cs,
ConstraintKind constraintKind,
FunctionType *fromType,
FunctionType *toType,
ConstraintLocatorBuilder locator);

static bool classof(ConstraintFix *fix) {
return fix->getKind() == FixKind::MarkGlobalActorFunction;
}
Expand Down Expand Up @@ -855,6 +860,16 @@ class AddSendableAttribute final : public ContextualMismatch {
ConstraintLocator *locator,
FixBehavior fixBehavior);

/// Try to apply this fix to the given types.
///
/// \returns \c true if the fix cannot be applied and the solver must fail,
/// or \c false if the fix has been applied and the solver can continue.
static bool attempt(ConstraintSystem &cs,
ConstraintKind constraintKind,
FunctionType *fromType,
FunctionType *toType,
ConstraintLocatorBuilder locator);

static bool classof(ConstraintFix *fix) {
return fix->getKind() == FixKind::AddSendableAttribute;
}
Expand Down Expand Up @@ -3025,8 +3040,10 @@ class AddExplicitExistentialCoercion final : public ConstraintFix {
Type ErasedResultType;

AddExplicitExistentialCoercion(ConstraintSystem &cs, Type erasedResultTy,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AddExplicitExistentialCoercion, locator),
ConstraintLocator *locator,
FixBehavior fixBehavior)
: ConstraintFix(cs, FixKind::AddExplicitExistentialCoercion, locator,
fixBehavior),
ErasedResultType(erasedResultTy) {}

public:
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -3820,6 +3820,10 @@ class ConstraintSystem {
});
}

/// Determine whether the callee for the given locator is marked as
/// `@preconcurrency`.
bool hasPreconcurrencyCallee(ConstraintLocatorBuilder locator);

/// Determine whether the given declaration is unavailable from the
/// current context.
bool isDeclUnavailable(const Decl *D,
Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8467,7 +8467,7 @@ bool ConstraintSystem::applySolutionFixes(const Solution &solution) {

auto diagnosed =
primaryFix->coalesceAndDiagnose(solution, secondaryFixes);
if (primaryFix->canApplySolution()) {
if (!primaryFix->isFatal()) {
assert(diagnosed && "warnings should always be diagnosed");
(void)diagnosed;
} else {
Expand Down Expand Up @@ -9127,9 +9127,9 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
bool diagnosedErrorsViaFixes = applySolutionFixes(solution);
bool canApplySolution = true;
for (const auto fix : solution.Fixes) {
if (!fix->canApplySolution())
if (fix->isFatal())
canApplySolution = false;
if (fix->affectsSolutionScore() == SK_Fix && fix->canApplySolution())
if (fix->impact() == SK_Fix && !fix->isFatal())
++numResolvableFixes;
}

Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2749,8 +2749,9 @@ class MissingExplicitExistentialCoercion final : public FailureDiagnostic {
public:
MissingExplicitExistentialCoercion(const Solution &solution,
Type erasedResultTy,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
ConstraintLocator *locator,
FixBehavior fixBehavior)
: FailureDiagnostic(solution, locator, fixBehavior),
ErasedResultType(resolveType(erasedResultTy)) {}

SourceRange getSourceRange() const override {
Expand Down
79 changes: 73 additions & 6 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//

#include "CSDiagnostics.h"
#include "TypeCheckConcurrency.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Type.h"
Expand All @@ -37,7 +38,7 @@ using namespace constraints;

ConstraintFix::~ConstraintFix() {}

Optional<ScoreKind> ConstraintFix::affectsSolutionScore() const {
Optional<ScoreKind> ConstraintFix::impact() const {
switch (fixBehavior) {
case FixBehavior::AlwaysWarning:
return None;
Expand Down Expand Up @@ -243,10 +244,42 @@ MarkExplicitlyEscaping::create(ConstraintSystem &cs, Type lhs, Type rhs,
bool MarkGlobalActorFunction::diagnose(const Solution &solution,
bool asNote) const {
DroppedGlobalActorFunctionAttr failure(
solution, getFromType(), getToType(), getLocator(), diagfixBehavior());
solution, getFromType(), getToType(), getLocator(), fixBehavior);
return failure.diagnose(asNote);
}

/// The fix behavior to apply to a concurrency-related diagnostic.
static Optional<FixBehavior>
getConcurrencyFixBehavior(
ConstraintSystem &cs, ConstraintKind constraintKind,
ConstraintLocatorBuilder locator, bool forSendable) {
// We can only handle the downgrade for conversions.
switch (constraintKind) {
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
break;

default:
if (!cs.shouldAttemptFixes())
return None;

return FixBehavior::Error;
}

// For a @preconcurrency callee outside of a strict concurrency
// context, ignore.
if (cs.hasPreconcurrencyCallee(locator) &&
!contextRequiresStrictConcurrencyChecking(
cs.DC, GetClosureType{cs}, ClosureIsolatedByPreconcurrency{cs}))
return FixBehavior::Suppress;

// Otherwise, warn until Swift 6.
if (!cs.getASTContext().LangOpts.isSwiftVersionAtLeast(6))
return FixBehavior::DowngradeToWarning;

return FixBehavior::Error;
}

MarkGlobalActorFunction *
MarkGlobalActorFunction::create(ConstraintSystem &cs, Type lhs, Type rhs,
ConstraintLocator *locator,
Expand All @@ -259,11 +292,28 @@ MarkGlobalActorFunction::create(ConstraintSystem &cs, Type lhs, Type rhs,
cs, lhs, rhs, locator, fixBehavior);
}

bool MarkGlobalActorFunction::attempt(ConstraintSystem &cs,
ConstraintKind constraintKind,
FunctionType *fromType,
FunctionType *toType,
ConstraintLocatorBuilder locator) {
auto fixBehavior = getConcurrencyFixBehavior(
cs, constraintKind, locator, /*forSendable=*/false);
if (!fixBehavior)
return true;

auto *fix = MarkGlobalActorFunction::create(
cs, fromType, toType, cs.getConstraintLocator(locator),
*fixBehavior);

return cs.recordFix(fix);
}

bool AddSendableAttribute::diagnose(const Solution &solution,
bool asNote) const {
AttributedFuncToTypeConversionFailure failure(
solution, getFromType(), getToType(), getLocator(),
AttributedFuncToTypeConversionFailure::Concurrent, diagfixBehavior());
AttributedFuncToTypeConversionFailure::Concurrent, fixBehavior);
return failure.diagnose(asNote);
}

Expand All @@ -280,6 +330,22 @@ AddSendableAttribute::create(ConstraintSystem &cs,
return new (cs.getAllocator()) AddSendableAttribute(
cs, fromType, toType, locator, fixBehavior);
}

bool AddSendableAttribute::attempt(ConstraintSystem &cs,
ConstraintKind constraintKind,
FunctionType *fromType,
FunctionType *toType,
ConstraintLocatorBuilder locator) {
auto fixBehavior = getConcurrencyFixBehavior(
cs, constraintKind, locator, /*forSendable=*/true);
if (!fixBehavior)
return true;

auto *fix = AddSendableAttribute::create(
cs, fromType, toType, cs.getConstraintLocator(locator), *fixBehavior);
return cs.recordFix(fix);
}

bool RelabelArguments::diagnose(const Solution &solution, bool asNote) const {
LabelingFailure failure(solution, getLocator(), getLabels());
return failure.diagnose(asNote);
Expand Down Expand Up @@ -1639,7 +1705,7 @@ bool TreatEphemeralAsNonEphemeral::diagnose(const Solution &solution,
bool asNote) const {
NonEphemeralConversionFailure failure(solution, getLocator(), getFromType(),
getToType(), ConversionKind,
diagfixBehavior());
fixBehavior);
return failure.diagnose(asNote);
}

Expand Down Expand Up @@ -2233,7 +2299,7 @@ IgnoreDefaultExprTypeMismatch::create(ConstraintSystem &cs, Type argType,
bool AddExplicitExistentialCoercion::diagnose(const Solution &solution,
bool asNote) const {
MissingExplicitExistentialCoercion failure(solution, ErasedResultType,
getLocator());
getLocator(), fixBehavior);
return failure.diagnose(asNote);
}

Expand Down Expand Up @@ -2465,8 +2531,9 @@ bool AddExplicitExistentialCoercion::isRequired(
AddExplicitExistentialCoercion *
AddExplicitExistentialCoercion::create(ConstraintSystem &cs, Type resultTy,
ConstraintLocator *locator) {
FixBehavior fixBehavior = FixBehavior::Error;
return new (cs.getAllocator())
AddExplicitExistentialCoercion(cs, resultTy, locator);
AddExplicitExistentialCoercion(cs, resultTy, locator, fixBehavior);
}

bool RenameConflictingPatternVariables::diagnose(const Solution &solution,
Expand Down
68 changes: 10 additions & 58 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2655,14 +2655,10 @@ static bool fixExtraneousArguments(ConstraintSystem &cs,
/*impact=*/numExtraneous * 2);
}

bool hasPreconcurrencyCallee(ConstraintSystem *cs,
ConstraintLocatorBuilder locator) {
if (cs->getASTContext().isSwiftVersionAtLeast(6))
// Swift 6 mode does not reduce errors to warnings.
return false;

auto calleeLocator = cs->getCalleeLocator(cs->getConstraintLocator(locator));
auto calleeOverload = cs->findSelectedOverloadFor(calleeLocator);
bool ConstraintSystem::hasPreconcurrencyCallee(
ConstraintLocatorBuilder locator) {
auto calleeLocator = getCalleeLocator(getConstraintLocator(locator));
auto calleeOverload = findSelectedOverloadFor(calleeLocator);
if (!calleeOverload || !calleeOverload->choice.isDecl())
return false;

Expand Down Expand Up @@ -2716,48 +2712,12 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
increaseScore(SK_SyncInAsync);
}

/// The behavior limit to apply to a concurrency check.
auto getConcurrencyFixBehavior = [&](
bool forSendable
) -> Optional<FixBehavior> {
// We can only handle the downgrade for conversions.
switch (kind) {
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
break;

default:
if (!shouldAttemptFixes())
return None;

return FixBehavior::Error;
}

// For a @preconcurrency callee outside of a strict concurrency
// context, ignore.
if (hasPreconcurrencyCallee(this, locator) &&
!contextRequiresStrictConcurrencyChecking(DC, GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this}))
return FixBehavior::Suppress;

// Otherwise, warn until Swift 6.
if (!getASTContext().LangOpts.isSwiftVersionAtLeast(6))
return FixBehavior::DowngradeToWarning;

return FixBehavior::Error;
};

// A @Sendable function can be a subtype of a non-@Sendable function.
if (func1->isSendable() != func2->isSendable()) {
// Cannot add '@Sendable'.
if (func2->isSendable() || kind < ConstraintKind::Subtype) {
if (auto fixBehavior = getConcurrencyFixBehavior(true)) {
auto *fix = AddSendableAttribute::create(
*this, func1, func2, getConstraintLocator(locator), *fixBehavior);
if (recordFix(fix))
return getTypeMatchFailure(locator);
} else {
if (AddSendableAttribute::attempt(*this, kind, func1, func2, locator))
return getTypeMatchFailure(locator);
}
}
}

Expand Down Expand Up @@ -2785,16 +2745,8 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
return getTypeMatchFailure(locator);
} else if (func1->getGlobalActor() && !func2->isAsync()) {
// Cannot remove a global actor from a synchronous function.
if (auto fixBehavior = getConcurrencyFixBehavior(false)) {
auto *fix = MarkGlobalActorFunction::create(
*this, func1, func2, getConstraintLocator(locator),
*fixBehavior);

if (recordFix(fix))
return getTypeMatchFailure(locator);
} else {
if (MarkGlobalActorFunction::attempt(*this, kind, func1, func2, locator))
return getTypeMatchFailure(locator);
}
} else if (kind < ConstraintKind::Subtype) {
return getTypeMatchFailure(locator);
}
Expand Down Expand Up @@ -9839,7 +9791,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
auto *inferredClosureType = getClosureType(closure);

// Note if this closure is isolated by preconcurrency.
if (hasPreconcurrencyCallee(this, locator))
if (hasPreconcurrencyCallee(locator))
preconcurrencyClosures.insert(closure);

// Let's look through all optionals associated with contextual
Expand Down Expand Up @@ -12711,8 +12663,8 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) {
// Record the fix.

// If this should affect the solution score, do so.
if (auto scoreKind = fix->affectsSolutionScore())
increaseScore(*scoreKind, impact);
if (auto impactScoreKind = fix->impact())
increaseScore(*impactScoreKind, impact);

// If we've made the current solution worse than the best solution we've seen
// already, stop now.
Expand All @@ -12735,7 +12687,7 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) {
// Fixes that don't affect the score shouldn't be considered because even
// if such a fix is recorded at that anchor this should not
// have any affect in the recording of any other fix.
if (!fix->affectsSolutionScore())
if (!fix->impact())
continue;

anchors.insert(fix->getAnchor());
Expand Down
Loading