Skip to content

Commit 9d73ead

Browse files
authored
Merge pull request #27283 from xedin/assign-conversion-failures
[ConstraintSystem] Introduce a fix for assignment type mismatch
2 parents 3a93147 + 8eaeb51 commit 9d73ead

File tree

6 files changed

+79
-14
lines changed

6 files changed

+79
-14
lines changed

lib/Sema/CSFix.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,26 @@ IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs,
759759
IgnoreContextualType(cs, resultTy, specifiedTy, locator);
760760
}
761761

762+
bool IgnoreAssignmentDestinationType::diagnose(Expr *root, bool asNote) const {
763+
auto &cs = getConstraintSystem();
764+
auto *AE = cast<AssignExpr>(getAnchor());
765+
auto CTP = isa<SubscriptExpr>(AE->getDest()) ? CTP_SubscriptAssignSource
766+
: CTP_AssignSource;
767+
768+
ContextualFailure failure(
769+
root, cs, CTP, getFromType(), getToType(),
770+
cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType()));
771+
return failure.diagnose(asNote);
772+
}
773+
774+
IgnoreAssignmentDestinationType *
775+
IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy,
776+
Type destTy,
777+
ConstraintLocator *locator) {
778+
return new (cs.getAllocator())
779+
IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator);
780+
}
781+
762782
bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const {
763783
auto &cs = getConstraintSystem();
764784
InOutConversionFailure failure(root, cs, getFromType(), getToType(),

lib/Sema/CSFix.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,23 @@ class IgnoreContextualType : public ContextualMismatch {
12991299
ConstraintLocator *locator);
13001300
};
13011301

1302+
class IgnoreAssignmentDestinationType final : public ContextualMismatch {
1303+
IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy,
1304+
Type destTy, ConstraintLocator *locator)
1305+
: ContextualMismatch(cs, sourceTy, destTy, locator) {}
1306+
1307+
public:
1308+
std::string getName() const override {
1309+
return "ignore type of the assignment destination";
1310+
}
1311+
1312+
bool diagnose(Expr *root, bool asNote = false) const override;
1313+
1314+
static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs,
1315+
Type sourceTy, Type destTy,
1316+
ConstraintLocator *locator);
1317+
};
1318+
13021319
/// If this is an argument-to-parameter conversion which is associated with
13031320
/// `inout` parameter, subtyping is not permitted, types have to
13041321
/// be identical.

lib/Sema/CSSimplify.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,15 @@ bool ConstraintSystem::repairFailures(
23532353
return false;
23542354
};
23552355

2356+
auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) {
2357+
return llvm::any_of(conversionsOrFixes,
2358+
[kind](const RestrictionOrFix correction) {
2359+
if (auto restriction = correction.getRestriction())
2360+
return restriction == kind;
2361+
return false;
2362+
});
2363+
};
2364+
23562365
if (path.empty()) {
23572366
if (!anchor)
23582367
return false;
@@ -2391,20 +2400,39 @@ bool ConstraintSystem::repairFailures(
23912400

23922401
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
23932402
return true;
2403+
2404+
// If we are trying to assign e.g. `Array<Int>` to `Array<Float>` let's
2405+
// give solver a chance to determine which generic parameters are
2406+
// mismatched and produce a fix for that.
2407+
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality))
2408+
return false;
2409+
2410+
// If the situation has to do with protocol composition types and
2411+
// destination doesn't have one of the conformances e.g. source is
2412+
// `X & Y` but destination is only `Y` or vice versa, there is a
2413+
// tailored "missing conformance" fix for that.
2414+
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
2415+
return false;
2416+
2417+
// If this is an attempt to assign something to a value of optional type
2418+
// there is a possiblity that the problem is related to escapiness, so
2419+
// fix has to be delayed.
2420+
if (hasConversionOrRestriction(
2421+
ConversionRestrictionKind::ValueToOptional))
2422+
return false;
2423+
2424+
// If the destination of an assignment is l-value type
2425+
// it leaves only possible reason for failure - a type mismatch.
2426+
if (getType(AE->getDest())->is<LValueType>()) {
2427+
conversionsOrFixes.push_back(IgnoreAssignmentDestinationType::create(
2428+
*this, lhs, rhs, getConstraintLocator(locator)));
2429+
return true;
2430+
}
23942431
}
23952432

23962433
return false;
23972434
}
23982435

2399-
auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) {
2400-
return llvm::any_of(conversionsOrFixes,
2401-
[kind](const RestrictionOrFix correction) {
2402-
if (auto restriction = correction.getRestriction())
2403-
return restriction == kind;
2404-
return false;
2405-
});
2406-
};
2407-
24082436
auto elt = path.back();
24092437
switch (elt.getKind()) {
24102438
case ConstraintLocator::LValueConversion: {

test/Constraints/closures.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ func rdar20868864(_ s: String) {
394394
func r22058555() {
395395
var firstChar: UInt8 = 0
396396
"abc".withCString { chars in
397-
firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}}
397+
firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} {{17-17=UInt8(}} {{25-25=)}}
398398
}
399399
}
400400

test/Generics/deduction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) {
2222

2323
// Deduction where the result type and input type can get different results
2424
var xx : X, yy : Y
25-
xx = identity(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
25+
xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}}
2626
xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
2727
}
2828

test/ModuleInterface/Inputs/opaque-result-types-client.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ struct YourFoo: Foo {}
1717
func someTypeIsTheSame() {
1818
var a = foo(0)
1919
a = foo(0)
20-
a = foo("") // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
20+
a = foo("") // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
2121

2222
var b = foo("")
23-
b = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'String'}}
23+
b = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
2424
b = foo("")
2525

2626
var c = foo(MyFoo())
27-
c = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'MyFoo'}}
27+
c = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
2828
c = foo(MyFoo())
2929
c = foo(YourFoo()) // expected-error{{cannot convert value of type 'YourFoo' to expected argument type 'MyFoo'}}
3030

0 commit comments

Comments
 (0)