Skip to content

Commit f92b43e

Browse files
authored
Merge pull request #22563 from xedin/rdar-47967277-5.0
[5.0][CSBindings] Preserve l-valueness of optional object type
2 parents 856fec7 + a399b71 commit f92b43e

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,14 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
350350
"not a representative");
351351
assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type");
352352

353+
// Determines whether this type variable represents an object
354+
// of the optional type extracted by force unwrap.
355+
bool isOptionalObject = false;
356+
if (auto *locator = typeVar->getImpl().getLocator()) {
357+
auto *anchor = locator->getAnchor();
358+
isOptionalObject = anchor && isa<ForceValueExpr>(anchor);
359+
}
360+
353361
// Gather the constraints associated with this type variable.
354362
llvm::SetVector<Constraint *> constraints;
355363
getConstraintGraph().gatherConstraints(
@@ -401,6 +409,18 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
401409
if (exactTypes.insert(type->getCanonicalType()).second) {
402410
result.addPotentialBinding(*binding);
403411

412+
// Result of force unwrap is always connected to its base
413+
// optional type via `OptionalObject` constraint which
414+
// preserves l-valueness, so in case where object type got
415+
// inferred before optional type (because it got the
416+
// type from context e.g. parameter type of a function call),
417+
// we need to test type with and without l-value after
418+
// delaying bindings for as long as possible.
419+
if (isOptionalObject && !type->is<LValueType>()) {
420+
result.FullyBound = true;
421+
result.PotentiallyIncomplete = true;
422+
}
423+
404424
if (auto *locator = typeVar->getImpl().getLocator()) {
405425
auto path = locator->getPath();
406426
auto voidType = getASTContext().TheEmptyTupleType;

test/Constraints/optional.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,34 @@ func rdar45218255(_ i: Int) {
302302
_ = [i!] // expected-error {{cannot force unwrap value of non-optional type 'Int'}} {{9-10=}}
303303
_ = S<Int>([i!]) // expected-error {{cannot force unwrap value of non-optional type 'Int'}} {{16-17=}}
304304
}
305+
306+
// rdar://problem/47967277 - cannot assign through '!': '$0' is immutable
307+
func sr_9893_1() {
308+
func foo<T : Equatable>(_: @autoclosure () throws -> T,
309+
_: @autoclosure () throws -> T) {}
310+
311+
class A {
312+
var bar: String?
313+
}
314+
315+
let r1 = A()
316+
let r2 = A()
317+
318+
let arr1: [A] = []
319+
foo(Set(arr1.map { $0.bar! }), Set([r1, r2].map { $0.bar! })) // Ok
320+
}
321+
322+
func sr_9893_2(cString: UnsafePointer<CChar>) {
323+
struct S {
324+
var a: Int32 = 0
325+
var b = ContiguousArray<CChar>(repeating: 0, count: 10)
326+
}
327+
328+
var s = S()
329+
330+
withUnsafeMutablePointer(to: &s.a) { ptrA in
331+
s.b.withUnsafeMutableBufferPointer { bufferB in
332+
withVaList([ptrA, bufferB.baseAddress!]) { ptr in } // Ok
333+
}
334+
}
335+
}

0 commit comments

Comments
 (0)