Skip to content

Commit 16244b3

Browse files
authored
Merge pull request #76439 from xedin/delay-implicit-pointer-conversions-for-unknown-inout
[CSSimplify] Delay `inout` type to pointer conversion until `inout` is sufficiently resolved
2 parents 0fc7fc6 + 279ef7d commit 16244b3

File tree

6 files changed

+63
-24
lines changed

6 files changed

+63
-24
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,23 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
14841484
AdjacentVars.insert({typeVar, constraint});
14851485
}
14861486

1487+
// Infer a binding from `inout $T <convertible to> Unsafe*Pointer<...>?`.
1488+
if (first->is<InOutType>() &&
1489+
first->getInOutObjectType()->isEqual(TypeVar)) {
1490+
if (auto pointeeTy = second->lookThroughAllOptionalTypes()
1491+
->getAnyPointerElementType()) {
1492+
if (!pointeeTy->isTypeVariableOrMember()) {
1493+
// The binding is as a fallback in this case because $T could
1494+
// also be Array<X> or C-style pointer.
1495+
if (constraint->getKind() >= ConstraintKind::ArgumentConversion)
1496+
DelayedBy.push_back(constraint);
1497+
1498+
return PotentialBinding(pointeeTy, AllowedBindingKind::Exact,
1499+
constraint);
1500+
}
1501+
}
1502+
}
1503+
14871504
return std::nullopt;
14881505
}
14891506

lib/Sema/CSSimplify.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7683,15 +7683,16 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
76837683
// scalar or array.
76847684
if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) {
76857685
if (!isAutoClosureArgument) {
7686-
auto inoutBaseType = inoutType1->getInOutObjectType();
7686+
auto inoutBaseType = getFixedTypeRecursive(
7687+
inoutType1->getInOutObjectType(), /*wantRValue=*/true);
76877688

7688-
auto baseIsArray =
7689-
getFixedTypeRecursive(inoutBaseType, /*wantRValue=*/true)
7690-
->isArrayType();
7689+
// Wait until the base type of `inout` is sufficiently resolved
7690+
// before making any assessments regarding conversions.
7691+
if (inoutBaseType->isTypeVariableOrMember())
7692+
return formUnsolvedResult();
7693+
7694+
auto baseIsArray = inoutBaseType->isArrayType();
76917695

7692-
// FIXME: If the base is still a type variable, we can't tell
7693-
// what to do here. Might have to try \c ArrayToPointer and make
7694-
// it more robust.
76957696
if (baseIsArray)
76967697
conversionsOrFixes.push_back(
76977698
ConversionRestrictionKind::ArrayToPointer);

test/Constraints/optional.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -478,20 +478,17 @@ func rdar75146811() {
478478

479479
var arr: [Double]! = []
480480

481-
test(&arr) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
481+
test(&arr) // Ok
482482
test((&arr)) // expected-error {{'&' may only be used to pass an argument to inout parameter}}
483-
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
484-
test(&(arr)) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
483+
test(&(arr)) // Ok
485484

486-
test_tuple(&arr, x: 0) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
485+
test_tuple(&arr, x: 0) // Ok
487486
test_tuple((&arr), x: 0) // expected-error {{'&' may only be used to pass an argument to inout parameter}}
488-
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
489-
test_tuple(&(arr), x: 0) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
487+
test_tuple(&(arr), x: 0) // Ok
490488

491-
test_named(x: &arr) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
489+
test_named(x: &arr) // Ok
492490
test_named(x: (&arr)) // expected-error {{'&' may only be used to pass an argument to inout parameter}}
493-
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
494-
test_named(x: &(arr)) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
491+
test_named(x: &(arr)) // Ok
495492
}
496493

497494
// rdar://75514153 - Unable to produce a diagnostic for ambiguities related to use of `nil`

test/Constraints/valid_pointer_conversions.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,21 @@ do {
5151
func rdar68254165(ptr: UnsafeMutablePointer<Int8>) {
5252
_ = String(decodingCString: ptr, as: .utf8) // expected-error {{generic parameter 'Encoding' could not be inferred}}
5353
}
54+
55+
// The base of leading-dot syntax could be inferred through an implicit pointer conversion.
56+
do {
57+
struct S {
58+
static var prop = S()
59+
}
60+
61+
func inference_through_optional(_ ptr: UnsafePointer<S>?) {}
62+
63+
inference_through_optional(&.prop) // Ok
64+
65+
func inference_through_force_unwrap(name: String) {
66+
func test(_: UnsafeMutablePointer<Float>!) {}
67+
68+
var outputs = [String: [Float]]()
69+
test(&outputs[name]!) // Ok
70+
}
71+
}

test/Sema/diag_non_ephemeral.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,10 @@ takesMutableRaw(&ResilientStruct.staticStoredProperty, 5) // expected-error {{ca
198198
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw'}}
199199
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
200200

201-
// FIXME: This should also produce an error.
202-
takesMutableRaw(&type(of: topLevelResilientS).staticStoredProperty, 5)
201+
202+
takesMutableRaw(&type(of: topLevelResilientS).staticStoredProperty, 5) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesMutableRaw'}}
203+
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw'}}
204+
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
203205

204206
// - Resilient struct or class bases
205207

@@ -221,8 +223,10 @@ takesRaw(&topLevelP.property) // expected-error {{cannot use inout expression he
221223
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}
222224
// expected-note@-2 {{use 'withUnsafeBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
223225

224-
// FIXME: This should also produce an error.
225-
takesRaw(&type(of: topLevelP).staticProperty)
226+
227+
takesRaw(&type(of: topLevelP).staticProperty) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesRaw'}}
228+
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}
229+
// expected-note@-2 {{use 'withUnsafeBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
226230

227231
takesRaw(&topLevelP[]) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesRaw'}}
228232
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}

test/Sema/diag_non_ephemeral_warning.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ takesMutableRaw(&ResilientStruct.staticStoredProperty, 5) // expected-warning {{
198198
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw'}}
199199
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
200200

201-
// FIXME: This should also produce a warning.
202-
takesMutableRaw(&type(of: topLevelResilientS).staticStoredProperty, 5)
201+
takesMutableRaw(&type(of: topLevelResilientS).staticStoredProperty, 5) // expected-warning {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesMutableRaw'}}
202+
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw'}}
203+
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
203204

204205
// - Resilient struct or class bases
205206

@@ -221,8 +222,9 @@ takesRaw(&topLevelP.property) // expected-warning {{cannot use inout expression
221222
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}
222223
// expected-note@-2 {{use 'withUnsafeBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
223224

224-
// FIXME: This should also produce a warning.
225-
takesRaw(&type(of: topLevelP).staticProperty)
225+
takesRaw(&type(of: topLevelP).staticProperty) // expected-warning {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesRaw'}}
226+
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}
227+
// expected-note@-2 {{use 'withUnsafeBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
226228

227229
takesRaw(&topLevelP[]) // expected-warning {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesRaw'}}
228230
// expected-note@-1 {{implicit argument conversion from 'Int8' to 'UnsafeRawPointer' produces a pointer valid only for the duration of the call to 'takesRaw'}}

0 commit comments

Comments
 (0)