Skip to content

Commit 5291ffb

Browse files
authored
Merge pull request #26996 from xedin/extend-use-of-invalid-generic-param
[ConstraintSystem] Extend `generic argument mismatch` fix to all pointer conversions
2 parents f2d1f6d + 96ea85a commit 5291ffb

File tree

5 files changed

+77
-90
lines changed

5 files changed

+77
-90
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4389,52 +4389,7 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
43894389
return false;
43904390
}
43914391

4392-
4393-
/// Return true if this type is known to be an ArrayType.
4394-
static bool isKnownToBeArrayType(Type ty) {
4395-
if (!ty) return false;
4396-
4397-
auto bgt = ty->getAs<BoundGenericType>();
4398-
if (!bgt) return false;
4399-
4400-
auto &ctx = bgt->getASTContext();
4401-
return bgt->getDecl() == ctx.getArrayDecl();
4402-
}
4403-
44044392
bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
4405-
// If we have a contextual type, it must be an inout type.
4406-
auto contextualType = CS.getContextualType();
4407-
if (contextualType) {
4408-
// If the contextual type is one of the UnsafePointer<T> types, then the
4409-
// contextual type of the subexpression must be T.
4410-
Type unwrappedType = contextualType;
4411-
if (auto unwrapped = contextualType->getOptionalObjectType())
4412-
unwrappedType = unwrapped;
4413-
4414-
if (auto pointerEltType = unwrappedType->getAnyPointerElementType()) {
4415-
4416-
// If the element type is Void, then we allow any input type, since
4417-
// everything is convertible to UnsafeRawPointer
4418-
if (pointerEltType->isVoid())
4419-
contextualType = Type();
4420-
else
4421-
contextualType = pointerEltType;
4422-
4423-
// Furthermore, if the subexpr type is already known to be an array type,
4424-
// then we must have an attempt at an array to pointer conversion.
4425-
if (isKnownToBeArrayType(CS.getType(IOE->getSubExpr()))) {
4426-
contextualType = ArraySliceType::get(contextualType);
4427-
}
4428-
} else if (contextualType->is<InOutType>()) {
4429-
contextualType = contextualType->getInOutObjectType();
4430-
}
4431-
}
4432-
4433-
if (!typeCheckChildIndependently(IOE->getSubExpr(), contextualType,
4434-
CS.getContextualTypePurpose(),
4435-
TCC_AllowLValue)) {
4436-
return true;
4437-
}
44384393
return false;
44394394
}
44404395

lib/Sema/CSSimplify.cpp

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,8 +2529,15 @@ bool ConstraintSystem::repairFailures(
25292529
// `&`.
25302530
if (lhs->is<LValueType>() &&
25312531
(rhs->is<InOutType>() || rhs->getAnyPointerElementType())) {
2532-
auto result = matchTypes(InOutType::get(lhs->getRValueType()), rhs,
2533-
ConstraintKind::ArgumentConversion,
2532+
auto baseType = rhs->is<InOutType>() ? rhs->getInOutObjectType()
2533+
: rhs->getAnyPointerElementType();
2534+
2535+
// Let's use `BindToPointer` constraint here to match up base types
2536+
// of implied `inout` argument and `inout` or pointer parameter.
2537+
// This helps us to avoid implicit conversions associated with
2538+
// `ArgumentConversion` constraint.
2539+
auto result = matchTypes(lhs->getRValueType(), baseType,
2540+
ConstraintKind::BindToPointerType,
25342541
TypeMatchFlags::TMF_ApplyingFix, locator);
25352542

25362543
if (result.isSuccess()) {
@@ -6923,6 +6930,44 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
69236930

69246931
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
69256932

6933+
auto matchPointerBaseTypes = [&](Type baseType1,
6934+
Type baseType2) -> SolutionKind {
6935+
if (restriction != ConversionRestrictionKind::PointerToPointer)
6936+
increaseScore(ScoreKind::SK_ValueToPointerConversion);
6937+
6938+
auto result =
6939+
matchTypes(baseType1, baseType2, ConstraintKind::BindToPointerType,
6940+
subflags, locator);
6941+
6942+
if (!(result.isFailure() && shouldAttemptFixes()))
6943+
return result;
6944+
6945+
BoundGenericType *ptr1 = nullptr;
6946+
BoundGenericType *ptr2 = nullptr;
6947+
6948+
switch (restriction) {
6949+
case ConversionRestrictionKind::ArrayToPointer:
6950+
case ConversionRestrictionKind::InoutToPointer: {
6951+
ptr2 = type2->lookThroughAllOptionalTypes()->castTo<BoundGenericType>();
6952+
ptr1 = BoundGenericType::get(ptr2->getDecl(), ptr2->getParent(),
6953+
{baseType1});
6954+
break;
6955+
}
6956+
6957+
case ConversionRestrictionKind::PointerToPointer:
6958+
ptr1 = type1->castTo<BoundGenericType>();
6959+
ptr2 = type2->castTo<BoundGenericType>();
6960+
break;
6961+
6962+
default:
6963+
return SolutionKind::Error;
6964+
}
6965+
6966+
auto *fix = GenericArgumentsMismatch::create(*this, ptr1, ptr2, {0},
6967+
getConstraintLocator(locator));
6968+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
6969+
};
6970+
69266971
switch (restriction) {
69276972
// for $< in { <, <c, <oc }:
69286973
// T_i $< U_i ===> (T_i...) $< (U_i...)
@@ -7042,23 +7087,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
70427087
auto baseType1 = getFixedTypeRecursive(*isArrayType(obj1), false);
70437088
auto baseType2 = getBaseTypeForPointer(*this, t2);
70447089

7045-
increaseScore(ScoreKind::SK_ValueToPointerConversion);
7046-
auto result = matchTypes(baseType1, baseType2,
7047-
ConstraintKind::BindToPointerType,
7048-
subflags, locator);
7049-
7050-
if (!(result.isFailure() && shouldAttemptFixes()))
7051-
return result;
7052-
7053-
auto *arrTy = obj1->getAs<BoundGenericType>();
7054-
// Let's dig out underlying pointer type since it could
7055-
// be wrapped into N (implicit) optionals.
7056-
auto *ptrTy =
7057-
type2->lookThroughAllOptionalTypes()->getAs<BoundGenericType>();
7058-
7059-
auto *fix = GenericArgumentsMismatch::create(*this, arrTy, ptrTy, {0},
7060-
getConstraintLocator(locator));
7061-
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
7090+
return matchPointerBaseTypes(baseType1, baseType2);
70627091
}
70637092

70647093
// String ===> UnsafePointer<[U]Int8>
@@ -7111,13 +7140,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
71117140

71127141
auto baseType1 = type1->getInOutObjectType();
71137142
auto baseType2 = getBaseTypeForPointer(*this, t2);
7114-
7115-
// Set up the disjunction for the array or scalar cases.
71167143

7117-
increaseScore(ScoreKind::SK_ValueToPointerConversion);
7118-
return matchTypes(baseType1, baseType2,
7119-
ConstraintKind::BindToPointerType,
7120-
subflags, locator);
7144+
return matchPointerBaseTypes(baseType1, baseType2);
71217145
}
71227146

71237147
// T <p U ===> UnsafeMutablePointer<T> <a UnsafeMutablePointer<U>
@@ -7127,10 +7151,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
71277151

71287152
Type baseType1 = getBaseTypeForPointer(*this, t1);
71297153
Type baseType2 = getBaseTypeForPointer(*this, t2);
7130-
7131-
return matchTypes(baseType1, baseType2,
7132-
ConstraintKind::BindToPointerType,
7133-
subflags, locator);
7154+
7155+
return matchPointerBaseTypes(baseType1, baseType2);
71347156
}
71357157

71367158
// 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)