@@ -2291,7 +2291,8 @@ repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
2291
2291
// / \return true if at least some of the failures has been repaired
2292
2292
// / successfully, which allows type matcher to continue.
2293
2293
bool ConstraintSystem::repairFailures (
2294
- Type lhs, Type rhs, SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2294
+ Type lhs, Type rhs, ConstraintKind matchKind,
2295
+ SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2295
2296
ConstraintLocatorBuilder locator) {
2296
2297
SmallVector<LocatorPathElt, 4 > path;
2297
2298
auto *anchor = locator.getLocatorParts (path);
@@ -2375,10 +2376,43 @@ bool ConstraintSystem::repairFailures(
2375
2376
return true ;
2376
2377
};
2377
2378
2379
+ auto repairByTreatingRValueAsLValue = [&](Type lhs, Type rhs) -> bool {
2380
+ if (!lhs->is <LValueType>() &&
2381
+ (rhs->is <LValueType>() || rhs->is <InOutType>())) {
2382
+ // Conversion from l-value to inout in an operator argument
2383
+ // position (which doesn't require explicit `&`) decays into
2384
+ // a `Bind` of involved object types, same goes for explicit
2385
+ // `&` conversion from l-value to inout type.
2386
+ auto kind = (isa<InOutExpr>(anchor) ||
2387
+ (rhs->is <InOutType>() &&
2388
+ matchKind == ConstraintKind::OperatorArgumentConversion))
2389
+ ? ConstraintKind::Bind
2390
+ : matchKind;
2391
+
2392
+ auto result = matchTypes (lhs, rhs->getWithoutSpecifierType (), kind,
2393
+ TMF_ApplyingFix, locator);
2394
+
2395
+ if (result.isSuccess ()) {
2396
+ conversionsOrFixes.push_back (
2397
+ TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
2398
+ return true ;
2399
+ }
2400
+ }
2401
+
2402
+ return false ;
2403
+ };
2404
+
2378
2405
if (path.empty ()) {
2379
2406
if (!anchor)
2380
2407
return false ;
2381
2408
2409
+ // This could be:
2410
+ // - `InOutExpr` used with r-value e.g. `foo(&x)` where `x` is a `let`.
2411
+ // - `ForceValueExpr` e.g. `foo.bar! = 42` where `bar` or `foo` are
2412
+ // immutable or a subscript e.g. `foo["bar"]! = 42`.
2413
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2414
+ return true ;
2415
+
2382
2416
// If method reference forms a value type of the key path,
2383
2417
// there is going to be a constraint to match result of the
2384
2418
// member lookup to the generic parameter `V` of *KeyPath<R, V>
@@ -2453,6 +2487,18 @@ bool ConstraintSystem::repairFailures(
2453
2487
if (repairViaBridgingCast (*this , lhs, rhs, conversionsOrFixes, locator))
2454
2488
break ;
2455
2489
2490
+ // Argument is a r-value but parameter expects an l-value e.g.
2491
+ //
2492
+ // func foo(_ x: inout Int) {}
2493
+ // let x: Int = 42
2494
+ // foo(x) // `x` can't be converted to `inout Int`.
2495
+ //
2496
+ // This has to happen before checking for optionality mismatch
2497
+ // because otherwise `Int? arg conv inout Int` is going to get
2498
+ // fixed as 2 fixes - "force unwrap" + r-value -> l-value mismatch.
2499
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2500
+ break ;
2501
+
2456
2502
if (lhs->getOptionalObjectType () && !rhs->getOptionalObjectType ()) {
2457
2503
conversionsOrFixes.push_back (
2458
2504
ForceOptional::create (*this , lhs, lhs->getOptionalObjectType (), loc));
@@ -2477,6 +2523,7 @@ bool ConstraintSystem::repairFailures(
2477
2523
},
2478
2524
rhs)) {
2479
2525
conversionsOrFixes.push_back (fix);
2526
+ break ;
2480
2527
}
2481
2528
2482
2529
// If argument in l-value type and parameter is `inout` or a pointer,
@@ -2488,25 +2535,28 @@ bool ConstraintSystem::repairFailures(
2488
2535
ConstraintKind::ArgumentConversion,
2489
2536
TypeMatchFlags::TMF_ApplyingFix, locator);
2490
2537
2491
- if (result.isSuccess ())
2538
+ if (result.isSuccess ()) {
2492
2539
conversionsOrFixes.push_back (AddAddressOf::create (
2493
2540
*this , lhs, rhs, getConstraintLocator (locator)));
2541
+ break ;
2542
+ }
2494
2543
}
2495
2544
2496
2545
// If the argument is inout and the parameter is not inout or a pointer,
2497
2546
// suggest removing the &.
2498
2547
if (lhs->is <InOutType>() && !rhs->is <InOutType>()) {
2499
2548
auto objectType = rhs->lookThroughAllOptionalTypes ();
2500
- if (objectType->getAnyPointerElementType ())
2501
- break ;
2502
-
2503
- auto result = matchTypes (lhs->getInOutObjectType (), rhs,
2504
- ConstraintKind::ArgumentConversion,
2505
- TypeMatchFlags::TMF_ApplyingFix, locator);
2506
-
2507
- if (result.isSuccess ())
2508
- conversionsOrFixes.push_back (RemoveAddressOf::create (*this , lhs,
2509
- rhs, getConstraintLocator (locator)));
2549
+ if (!objectType->getAnyPointerElementType ()) {
2550
+ auto result = matchTypes (lhs->getInOutObjectType (), rhs,
2551
+ ConstraintKind::ArgumentConversion,
2552
+ TypeMatchFlags::TMF_ApplyingFix, locator);
2553
+
2554
+ if (result.isSuccess ()) {
2555
+ conversionsOrFixes.push_back (RemoveAddressOf::create (
2556
+ *this , lhs, rhs, getConstraintLocator (locator)));
2557
+ break ;
2558
+ }
2559
+ }
2510
2560
}
2511
2561
2512
2562
break ;
@@ -2672,7 +2722,15 @@ bool ConstraintSystem::repairFailures(
2672
2722
break ;
2673
2723
}
2674
2724
2675
- case ConstraintLocator::FunctionResult: {
2725
+ case ConstraintLocator::Member:
2726
+ case ConstraintLocator::FunctionResult:
2727
+ case ConstraintLocator::DynamicLookupResult: {
2728
+ // Most likely this is an attempt to use get-only subscript as mutating,
2729
+ // or assign a value of a result of function/member ref e.g. `foo() = 42`
2730
+ // or `foo.bar = 42`, or `foo.bar()! = 42`.
2731
+ if (repairByTreatingRValueAsLValue (rhs, lhs))
2732
+ break ;
2733
+
2676
2734
// `apply argument` -> `arg/param compare` ->
2677
2735
// `@autoclosure result` -> `function result`
2678
2736
if (path.size () > 3 ) {
@@ -2727,6 +2785,13 @@ bool ConstraintSystem::repairFailures(
2727
2785
break ;
2728
2786
}
2729
2787
2788
+ case ConstraintLocator::SubscriptMember: {
2789
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2790
+ break ;
2791
+
2792
+ break ;
2793
+ }
2794
+
2730
2795
default :
2731
2796
break ;
2732
2797
}
@@ -3517,25 +3582,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
3517
3582
getConstraintLocator (locator)));
3518
3583
}
3519
3584
}
3520
-
3521
- if (!type1->is <LValueType>() && type2->is <InOutType>()) {
3522
- // If we have a concrete type that's an rvalue, "fix" it.
3523
- conversionsOrFixes.push_back (
3524
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3525
- }
3526
- }
3527
-
3528
- if (attemptFixes && type2->is <LValueType>()) {
3529
- conversionsOrFixes.push_back (
3530
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3531
- } else if (attemptFixes && kind == ConstraintKind::Bind && type1->is <LValueType>()) {
3532
- conversionsOrFixes.push_back (
3533
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3534
3585
}
3535
3586
3536
3587
// Attempt to repair any failures identifiable at this point.
3537
3588
if (attemptFixes) {
3538
- if (repairFailures (type1, type2, conversionsOrFixes, locator)) {
3589
+ if (repairFailures (type1, type2, kind, conversionsOrFixes, locator)) {
3539
3590
if (conversionsOrFixes.empty ())
3540
3591
return getTypeMatchSuccess ();
3541
3592
}
@@ -5055,6 +5106,7 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
5055
5106
// overload here, that would help if such subscript has
5056
5107
// not been provided.
5057
5108
case MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember:
5109
+ return TreatRValueAsLValue::create (cs, cs.getConstraintLocator (locator));
5058
5110
case MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember:
5059
5111
break ;
5060
5112
case MemberLookupResult::UR_KeyPathWithAnyObjectRootType:
@@ -7238,20 +7290,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
7238
7290
return result;
7239
7291
}
7240
7292
7241
- case FixKind::TreatRValueAsLValue: {
7242
- if (type2->is <LValueType>() || type2->is <InOutType>())
7243
- type1 = LValueType::get (type1);
7244
- else
7245
- type2 = LValueType::get (type2);
7246
- auto result = matchTypes (type1, type2,
7247
- matchKind, subflags, locator);
7248
- if (result == SolutionKind::Solved)
7249
- if (recordFix (fix))
7250
- return SolutionKind::Error;
7251
-
7252
- return result;
7253
- }
7254
-
7255
7293
case FixKind::AutoClosureForwarding: {
7256
7294
if (recordFix (fix))
7257
7295
return SolutionKind::Error;
@@ -7301,6 +7339,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
7301
7339
case FixKind::RemoveReturn:
7302
7340
case FixKind::AddConformance:
7303
7341
case FixKind::RemoveAddressOf:
7342
+ case FixKind::TreatRValueAsLValue:
7304
7343
case FixKind::SkipSameTypeRequirement:
7305
7344
case FixKind::SkipSuperclassRequirement:
7306
7345
case FixKind::AddMissingArguments:
0 commit comments