Skip to content

Commit e974958

Browse files
committed
---
yaml --- r: 349560 b: refs/heads/master-next c: 27decb6 h: refs/heads/master
1 parent d352ec0 commit e974958

File tree

5 files changed

+106
-52
lines changed

5 files changed

+106
-52
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: 56dde70520abf96966d6f2c5829f92f0437bb41d
3+
refs/heads/master-next: 27decb6b7869bedeb4f7275995f5981eba167cd2
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/lib/Sema/CSGen.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,10 +2757,25 @@ namespace {
27572757
}
27582758
return TupleType::get(destTupleTypes, CS.getASTContext());
27592759
} else {
2760-
Type destTy = CS.createTypeVariable(CS.getConstraintLocator(expr),
2761-
TVO_CanBindToNoEscape);
2762-
CS.addConstraint(ConstraintKind::Bind, LValueType::get(destTy), CS.getType(expr),
2763-
CS.getConstraintLocator(expr));
2760+
auto *locator = CS.getConstraintLocator(expr);
2761+
2762+
auto isOrCanBeLValueType = [](Type type) {
2763+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
2764+
return typeVar->getImpl().canBindToLValue();
2765+
}
2766+
return type->is<LValueType>();
2767+
};
2768+
2769+
auto exprType = CS.getType(expr);
2770+
if (!isOrCanBeLValueType(exprType)) {
2771+
// Pretend that destination is an l-value type.
2772+
exprType = LValueType::get(exprType);
2773+
(void)CS.recordFix(TreatRValueAsLValue::create(CS, locator));
2774+
}
2775+
2776+
auto *destTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape);
2777+
CS.addConstraint(ConstraintKind::Bind, LValueType::get(destTy),
2778+
exprType, locator);
27642779
return destTy;
27652780
}
27662781
}

branches/master-next/lib/Sema/CSSimplify.cpp

Lines changed: 81 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,7 +2301,8 @@ repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
23012301
/// \return true if at least some of the failures has been repaired
23022302
/// successfully, which allows type matcher to continue.
23032303
bool ConstraintSystem::repairFailures(
2304-
Type lhs, Type rhs, SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2304+
Type lhs, Type rhs, ConstraintKind matchKind,
2305+
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
23052306
ConstraintLocatorBuilder locator) {
23062307
SmallVector<LocatorPathElt, 4> path;
23072308
auto *anchor = locator.getLocatorParts(path);
@@ -2385,10 +2386,43 @@ bool ConstraintSystem::repairFailures(
23852386
return true;
23862387
};
23872388

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+
23882415
if (path.empty()) {
23892416
if (!anchor)
23902417
return false;
23912418

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+
23922426
// If method reference forms a value type of the key path,
23932427
// there is going to be a constraint to match result of the
23942428
// member lookup to the generic parameter `V` of *KeyPath<R, V>
@@ -2463,6 +2497,18 @@ bool ConstraintSystem::repairFailures(
24632497
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
24642498
break;
24652499

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+
24662512
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
24672513
conversionsOrFixes.push_back(
24682514
ForceOptional::create(*this, lhs, lhs->getOptionalObjectType(), loc));
@@ -2487,6 +2533,7 @@ bool ConstraintSystem::repairFailures(
24872533
},
24882534
rhs)) {
24892535
conversionsOrFixes.push_back(fix);
2536+
break;
24902537
}
24912538

24922539
// If argument in l-value type and parameter is `inout` or a pointer,
@@ -2498,25 +2545,28 @@ bool ConstraintSystem::repairFailures(
24982545
ConstraintKind::ArgumentConversion,
24992546
TypeMatchFlags::TMF_ApplyingFix, locator);
25002547

2501-
if (result.isSuccess())
2548+
if (result.isSuccess()) {
25022549
conversionsOrFixes.push_back(AddAddressOf::create(
25032550
*this, lhs, rhs, getConstraintLocator(locator)));
2551+
break;
2552+
}
25042553
}
25052554

25062555
// If the argument is inout and the parameter is not inout or a pointer,
25072556
// suggest removing the &.
25082557
if (lhs->is<InOutType>() && !rhs->is<InOutType>()) {
25092558
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+
}
25202570
}
25212571

25222572
break;
@@ -2682,7 +2732,15 @@ bool ConstraintSystem::repairFailures(
26822732
break;
26832733
}
26842734

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+
26862744
// `apply argument` -> `arg/param compare` ->
26872745
// `@autoclosure result` -> `function result`
26882746
if (path.size() > 3) {
@@ -2737,6 +2795,13 @@ bool ConstraintSystem::repairFailures(
27372795
break;
27382796
}
27392797

2798+
case ConstraintLocator::SubscriptMember: {
2799+
if (repairByTreatingRValueAsLValue(lhs, rhs))
2800+
break;
2801+
2802+
break;
2803+
}
2804+
27402805
default:
27412806
break;
27422807
}
@@ -3527,25 +3592,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
35273592
getConstraintLocator(locator)));
35283593
}
35293594
}
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)));
35443595
}
35453596

35463597
// Attempt to repair any failures identifiable at this point.
35473598
if (attemptFixes) {
3548-
if (repairFailures(type1, type2, conversionsOrFixes, locator)) {
3599+
if (repairFailures(type1, type2, kind, conversionsOrFixes, locator)) {
35493600
if (conversionsOrFixes.empty())
35503601
return getTypeMatchSuccess();
35513602
}
@@ -5082,6 +5133,7 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
50825133
// overload here, that would help if such subscript has
50835134
// not been provided.
50845135
case MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember:
5136+
return TreatRValueAsLValue::create(cs, cs.getConstraintLocator(locator));
50855137
case MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember:
50865138
break;
50875139
case MemberLookupResult::UR_KeyPathWithAnyObjectRootType:
@@ -7343,20 +7395,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
73437395
return result;
73447396
}
73457397

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-
73607398
case FixKind::AutoClosureForwarding: {
73617399
if (recordFix(fix))
73627400
return SolutionKind::Error;
@@ -7406,6 +7444,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
74067444
case FixKind::RemoveReturn:
74077445
case FixKind::AddConformance:
74087446
case FixKind::RemoveAddressOf:
7447+
case FixKind::TreatRValueAsLValue:
74097448
case FixKind::SkipSameTypeRequirement:
74107449
case FixKind::SkipSuperclassRequirement:
74117450
case FixKind::AddMissingArguments:

branches/master-next/lib/Sema/ConstraintSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2778,7 +2778,7 @@ class ConstraintSystem {
27782778
/// Attempt to repair typing failures and record fixes if needed.
27792779
/// \return true if at least some of the failures has been repaired
27802780
/// successfully, which allows type matcher to continue.
2781-
bool repairFailures(Type lhs, Type rhs,
2781+
bool repairFailures(Type lhs, Type rhs, ConstraintKind matchKind,
27822782
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
27832783
ConstraintLocatorBuilder locator);
27842784

branches/master-next/test/stmt/statements.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ func funcdecl5(_ a: Int, y: Int) {
3939
x = y
4040
(x) = y
4141

42-
1 = x // expected-error {{cannot assign to a literal value}}
43-
(1) = x // expected-error {{cannot assign to a literal value}}
44-
"string" = "other" // expected-error {{cannot assign to a literal value}}
42+
1 = x // expected-error {{cannot assign to value: literals are not mutable}}
43+
(1) = x // expected-error {{cannot assign to value: literals are not mutable}}
44+
"string" = "other" // expected-error {{cannot assign to value: literals are not mutable}}
4545
[1, 1, 1, 1] = [1, 1] // expected-error {{cannot assign to immutable expression of type '[Int]}}
4646
1.0 = x // expected-error {{cannot assign to a literal value}}
47-
nil = 1 // expected-error {{cannot assign to a literal value}}
47+
nil = 1 // expected-error {{cannot assign to value: literals are not mutable}}
4848

4949
(x:1).x = 1 // expected-error {{cannot assign to immutable expression of type 'Int'}}
5050
var tup : (x:Int, y:Int)

0 commit comments

Comments
 (0)