Skip to content
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
73 changes: 40 additions & 33 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,21 +587,38 @@ class RelabelArguments final
}
};

class RequirementFix : public ConstraintFix {
protected:
Type LHS;
Type RHS;

RequirementFix(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs,
ConstraintLocator *locator)
: ConstraintFix(cs, kind, locator), LHS(lhs), RHS(rhs) {}

public:
std::string getName() const override = 0;

Type lhsType() const { return LHS; }
Type rhsType() const { return RHS; }

bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;

bool diagnose(const Solution &solution,
bool asNote = false) const override = 0;
};

/// Add a new conformance to the type to satisfy a requirement.
class MissingConformance final : public ConstraintFix {
class MissingConformance final : public RequirementFix {
// Determines whether given protocol type comes from the context e.g.
// assignment destination or argument comparison.
bool IsContextual;

Type NonConformingType;
// This could either be a protocol or protocol composition.
Type ProtocolType;

MissingConformance(ConstraintSystem &cs, bool isContextual, Type type,
Type protocolType, ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AddConformance, locator),
IsContextual(isContextual), NonConformingType(type),
ProtocolType(protocolType) {}
: RequirementFix(cs, FixKind::AddConformance, type, protocolType,
locator),
IsContextual(isContextual) {}

public:
std::string getName() const override {
Expand All @@ -610,8 +627,6 @@ class MissingConformance final : public ConstraintFix {

bool diagnose(const Solution &solution, bool asNote = false) const override;

bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;

static MissingConformance *forRequirement(ConstraintSystem &cs, Type type,
Type protocolType,
ConstraintLocator *locator);
Expand All @@ -620,9 +635,9 @@ class MissingConformance final : public ConstraintFix {
Type protocolType,
ConstraintLocator *locator);

Type getNonConformingType() { return NonConformingType; }
Type getNonConformingType() const { return LHS; }

Type getProtocolType() { return ProtocolType; }
Type getProtocolType() const { return RHS; }

bool isEqual(const ConstraintFix *other) const;

Expand All @@ -633,13 +648,11 @@ class MissingConformance final : public ConstraintFix {

/// Skip same-type generic requirement constraint,
/// and assume that types are equal.
class SkipSameTypeRequirement final : public ConstraintFix {
Type LHS, RHS;

class SkipSameTypeRequirement final : public RequirementFix {
SkipSameTypeRequirement(ConstraintSystem &cs, Type lhs, Type rhs,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::SkipSameTypeRequirement, locator), LHS(lhs),
RHS(rhs) {}
: RequirementFix(cs, FixKind::SkipSameTypeRequirement, lhs, rhs,
locator) {}

public:
std::string getName() const override {
Expand All @@ -648,9 +661,6 @@ class SkipSameTypeRequirement final : public ConstraintFix {

bool diagnose(const Solution &solution, bool asNote = false) const override;

Type lhsType() { return LHS; }
Type rhsType() { return RHS; }

static SkipSameTypeRequirement *create(ConstraintSystem &cs, Type lhs,
Type rhs, ConstraintLocator *locator);

Expand All @@ -661,13 +671,11 @@ class SkipSameTypeRequirement final : public ConstraintFix {

/// Skip same-shape generic requirement constraint,
/// and assume that types are equal.
class SkipSameShapeRequirement final : public ConstraintFix {
Type LHS, RHS;

class SkipSameShapeRequirement final : public RequirementFix {
SkipSameShapeRequirement(ConstraintSystem &cs, Type lhs, Type rhs,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::SkipSameShapeRequirement, locator), LHS(lhs),
RHS(rhs) {}
: RequirementFix(cs, FixKind::SkipSameShapeRequirement, lhs, rhs,
locator) {}

public:
std::string getName() const override {
Expand All @@ -676,9 +684,6 @@ class SkipSameShapeRequirement final : public ConstraintFix {

bool diagnose(const Solution &solution, bool asNote = false) const override;

Type lhsType() { return LHS; }
Type rhsType() { return RHS; }

static SkipSameShapeRequirement *create(ConstraintSystem &cs, Type lhs,
Type rhs, ConstraintLocator *locator);

Expand All @@ -689,13 +694,11 @@ class SkipSameShapeRequirement final : public ConstraintFix {

/// Skip 'superclass' generic requirement constraint,
/// and assume that types are equal.
class SkipSuperclassRequirement final : public ConstraintFix {
Type LHS, RHS;

class SkipSuperclassRequirement final : public RequirementFix {
SkipSuperclassRequirement(ConstraintSystem &cs, Type lhs, Type rhs,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::SkipSuperclassRequirement, locator),
LHS(lhs), RHS(rhs) {}
: RequirementFix(cs, FixKind::SkipSuperclassRequirement, lhs, rhs,
locator) {}

public:
std::string getName() const override {
Expand Down Expand Up @@ -1839,6 +1842,10 @@ class AllowInaccessibleMember final : public AllowInvalidMemberRef {

bool diagnose(const Solution &solution, bool asNote = false) const override;

bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
return diagnose(*commonFixes.front().first);
}

static AllowInaccessibleMember *create(ConstraintSystem &cs, Type baseType,
ValueDecl *member, DeclNameRef name,
ConstraintLocator *locator);
Expand Down
6 changes: 4 additions & 2 deletions lib/Sema/BuilderTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2480,8 +2480,10 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
}

// Record the first unhandled construct as a fix.
if (recordFix(SkipUnhandledConstructInResultBuilder::create(
*this, unsupported, builder, getConstraintLocator(locator)))) {
if (recordFix(
SkipUnhandledConstructInResultBuilder::create(
*this, unsupported, builder, getConstraintLocator(locator)),
/*impact=*/100)) {
return getTypeMatchFailure(locator);
}

Expand Down
16 changes: 9 additions & 7 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,25 +400,26 @@ bool MissingConformance::diagnose(const Solution &solution, bool asNote) const {
auto &cs = solution.getConstraintSystem();
auto context = cs.getContextualTypePurpose(locator->getAnchor());
MissingContextualConformanceFailure failure(
solution, context, NonConformingType, ProtocolType, locator);
solution, context, getNonConformingType(), getProtocolType(), locator);
return failure.diagnose(asNote);
}

MissingConformanceFailure failure(
solution, locator, std::make_pair(NonConformingType, ProtocolType));
solution, locator,
std::make_pair(getNonConformingType(), getProtocolType()));
return failure.diagnose(asNote);
}

bool MissingConformance::diagnoseForAmbiguity(
bool RequirementFix::diagnoseForAmbiguity(
CommonFixesArray commonFixes) const {
auto *primaryFix = commonFixes.front().second->getAs<MissingConformance>();
auto *primaryFix = commonFixes.front().second;
assert(primaryFix);

if (llvm::all_of(
commonFixes,
[&primaryFix](
const std::pair<const Solution *, const ConstraintFix *> &entry) {
return primaryFix->isEqual(entry.second);
return primaryFix->getLocator() == entry.second->getLocator();
}))
return diagnose(*commonFixes.front().first);

Expand All @@ -433,8 +434,9 @@ bool MissingConformance::isEqual(const ConstraintFix *other) const {
return false;

return IsContextual == conformanceFix->IsContextual &&
NonConformingType->isEqual(conformanceFix->NonConformingType) &&
ProtocolType->isEqual(conformanceFix->ProtocolType);
getNonConformingType()->isEqual(
conformanceFix->getNonConformingType()) &&
getProtocolType()->isEqual(conformanceFix->getProtocolType());
}

MissingConformance *
Expand Down
43 changes: 38 additions & 5 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4542,14 +4542,30 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
if (!anchor)
return false;

bool possibleContextualMismatch = false;
// If this is a conversion to a non-optional contextual type e.g.
// `let _: Bool = try? foo()` and `foo()` produces `Int`
// we should diagnose it as type mismatch instead of missing unwrap.
if (auto last = locator.last()) {
possibleContextualMismatch = last->is<LocatorPathElt::ContextualType>() &&
!toType->getOptionalObjectType();
}
bool possibleContextualMismatch = [&]() {
auto last = locator.last();
if (!(last && last->is<LocatorPathElt::ContextualType>()))
return false;

// If the contextual type is optional as well, it's definitely a
// missing unwrap.
if (toType->getOptionalObjectType())
return false;

// If this is a leading-dot syntax member chain with `?.`
// notation, it wouldn't be possible to infer the base type
// without the contextual type, so we have to treat it as
// a missing unwrap.
if (auto *OEE = getAsExpr<OptionalEvaluationExpr>(anchor)) {
if (isExpr<UnresolvedMemberChainResultExpr>(OEE->getSubExpr()))
return false;
}

return true;
}();

// `OptionalEvaluationExpr` doesn't add a new level of
// optionality but it could be hiding concrete types
Expand Down Expand Up @@ -6014,6 +6030,12 @@ bool ConstraintSystem::repairFailures(
}

case ConstraintLocator::TupleElement: {
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
recordAnyTypeVarAsPotentialHole(lhs);
recordAnyTypeVarAsPotentialHole(rhs);
return true;
}

if (isExpr<ArrayExpr>(anchor) || isExpr<DictionaryExpr>(anchor)) {
// If we could record a generic arguments mismatch instead of this fix,
// don't record a ContextualMismatch here.
Expand Down Expand Up @@ -6152,6 +6174,17 @@ bool ConstraintSystem::repairFailures(
if (rhs->isPlaceholder())
return true;

// The base is a placeholder, let's report an unknown base issue.
if (lhs->isPlaceholder()) {
auto *baseExpr =
castToExpr<UnresolvedMemberChainResultExpr>(anchor)->getChainBase();

auto *fix = SpecifyBaseTypeForContextualMember::create(
*this, baseExpr->getName(), getConstraintLocator(locator));
conversionsOrFixes.push_back(fix);
break;
}

if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
locator))
break;
Expand Down
Loading