Skip to content

Commit 0a178fd

Browse files
committed
[ConstraintGraph] Disallow subtype constraint contractions
Presently subtype constraint is considered a candidate for contraction via `shouldContractEdge` when left-hand side of the subtype constraint is an inout type with type variable inside. Although it's intended to be used only in combination with BindParam constraint assigned to the same variable, that is actually never checked and contraction of subtype constraint like that is invalid. Resolves: rdar://problem/34333874
1 parent 80c7d1e commit 0a178fd

File tree

2 files changed

+43
-21
lines changed

2 files changed

+43
-21
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -641,13 +641,6 @@ static bool shouldContractEdge(ConstraintKind kind) {
641641
case ConstraintKind::BindParam:
642642
case ConstraintKind::BindToPointerType:
643643
case ConstraintKind::Equal:
644-
645-
// We currently only allow subtype contractions for the purpose of
646-
// parameter binding constraints.
647-
// TODO: We do this because of how inout parameter bindings are handled
648-
// for implicit closure parameters. We should consider adjusting our
649-
// current approach to unlock more opportunities for subtype contractions.
650-
case ConstraintKind::Subtype:
651644
return true;
652645

653646
default:
@@ -671,12 +664,7 @@ static bool isStrictInoutSubtypeConstraint(Constraint *constraint) {
671664
t1 = tt->getElementType(0).getPointer();
672665
}
673666

674-
auto iot = t1->getAs<InOutType>();
675-
676-
if (!iot)
677-
return false;
678-
679-
return !iot->getObjectType()->isTypeVariableOrMember();
667+
return t1->is<InOutType>();
680668
}
681669

682670
bool ConstraintGraph::contractEdges() {
@@ -698,14 +686,6 @@ bool ConstraintGraph::contractEdges() {
698686
auto t1 = constraint->getFirstType()->getDesugaredType();
699687
auto t2 = constraint->getSecondType()->getDesugaredType();
700688

701-
if (kind == ConstraintKind::Subtype) {
702-
if (auto iot1 = t1->getAs<InOutType>()) {
703-
t1 = iot1->getObjectType().getPointer();
704-
} else {
705-
continue;
706-
}
707-
}
708-
709689
auto tyvar1 = t1->getAs<TypeVariableType>();
710690
auto tyvar2 = t2->getAs<TypeVariableType>();
711691

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
class C {
5+
var a: Int = 0
6+
var b: Int = 0
7+
}
8+
9+
@inline(never)
10+
func foo<T>(_ item: T, update: (inout T) throws -> Void) rethrows -> T {
11+
var this = item
12+
try update(&this)
13+
return this
14+
}
15+
16+
// Test single statement closure because it's type-checked
17+
// together with the call to `foo`
18+
19+
let rdar34333874_1 = foo(C()) {
20+
$0.a = 42
21+
}
22+
23+
// The multi-statement closure which is type-checked
24+
// separately from call to `foo`
25+
26+
let rdar34333874_2 = foo(C()) {
27+
$0.a = 42
28+
$0.b = 0
29+
}
30+
31+
print(rdar34333874_1)
32+
print(rdar34333874_2)
33+
34+
// Example which avoids mutating fields of the class
35+
36+
@inline(never)
37+
func bar(_ o : C) {
38+
let _ = foo(o) { (item) in
39+
}
40+
}
41+
42+
bar(C())

0 commit comments

Comments
 (0)