Skip to content

Commit e9aa04a

Browse files
committed
[ConstraintSystem] Extend generic argument mismatch fix to all pointer conversions
This makes it possible to diagnose all implicit pointer conversions in argument positions with a better error message which preserves enclosing types, and allows to share base type matching logic across all pointer conversions.
1 parent c16b888 commit e9aa04a

File tree

4 files changed

+77
-45
lines changed

4 files changed

+77
-45
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,8 +2558,15 @@ bool ConstraintSystem::repairFailures(
25582558
// `&`.
25592559
if (lhs->is<LValueType>() &&
25602560
(rhs->is<InOutType>() || rhs->getAnyPointerElementType())) {
2561-
auto result = matchTypes(InOutType::get(lhs->getRValueType()), rhs,
2562-
ConstraintKind::ArgumentConversion,
2561+
auto baseType = rhs->is<InOutType>() ? rhs->getInOutObjectType()
2562+
: rhs->getAnyPointerElementType();
2563+
2564+
// Let's use `BindToPointer` constraint here to match up base types
2565+
// of implied `inout` argument and `inout` or pointer parameter.
2566+
// This helps us to avoid implicit conversions associated with
2567+
// `ArgumentConversion` constraint.
2568+
auto result = matchTypes(lhs->getRValueType(), baseType,
2569+
ConstraintKind::BindToPointerType,
25632570
TypeMatchFlags::TMF_ApplyingFix, locator);
25642571

25652572
if (result.isSuccess()) {
@@ -6958,6 +6965,44 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
69586965

69596966
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
69606967

6968+
auto matchPointerBaseTypes = [&](Type baseType1,
6969+
Type baseType2) -> SolutionKind {
6970+
if (restriction != ConversionRestrictionKind::PointerToPointer)
6971+
increaseScore(ScoreKind::SK_ValueToPointerConversion);
6972+
6973+
auto result =
6974+
matchTypes(baseType1, baseType2, ConstraintKind::BindToPointerType,
6975+
subflags, locator);
6976+
6977+
if (!(result.isFailure() && shouldAttemptFixes()))
6978+
return result;
6979+
6980+
BoundGenericType *ptr1 = nullptr;
6981+
BoundGenericType *ptr2 = nullptr;
6982+
6983+
switch (restriction) {
6984+
case ConversionRestrictionKind::ArrayToPointer:
6985+
case ConversionRestrictionKind::InoutToPointer: {
6986+
ptr2 = type2->lookThroughAllOptionalTypes()->castTo<BoundGenericType>();
6987+
ptr1 = BoundGenericType::get(ptr2->getDecl(), ptr2->getParent(),
6988+
{baseType1});
6989+
break;
6990+
}
6991+
6992+
case ConversionRestrictionKind::PointerToPointer:
6993+
ptr1 = type1->castTo<BoundGenericType>();
6994+
ptr2 = type2->castTo<BoundGenericType>();
6995+
break;
6996+
6997+
default:
6998+
return SolutionKind::Error;
6999+
}
7000+
7001+
auto *fix = GenericArgumentsMismatch::create(*this, ptr1, ptr2, {0},
7002+
getConstraintLocator(locator));
7003+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
7004+
};
7005+
69617006
switch (restriction) {
69627007
// for $< in { <, <c, <oc }:
69637008
// T_i $< U_i ===> (T_i...) $< (U_i...)
@@ -7077,23 +7122,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
70777122
auto baseType1 = getFixedTypeRecursive(*isArrayType(obj1), false);
70787123
auto baseType2 = getBaseTypeForPointer(*this, t2);
70797124

7080-
increaseScore(ScoreKind::SK_ValueToPointerConversion);
7081-
auto result = matchTypes(baseType1, baseType2,
7082-
ConstraintKind::BindToPointerType,
7083-
subflags, locator);
7084-
7085-
if (!(result.isFailure() && shouldAttemptFixes()))
7086-
return result;
7087-
7088-
auto *arrTy = obj1->getAs<BoundGenericType>();
7089-
// Let's dig out underlying pointer type since it could
7090-
// be wrapped into N (implicit) optionals.
7091-
auto *ptrTy =
7092-
type2->lookThroughAllOptionalTypes()->getAs<BoundGenericType>();
7093-
7094-
auto *fix = GenericArgumentsMismatch::create(*this, arrTy, ptrTy, {0},
7095-
getConstraintLocator(locator));
7096-
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
7125+
return matchPointerBaseTypes(baseType1, baseType2);
70977126
}
70987127

70997128
// String ===> UnsafePointer<[U]Int8>
@@ -7146,13 +7175,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
71467175

71477176
auto baseType1 = type1->getInOutObjectType();
71487177
auto baseType2 = getBaseTypeForPointer(*this, t2);
7149-
7150-
// Set up the disjunction for the array or scalar cases.
71517178

7152-
increaseScore(ScoreKind::SK_ValueToPointerConversion);
7153-
return matchTypes(baseType1, baseType2,
7154-
ConstraintKind::BindToPointerType,
7155-
subflags, locator);
7179+
return matchPointerBaseTypes(baseType1, baseType2);
71567180
}
71577181

71587182
// T <p U ===> UnsafeMutablePointer<T> <a UnsafeMutablePointer<U>
@@ -7162,10 +7186,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
71627186

71637187
Type baseType1 = getBaseTypeForPointer(*this, t1);
71647188
Type baseType2 = getBaseTypeForPointer(*this, t2);
7165-
7166-
return matchTypes(baseType1, baseType2,
7167-
ConstraintKind::BindToPointerType,
7168-
subflags, locator);
7189+
7190+
return matchPointerBaseTypes(baseType1, baseType2);
71697191
}
71707192

71717193
// T < U or T is bridged to V where V < U ===> Array<T> <c Array<U>

test/ClangImporter/objc_id_as_any.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ idLover.takesId(ArbitraryThing())
1717
var x: AnyObject = NSObject()
1818
idLover.takesArray(ofId: &x)
1919
var xAsAny = x as Any
20-
idLover.takesArray(ofId: &xAsAny) // expected-error{{argument type 'Any' does not conform to expected type 'AnyObject'}}
20+
idLover.takesArray(ofId: &xAsAny) // expected-error{{cannot convert value of type 'UnsafePointer<Any>' to expected argument type 'UnsafePointer<AnyObject>'}}
21+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Any' and 'AnyObject') are expected to be equal}}
2122

2223
var y: Any = NSObject()
23-
idLover.takesArray(ofId: &y) // expected-error{{argument type 'Any' does not conform to expected type 'AnyObject'}}
24+
idLover.takesArray(ofId: &y) // expected-error{{cannot convert value of type 'UnsafePointer<Any>' to expected argument type 'UnsafePointer<AnyObject>'}}
25+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Any' and 'AnyObject') are expected to be equal}}
2426

2527
idLover.takesId(x)
2628
idLover.takesId(y)

test/Parse/pointer_conversion.swift.gyb

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,20 @@ func mutablePointerArguments(_ p: UnsafeMutablePointer<Int>,
4848
var i: Int = 0
4949
var f: Float = 0
5050
takesMutablePointer(&i)
51-
takesMutablePointer(&f) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
51+
takesMutablePointer(&f) // expected-error{{cannot convert value of type 'UnsafeMutablePointer<Float>' to expected argument type 'UnsafeMutablePointer<Int>'}}
52+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal}}
5253
takesMutablePointer(i) // expected-error{{cannot convert value of type 'Int' to expected argument type 'UnsafeMutablePointer<Int>${diag_suffix}'}}
5354
takesMutablePointer(f) // expected-error{{cannot convert value of type 'Float' to expected argument type 'UnsafeMutablePointer<Int>${diag_suffix}'}}
5455
var ii: [Int] = [0, 1, 2]
5556
var ff: [Float] = [0, 1, 2]
5657
takesMutablePointer(&ii)
57-
takesMutablePointer(&ff) // expected-error{{cannot convert value of type 'Array<Float>' to expected argument type 'UnsafeMutablePointer<Int>'}}
58+
takesMutablePointer(&ff) // expected-error{{cannot convert value of type 'UnsafeMutablePointer<Float>' to expected argument type 'UnsafeMutablePointer<Int>'}}
5859
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal}}
5960
takesMutablePointer(ii) // expected-error{{cannot convert value of type '[Int]' to expected argument type 'UnsafeMutablePointer<Int>${diag_suffix}'}}
6061
takesMutablePointer(ff) // expected-error{{cannot convert value of type '[Float]' to expected argument type 'UnsafeMutablePointer<Int>${diag_suffix}'}}
6162

62-
takesMutableArrayPointer(&i) // expected-error{{cannot convert value of type 'Int' to expected argument type '[Int]'}}
63+
takesMutableArrayPointer(&i) // expected-error{{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<[Int]>'}}
64+
//expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and '[Int]') are expected to be equal}}
6365
takesMutableArrayPointer(&ii)
6466

6567
// We don't allow these conversions outside of function arguments.
@@ -149,14 +151,15 @@ func constPointerArguments(_ p: UnsafeMutablePointer<Int>,
149151
var i: Int = 0
150152
var f: Float = 0
151153
takesConstPointer(&i)
152-
takesConstPointer(&f) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
154+
takesConstPointer(&f) // expected-error{{cannot convert value of type 'UnsafePointer<Float>' to expected argument type 'UnsafePointer<Int>'}}
155+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal}}
153156
var ii: [Int] = [0, 1, 2]
154157
var ff: [Float] = [0, 1, 2]
155158
takesConstPointer(&ii)
156-
takesConstPointer(&ff) // expected-error{{cannot convert value of type 'Array<Float>' to expected argument type 'UnsafePointer<Int>'}}
159+
takesConstPointer(&ff) // expected-error{{cannot convert value of type 'UnsafePointer<Float>' to expected argument type 'UnsafePointer<Int>'}}
157160
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal}}
158161
takesConstPointer(ii)
159-
takesConstPointer(ff) // expected-error{{cannot convert value of type 'Array<Float>' to expected argument type 'UnsafePointer<Int>'}}
162+
takesConstPointer(ff) // expected-error{{cannot convert value of type 'UnsafePointer<Float>' to expected argument type 'UnsafePointer<Int>'}}
160163
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal}}
161164
takesConstPointer([0, 1, 2])
162165
// <rdar://problem/22308330> QoI: CSDiags doesn't handle array -> pointer impl conversions well
@@ -258,9 +261,11 @@ func stringArguments(_ s: String) {
258261
takesMutableVoidPointer(s) // expected-error{{cannot convert value of type 'String' to expected argument type 'UnsafeMutableRawPointer${diag_suffix}'}}
259262
takesMutableRawPointer(s) // expected-error{{cannot convert value of type 'String' to expected argument type 'UnsafeMutableRawPointer${diag_suffix}'}}
260263
takesMutableInt8Pointer(s) // expected-error{{cannot convert value of type 'String' to expected argument type 'UnsafeMutablePointer<Int8>${diag_suffix}'}}
261-
takesMutableInt8Pointer(&s) // expected-error{{cannot convert value of type 'String' to expected argument type 'Int8'}}
264+
takesMutableInt8Pointer(&s) // expected-error{{cannot convert value of type 'UnsafeMutablePointer<String>' to expected argument type 'UnsafeMutablePointer<Int8>'}}
265+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('String' and 'Int8') are expected to be equal}}
262266
takesMutablePointer(s) // expected-error{{cannot convert value of type 'String' to expected argument type 'UnsafeMutablePointer<Int>${diag_suffix}'}}
263-
takesMutablePointer(&s) // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
267+
takesMutablePointer(&s) // expected-error{{cannot convert value of type 'UnsafeMutablePointer<String>' to expected argument type 'UnsafeMutablePointer<Int>'}}
268+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('String' and 'Int') are expected to be equal}}
264269
}
265270

266271

@@ -319,7 +324,8 @@ func addressConversion(p: UnsafeMutablePointer<Int>, x: Int) {
319324
func f19478919() {
320325
var viewport: Int = 1 // intentionally incorrect type, not Int32
321326
func GLKProject(_ a : UnsafeMutablePointer<Int32>) {}
322-
GLKProject(&viewport) // expected-error {{cannot convert value of type 'Int' to expected argument type 'Int32'}}
327+
GLKProject(&viewport) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Int32>'}}
328+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Int32') are expected to be equal}}
323329

324330
func GLKProjectUP(_ a : UnsafePointer<Int32>) {}
325331
func UP_Void(_ a : UnsafeRawPointer) {}
@@ -341,7 +347,7 @@ func f23202128() {
341347
UMP(&pipe) // expected-error {{cannot pass immutable value as inout argument: 'pipe' is a 'let' constant}}
342348

343349
var pipe2: [Int] = [0, 0]
344-
UMP(&pipe2) // expected-error {{cannot convert value of type 'Array<Int>' to expected argument type 'UnsafeMutablePointer<Int32>'}}
350+
UMP(&pipe2) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Int32>'}}
345351
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Int32') are expected to be equal}}
346352

347353

test/Parse/pointer_conversion_objc.swift.gyb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ func autoreleasingPointerArguments(p: UnsafeMutablePointer<Int>,
6363
takesAutoreleasingPointer(&c)
6464
takesAutoreleasingPointer(c) // expected-error{{cannot convert value of type 'C' to expected argument type 'AutoreleasingUnsafeMutablePointer<C>${diag_suffix}'}}
6565
var d: D = D()
66-
takesAutoreleasingPointer(&d) // expected-error{{cannot convert value of type 'D' to expected argument type 'C'}}
66+
takesAutoreleasingPointer(&d) // expected-error{{cannot convert value of type 'AutoreleasingUnsafeMutablePointer<D>' to expected argument type 'AutoreleasingUnsafeMutablePointer<C>'}}
67+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('D' and 'C') are expected to be equal}}
6768
takesAutoreleasingPointer(d) // expected-error{{cannot convert value of type 'D' to expected argument type 'AutoreleasingUnsafeMutablePointer<C>${diag_suffix}'}}
6869
var cc: [C] = [C(), C()]
6970
var dd: [D] = [D(), D()]
70-
takesAutoreleasingPointer(&cc) // expected-error{{cannot convert value of type '[C]' to expected argument type 'C'}}
71-
takesAutoreleasingPointer(&dd) // expected-error{{cannot convert value of type '[D]' to expected argument type 'C'}}
72-
71+
takesAutoreleasingPointer(&cc) // expected-error{{cannot convert value of type 'AutoreleasingUnsafeMutablePointer<[C]>' to expected argument type 'AutoreleasingUnsafeMutablePointer<C>'}}
72+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('[C]' and 'C') are expected to be equal}}
73+
takesAutoreleasingPointer(&dd) // expected-error{{cannot convert value of type 'AutoreleasingUnsafeMutablePointer<[D]>' to expected argument type 'AutoreleasingUnsafeMutablePointer<C>'}}
74+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('[D]' and 'C') are expected to be equal}}
7375
let _: AutoreleasingUnsafeMutablePointer<C> = &c // expected-error {{use of extraneous '&'}}
7476
}

0 commit comments

Comments
 (0)