@@ -2301,7 +2301,8 @@ repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
2301
2301
// / \return true if at least some of the failures has been repaired
2302
2302
// / successfully, which allows type matcher to continue.
2303
2303
bool ConstraintSystem::repairFailures (
2304
- Type lhs, Type rhs, SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2304
+ Type lhs, Type rhs, ConstraintKind matchKind,
2305
+ SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2305
2306
ConstraintLocatorBuilder locator) {
2306
2307
SmallVector<LocatorPathElt, 4 > path;
2307
2308
auto *anchor = locator.getLocatorParts (path);
@@ -2385,10 +2386,43 @@ bool ConstraintSystem::repairFailures(
2385
2386
return true ;
2386
2387
};
2387
2388
2389
+ auto repairByTreatingRValueAsLValue = [&](Type lhs, Type rhs) -> bool {
2390
+ if (!lhs->is <LValueType>() &&
2391
+ (rhs->is <LValueType>() || rhs->is <InOutType>())) {
2392
+ // Conversion from l-value to inout in an operator argument
2393
+ // position (which doesn't require explicit `&`) decays into
2394
+ // a `Bind` of involved object types, same goes for explicit
2395
+ // `&` conversion from l-value to inout type.
2396
+ auto kind = (isa<InOutExpr>(anchor) ||
2397
+ (rhs->is <InOutType>() &&
2398
+ matchKind == ConstraintKind::OperatorArgumentConversion))
2399
+ ? ConstraintKind::Bind
2400
+ : matchKind;
2401
+
2402
+ auto result = matchTypes (lhs, rhs->getWithoutSpecifierType (), kind,
2403
+ TMF_ApplyingFix, locator);
2404
+
2405
+ if (result.isSuccess ()) {
2406
+ conversionsOrFixes.push_back (
2407
+ TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
2408
+ return true ;
2409
+ }
2410
+ }
2411
+
2412
+ return false ;
2413
+ };
2414
+
2388
2415
if (path.empty ()) {
2389
2416
if (!anchor)
2390
2417
return false ;
2391
2418
2419
+ // This could be:
2420
+ // - `InOutExpr` used with r-value e.g. `foo(&x)` where `x` is a `let`.
2421
+ // - `ForceValueExpr` e.g. `foo.bar! = 42` where `bar` or `foo` are
2422
+ // immutable or a subscript e.g. `foo["bar"]! = 42`.
2423
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2424
+ return true ;
2425
+
2392
2426
// If method reference forms a value type of the key path,
2393
2427
// there is going to be a constraint to match result of the
2394
2428
// member lookup to the generic parameter `V` of *KeyPath<R, V>
@@ -2463,6 +2497,18 @@ bool ConstraintSystem::repairFailures(
2463
2497
if (repairViaBridgingCast (*this , lhs, rhs, conversionsOrFixes, locator))
2464
2498
break ;
2465
2499
2500
+ // Argument is a r-value but parameter expects an l-value e.g.
2501
+ //
2502
+ // func foo(_ x: inout Int) {}
2503
+ // let x: Int = 42
2504
+ // foo(x) // `x` can't be converted to `inout Int`.
2505
+ //
2506
+ // This has to happen before checking for optionality mismatch
2507
+ // because otherwise `Int? arg conv inout Int` is going to get
2508
+ // fixed as 2 fixes - "force unwrap" + r-value -> l-value mismatch.
2509
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2510
+ break ;
2511
+
2466
2512
if (lhs->getOptionalObjectType () && !rhs->getOptionalObjectType ()) {
2467
2513
conversionsOrFixes.push_back (
2468
2514
ForceOptional::create (*this , lhs, lhs->getOptionalObjectType (), loc));
@@ -2487,6 +2533,7 @@ bool ConstraintSystem::repairFailures(
2487
2533
},
2488
2534
rhs)) {
2489
2535
conversionsOrFixes.push_back (fix);
2536
+ break ;
2490
2537
}
2491
2538
2492
2539
// If argument in l-value type and parameter is `inout` or a pointer,
@@ -2498,25 +2545,28 @@ bool ConstraintSystem::repairFailures(
2498
2545
ConstraintKind::ArgumentConversion,
2499
2546
TypeMatchFlags::TMF_ApplyingFix, locator);
2500
2547
2501
- if (result.isSuccess ())
2548
+ if (result.isSuccess ()) {
2502
2549
conversionsOrFixes.push_back (AddAddressOf::create (
2503
2550
*this , lhs, rhs, getConstraintLocator (locator)));
2551
+ break ;
2552
+ }
2504
2553
}
2505
2554
2506
2555
// If the argument is inout and the parameter is not inout or a pointer,
2507
2556
// suggest removing the &.
2508
2557
if (lhs->is <InOutType>() && !rhs->is <InOutType>()) {
2509
2558
auto objectType = rhs->lookThroughAllOptionalTypes ();
2510
- if (objectType->getAnyPointerElementType ())
2511
- break ;
2512
-
2513
- auto result = matchTypes (lhs->getInOutObjectType (), rhs,
2514
- ConstraintKind::ArgumentConversion,
2515
- TypeMatchFlags::TMF_ApplyingFix, locator);
2516
-
2517
- if (result.isSuccess ())
2518
- conversionsOrFixes.push_back (RemoveAddressOf::create (*this , lhs,
2519
- rhs, getConstraintLocator (locator)));
2559
+ if (!objectType->getAnyPointerElementType ()) {
2560
+ auto result = matchTypes (lhs->getInOutObjectType (), rhs,
2561
+ ConstraintKind::ArgumentConversion,
2562
+ TypeMatchFlags::TMF_ApplyingFix, locator);
2563
+
2564
+ if (result.isSuccess ()) {
2565
+ conversionsOrFixes.push_back (RemoveAddressOf::create (
2566
+ *this , lhs, rhs, getConstraintLocator (locator)));
2567
+ break ;
2568
+ }
2569
+ }
2520
2570
}
2521
2571
2522
2572
break ;
@@ -2682,7 +2732,15 @@ bool ConstraintSystem::repairFailures(
2682
2732
break ;
2683
2733
}
2684
2734
2685
- case ConstraintLocator::FunctionResult: {
2735
+ case ConstraintLocator::Member:
2736
+ case ConstraintLocator::FunctionResult:
2737
+ case ConstraintLocator::DynamicLookupResult: {
2738
+ // Most likely this is an attempt to use get-only subscript as mutating,
2739
+ // or assign a value of a result of function/member ref e.g. `foo() = 42`
2740
+ // or `foo.bar = 42`, or `foo.bar()! = 42`.
2741
+ if (repairByTreatingRValueAsLValue (rhs, lhs))
2742
+ break ;
2743
+
2686
2744
// `apply argument` -> `arg/param compare` ->
2687
2745
// `@autoclosure result` -> `function result`
2688
2746
if (path.size () > 3 ) {
@@ -2737,6 +2795,13 @@ bool ConstraintSystem::repairFailures(
2737
2795
break ;
2738
2796
}
2739
2797
2798
+ case ConstraintLocator::SubscriptMember: {
2799
+ if (repairByTreatingRValueAsLValue (lhs, rhs))
2800
+ break ;
2801
+
2802
+ break ;
2803
+ }
2804
+
2740
2805
default :
2741
2806
break ;
2742
2807
}
@@ -3527,25 +3592,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
3527
3592
getConstraintLocator (locator)));
3528
3593
}
3529
3594
}
3530
-
3531
- if (!type1->is <LValueType>() && type2->is <InOutType>()) {
3532
- // If we have a concrete type that's an rvalue, "fix" it.
3533
- conversionsOrFixes.push_back (
3534
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3535
- }
3536
- }
3537
-
3538
- if (attemptFixes && type2->is <LValueType>()) {
3539
- conversionsOrFixes.push_back (
3540
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3541
- } else if (attemptFixes && kind == ConstraintKind::Bind && type1->is <LValueType>()) {
3542
- conversionsOrFixes.push_back (
3543
- TreatRValueAsLValue::create (*this , getConstraintLocator (locator)));
3544
3595
}
3545
3596
3546
3597
// Attempt to repair any failures identifiable at this point.
3547
3598
if (attemptFixes) {
3548
- if (repairFailures (type1, type2, conversionsOrFixes, locator)) {
3599
+ if (repairFailures (type1, type2, kind, conversionsOrFixes, locator)) {
3549
3600
if (conversionsOrFixes.empty ())
3550
3601
return getTypeMatchSuccess ();
3551
3602
}
@@ -5082,6 +5133,7 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
5082
5133
// overload here, that would help if such subscript has
5083
5134
// not been provided.
5084
5135
case MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember:
5136
+ return TreatRValueAsLValue::create (cs, cs.getConstraintLocator (locator));
5085
5137
case MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember:
5086
5138
break ;
5087
5139
case MemberLookupResult::UR_KeyPathWithAnyObjectRootType:
@@ -7343,20 +7395,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
7343
7395
return result;
7344
7396
}
7345
7397
7346
- case FixKind::TreatRValueAsLValue: {
7347
- if (type2->is <LValueType>() || type2->is <InOutType>())
7348
- type1 = LValueType::get (type1);
7349
- else
7350
- type2 = LValueType::get (type2);
7351
- auto result = matchTypes (type1, type2,
7352
- matchKind, subflags, locator);
7353
- if (result == SolutionKind::Solved)
7354
- if (recordFix (fix))
7355
- return SolutionKind::Error;
7356
-
7357
- return result;
7358
- }
7359
-
7360
7398
case FixKind::AutoClosureForwarding: {
7361
7399
if (recordFix (fix))
7362
7400
return SolutionKind::Error;
@@ -7406,6 +7444,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
7406
7444
case FixKind::RemoveReturn:
7407
7445
case FixKind::AddConformance:
7408
7446
case FixKind::RemoveAddressOf:
7447
+ case FixKind::TreatRValueAsLValue:
7409
7448
case FixKind::SkipSameTypeRequirement:
7410
7449
case FixKind::SkipSuperclassRequirement:
7411
7450
case FixKind::AddMissingArguments:
0 commit comments