Skip to content

Commit 145a7c5

Browse files
authored
Merge pull request #80057 from slavapestov/fix-rdar146780049
Sema: Fix non-determinism with ConstraintSystem::ConstraintRestrictions
2 parents 3617a29 + 34e7e82 commit 145a7c5

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3627,16 +3627,6 @@ class ConstraintSystem {
36273627
});
36283628
}
36293629

3630-
bool
3631-
hasConversionRestriction(Type type1, Type type2,
3632-
ConversionRestrictionKind restrictionKind) const {
3633-
auto restriction =
3634-
ConstraintRestrictions.find({type1.getPointer(), type2.getPointer()});
3635-
return restriction == ConstraintRestrictions.end()
3636-
? false
3637-
: restriction->second == restrictionKind;
3638-
}
3639-
36403630
/// If an UnresolvedDotExpr, SubscriptMember, etc has been resolved by the
36413631
/// constraint system, return the decl that it references.
36423632
ValueDecl *findResolvedMemberRef(ConstraintLocator *locator);

lib/Sema/CSSolver.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ Solution ConstraintSystem::finalize() {
124124

125125
CanType first = simplifyType(types.first)->getCanonicalType();
126126
CanType second = simplifyType(types.second)->getCanonicalType();
127+
128+
// Pick the restriction with the highest value to avoid depending on
129+
// iteration order.
130+
auto found = solution.ConstraintRestrictions.find({first, second});
131+
if (found != solution.ConstraintRestrictions.end() &&
132+
(unsigned) restriction <= (unsigned) found->second) {
133+
continue;
134+
}
135+
127136
solution.ConstraintRestrictions[{first, second}] = restriction;
128137
}
129138
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
2+
3+
// rdar://146780049
4+
5+
class Image {}
6+
7+
class MyV {
8+
var image: Image = Image()
9+
}
10+
11+
func takesPtr(_: UnsafePointer<Image>?, _: UnsafePointer<Image>?, _: UnsafePointer<Image>?) {
12+
}
13+
14+
func test(buffers: [MyV]) {
15+
withUnsafePointer(to: buffers[0].image) { ptrA in
16+
withUnsafePointer(to: buffers[1].image) { ptrB in
17+
withUnsafePointer(to: buffers[2].image) { ptrC in
18+
_ = takesPtr(ptrA, ptrB, ptrC)
19+
}
20+
}
21+
}
22+
}
23+
24+
// The other valid conversion here that should not be considered because it has a worse
25+
// score is pointer-to-pointer instead of value-to-optional. The generated SIL looks
26+
// quite different in that case, involving calls to intrinsics. Make sure we pick the
27+
// value-to-optional conversion, because it generates much simpler SIL:
28+
29+
// CHECK-LABEL: sil private [ossa] @$s28ambiguous_pointer_conversion4test7buffersySayAA3MyVCG_tFySPyAA5ImageCGXEfU_yAIXEfU_yAIXEfU_ : $@convention(thin) @substituted <τ_0_0, τ_0_1, τ_0_2> (UnsafePointer<τ_0_0>, UnsafePointer<Image>, UnsafePointer<Image>) -> (@out τ_0_2, @error_indirect τ_0_1) for <Image, Never, ()> {
30+
// CHECK: bb0(%0 : $*(), %1 : $*Never, %2 : $UnsafePointer<Image>, %3 : @closureCapture $UnsafePointer<Image>, %4 : @closureCapture $UnsafePointer<Image>):
31+
// CHECK: [[X:%.*]] = enum $Optional<UnsafePointer<Image>>, #Optional.some!enumelt, %3
32+
// CHECK: [[Y:%.*]] = enum $Optional<UnsafePointer<Image>>, #Optional.some!enumelt, %4
33+
// CHECK: [[Z:%.*]] = enum $Optional<UnsafePointer<Image>>, #Optional.some!enumelt, %2
34+
// CHECK: [[FN:%.*]] = function_ref @$s28ambiguous_pointer_conversion8takesPtryySPyAA5ImageCGSg_A2FtF : $@convention(thin) (Optional<UnsafePointer<Image>>, Optional<UnsafePointer<Image>>, Optional<UnsafePointer<Image>>) -> ()
35+
// CHECK: apply %11([[X]], [[Y]], [[Z]]) : $@convention(thin) (Optional<UnsafePointer<Image>>, Optional<UnsafePointer<Image>>, Optional<UnsafePointer<Image>>) -> ()
36+
// CHECK: return
37+

0 commit comments

Comments
 (0)