Skip to content

Commit 844feda

Browse files
committed
[ConstraintSystem] Introduce a fix to allow conversion between inout types
If there is an argument-to-parameter conversion which is associated with `inout` parameter, subtyping is now permitted, types have to be identical. ```swift protocol P {} struct S : P {} func foo(_: inout P) {} var s = S() foo(&s) // `s` has to be defined as `P` e.g. `var s: P = S()` // to be used as an argument to `inout P` parameter. ```
1 parent 7b8fb88 commit 844feda

File tree

4 files changed

+44
-9
lines changed

4 files changed

+44
-9
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,15 +1668,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
16681668
if (!exprType)
16691669
return CS.TC.Diags.hadAnyError();
16701670

1671-
// If we contextually had an inout type, and got a non-lvalue result, then
1672-
// we fail with a mutability error.
1673-
if (contextualType->is<InOutType>() && !exprType->is<LValueType>()) {
1674-
AssignmentFailure failure(recheckedExpr, CS, recheckedExpr->getLoc(),
1675-
diag::cannot_pass_rvalue_inout_subelement,
1676-
diag::cannot_pass_rvalue_inout);
1677-
return failure.diagnose();
1678-
}
1679-
16801671
// If we don't have a type for the expression, then we cannot use it in
16811672
// conversion constraint diagnostic generation. If the types match, then it
16821673
// must not be the contextual type that is the problem.

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,14 @@ IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs,
773773
return new (cs.getAllocator())
774774
IgnoreContextualType(cs, resultTy, specifiedTy, locator);
775775
}
776+
777+
bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const {
778+
return false;
779+
}
780+
781+
AllowInOutConversion *AllowInOutConversion::create(ConstraintSystem &cs,
782+
Type argType, Type paramType,
783+
ConstraintLocator *locator) {
784+
return new (cs.getAllocator())
785+
AllowInOutConversion(cs, argType, paramType, locator);
786+
}

lib/Sema/CSFix.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,26 @@ class IgnoreContextualType : public ContextualMismatch {
13121312
ConstraintLocator *locator);
13131313
};
13141314

1315+
/// If this is an argument-to-parameter conversion which is associated with
1316+
/// `inout` parameter, subtyping is now permitted, types have to
1317+
/// be identical.
1318+
class AllowInOutConversion final : public ContextualMismatch {
1319+
AllowInOutConversion(ConstraintSystem &cs, Type argType, Type paramType,
1320+
ConstraintLocator *locator)
1321+
: ContextualMismatch(cs, argType, paramType, locator) {}
1322+
1323+
public:
1324+
std::string getName() const override {
1325+
return "allow conversions between argument/parameter marked as `inout`";
1326+
}
1327+
1328+
bool diagnose(Expr *root, bool asNote = false) const override;
1329+
1330+
static AllowInOutConversion *create(ConstraintSystem &cs, Type argType,
1331+
Type paramType,
1332+
ConstraintLocator *locator);
1333+
};
1334+
13151335
} // end namespace constraints
13161336
} // end namespace swift
13171337

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,19 @@ bool ConstraintSystem::repairFailures(
25122512
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
25132513
conversionsOrFixes.push_back(
25142514
ForceOptional::create(*this, lhs, lhs->getOptionalObjectType(), loc));
2515+
break;
2516+
}
2517+
2518+
// There is no subtyping between object types of inout argument/parameter.
2519+
if (elt.getKind() == ConstraintLocator::LValueConversion) {
2520+
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
2521+
TMF_ApplyingFix, locator);
2522+
2523+
if (!result.isFailure()) {
2524+
conversionsOrFixes.push_back(
2525+
AllowInOutConversion::create(*this, lhs, rhs, loc));
2526+
break;
2527+
}
25152528
}
25162529

25172530
if (elt.getKind() != ConstraintLocator::ApplyArgToParam)

0 commit comments

Comments
 (0)