Skip to content

Commit 77a5938

Browse files
committed
[CS] Penalize implicit pointer conversions to generic parameter types
We ought to consider outright banning these conversions if the destination is a generic parameter type, but for now let's penalize them such that we don't end up with ambiguities if you're doing an implicit pointer conversion through an identity generic function. rdar://161205293
1 parent 2fceb9a commit 77a5938

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,11 @@ enum ScoreKind: unsigned int {
10141014
SK_EmptyExistentialConversion,
10151015
/// A key path application subscript.
10161016
SK_KeyPathSubscript,
1017+
/// A pointer conversion where the destination type is a generic parameter.
1018+
/// This should eventually be removed in favor of outright banning pointer
1019+
/// conversions for generic parameters. As such we consider it more impactful
1020+
/// than \c SK_ValueToPointerConversion.
1021+
SK_GenericParamPointerConversion,
10171022
/// A conversion from a string, array, or inout to a pointer.
10181023
SK_ValueToPointerConversion,
10191024
/// A closure/function conversion to an autoclosure parameter.
@@ -1191,6 +1196,9 @@ struct Score {
11911196
case SK_KeyPathSubscript:
11921197
return "key path subscript";
11931198

1199+
case SK_GenericParamPointerConversion:
1200+
return "pointer conversion to generic parameter";
1201+
11941202
case SK_ValueToPointerConversion:
11951203
return "value-to-pointer conversion";
11961204

lib/Sema/CSSimplify.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15411,6 +15411,50 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1541115411
llvm_unreachable("bad conversion restriction");
1541215412
}
1541315413

15414+
static void increaseScoreForGenericParamPointerConversion(
15415+
ConstraintSystem &cs, ConversionRestrictionKind kind,
15416+
ConstraintLocatorBuilder locator) {
15417+
switch (kind) {
15418+
case ConversionRestrictionKind::InoutToPointer:
15419+
case ConversionRestrictionKind::ArrayToPointer:
15420+
case ConversionRestrictionKind::StringToPointer:
15421+
case ConversionRestrictionKind::PointerToPointer:
15422+
break;
15423+
default:
15424+
return;
15425+
}
15426+
15427+
auto *loc = cs.getConstraintLocator(locator);
15428+
auto argInfo = loc->findLast<LocatorPathElt::ApplyArgToParam>();
15429+
if (!argInfo)
15430+
return;
15431+
15432+
auto overload = cs.findSelectedOverloadFor(cs.getCalleeLocator(loc));
15433+
if (!overload)
15434+
return;
15435+
15436+
auto *D = overload->choice.getDeclOrNull();
15437+
if (!D)
15438+
return;
15439+
15440+
auto *param = getParameterAt(D, argInfo->getParamIdx());
15441+
if (!param)
15442+
return;
15443+
15444+
// Check to see if the parameter is a generic parameter, or dependent member.
15445+
auto paramTy = param->getInterfaceType()->lookThroughAllOptionalTypes();
15446+
if (!paramTy->isTypeParameter())
15447+
return;
15448+
15449+
// Don't increase the score if the type parameter is rooted on the protocol
15450+
// 'Self' type, e.g extensions on `_Pointer` shouldn't be penalized.
15451+
if (auto *PD = D->getDeclContext()->getSelfProtocolDecl()) {
15452+
if (PD->getSelfInterfaceType()->isEqual(paramTy->getRootGenericParam()))
15453+
return;
15454+
}
15455+
cs.increaseScore(SK_GenericParamPointerConversion, locator);
15456+
}
15457+
1541415458
ConstraintSystem::SolutionKind
1541515459
ConstraintSystem::simplifyRestrictedConstraint(
1541615460
ConversionRestrictionKind restriction,
@@ -15438,6 +15482,13 @@ ConstraintSystem::simplifyRestrictedConstraint(
1543815482
addFixConstraint(fix, matchKind, type1, type2, locator);
1543915483
}
1544015484

15485+
// Increase the score if needed for a pointer conversion to a generic
15486+
// parameter type.
15487+
// FIXME: We ought to consider outright banning pointer conversions to
15488+
// generic parameter types, in which case this logic could be adjusted to
15489+
// record a fix instead.
15490+
increaseScoreForGenericParamPointerConversion(*this, restriction, locator);
15491+
1544115492
addConversionRestriction(type1, type2, restriction);
1544215493
return SolutionKind::Solved;
1544315494
}

test/Constraints/valid_pointer_conversions.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,31 @@ do {
8888
let _: UInt8 = result1 // Ok
8989
let _: [UInt8] = result2 // Ok
9090
}
91+
92+
protocol PointerProtocol {}
93+
extension UnsafePointer: PointerProtocol {}
94+
95+
extension PointerProtocol {
96+
func foo(_ x: Self) {} // expected-note {{found this candidate}}
97+
func foo(_ x: UnsafePointer<CChar>) {} // expected-note {{found this candidate}}
98+
}
99+
100+
func testGenericPointerConversions(
101+
chars: [CChar], mutablePtr: UnsafeMutablePointer<CChar>, ptr: UnsafePointer<CChar>
102+
) {
103+
func id<T>(_ x: T) -> T { x }
104+
func optID<T>(_ x: T?) -> T { x! }
105+
func takesCharPtrs(_: UnsafePointer<CChar>, _: UnsafePointer<CChar>?) {}
106+
107+
// Make sure we don't end up with an ambiguity here, we should prefer to
108+
// do the pointer conversion for `takesPtrs` not `id`.
109+
takesCharPtrs(chars, "a")
110+
takesCharPtrs(id(chars), id("a"))
111+
takesCharPtrs(id("a"), optID(chars))
112+
takesCharPtrs(mutablePtr, mutablePtr)
113+
takesCharPtrs(id(mutablePtr), id(mutablePtr))
114+
takesCharPtrs(id(mutablePtr), optID(mutablePtr))
115+
116+
// Make sure this is ambiguous.
117+
ptr.foo(chars) // expected-error {{ambiguous use of 'foo'}}
118+
}

unittests/Sema/ConstraintSystemDumpTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ TEST_F(SemaTest, DumpConstraintSystemBasic) {
3333
TupleType::get({Type(t0), Type(t1)}, Context), emptyLoc));
3434

3535
std::string expectedOutput =
36-
R"(Score: <default 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>
36+
R"(Score: <default 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>
3737
Type Variables:
3838
$T0 [can bind to: lvalue] [adjacent to: $T1, $T2] [potential bindings: <none>] @ locator@ []
3939
$T1 [adjacent to: $T0, $T2] [potential bindings: <none>] @ locator@ []

0 commit comments

Comments
 (0)