Skip to content

Commit ff2a72d

Browse files
committed
[TypeChecker] Inference of inout for closure parameters in generic contexts
This fixes SR-1976
1 parent 994a187 commit ff2a72d

File tree

6 files changed

+52
-8
lines changed

6 files changed

+52
-8
lines changed

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,7 @@ namespace {
18891889

18901890
// Otherwise, create a fresh type variable.
18911891
Type ty = CS.createTypeVariable(CS.getConstraintLocator(locator),
1892-
/*options=*/0);
1892+
TVO_CanBeInOut);
18931893

18941894
param->overwriteType(ty);
18951895
}

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
14101410
case ConstraintKind::ArgumentConversion:
14111411
case ConstraintKind::OperatorArgumentTupleConversion:
14121412
case ConstraintKind::OperatorArgumentConversion:
1413+
if (type1->is<InOutType>() && typeVar2 &&
1414+
typeVar2->getImpl().canBeInOut()) {
1415+
// Upgrade type2 to an InOutType
1416+
auto inOutType1 = type1->getAs<InOutType>();
1417+
1418+
unsigned typeVar3Options = typeVar2->getImpl().getOptions();
1419+
typeVar3Options &= ~TVO_CanBeInOut;
1420+
auto typeVar3 = createTypeVariable(getConstraintLocator(locator),
1421+
typeVar3Options);
1422+
auto inOutType3 = InOutType::get(typeVar3);
1423+
1424+
addConstraint(ConstraintKind::Equal, typeVar2, inOutType3, locator);
1425+
return matchTypes(inOutType1->getObjectType(), typeVar3, kind, flags,
1426+
locator);
1427+
}
1428+
14131429
// We couldn't solve this constraint. If only one of the types is a type
14141430
// variable, perhaps we can do something with it below.
14151431
if (typeVar1 && typeVar2) {

lib/Sema/ConstraintSystem.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ namespace constraints {
6464
/// \brief A handle that holds the saved state of a type variable, which
6565
/// can be restored.
6666
class SavedTypeVariableBinding {
67-
/// \brief The type variable and type variable options.
68-
llvm::PointerIntPair<TypeVariableType *, 3> TypeVarAndOptions;
67+
/// \brief The type variable.
68+
TypeVariableType *TypeVar;
69+
70+
/// \brief The type variable options.
71+
unsigned TypeVarOptions : 4;
6972

7073
/// \brief The parent or fixed type.
7174
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
@@ -76,8 +79,8 @@ class SavedTypeVariableBinding {
7679
/// \brief Restore the state of the type variable to the saved state.
7780
void restore();
7881

79-
TypeVariableType *getTypeVariable() { return TypeVarAndOptions.getPointer(); }
80-
unsigned getOptions() { return TypeVarAndOptions.getInt(); }
82+
TypeVariableType *getTypeVariable() { return TypeVar; }
83+
unsigned getOptions() { return TypeVarOptions; }
8184
};
8285

8386
/// \brief A set of saved type variable bindings.
@@ -126,7 +129,10 @@ enum TypeVariableOptions {
126129
TVO_PrefersSubtypeBinding = 0x02,
127130

128131
/// Whether the variable must be bound to a materializable type.
129-
TVO_MustBeMaterializable = 0x04
132+
TVO_MustBeMaterializable = 0x04,
133+
134+
// Whether the variable can be of an inout type
135+
TVO_CanBeInOut = 0x08,
130136
};
131137

132138
/// \brief The implementation object for a type variable used within the
@@ -138,7 +144,7 @@ enum TypeVariableOptions {
138144
/// which it is assigned.
139145
class TypeVariableType::Implementation {
140146
/// Type variable options.
141-
unsigned Options : 3;
147+
unsigned Options : 4;
142148

143149
/// \brief The locator that describes where this type variable was generated.
144150
constraints::ConstraintLocator *locator;
@@ -178,6 +184,14 @@ class TypeVariableType::Implementation {
178184
bool mustBeMaterializable() const {
179185
return Options & TVO_MustBeMaterializable;
180186
}
187+
188+
bool canBeInOut() const {
189+
return Options & TVO_CanBeInOut;
190+
}
191+
192+
unsigned getOptions() const {
193+
return Options;
194+
}
181195

182196
/// \brief Retrieve the type variable associated with this implementation.
183197
TypeVariableType *getTypeVariable() {

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void TypeVariableType::Implementation::print(llvm::raw_ostream &OS) {
5656
}
5757

5858
SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar)
59-
: TypeVarAndOptions(typeVar, typeVar->getImpl().Options),
59+
: TypeVar(typeVar), TypeVarOptions(typeVar->getImpl().Options),
6060
ParentOrFixed(typeVar->getImpl().ParentOrFixed) { }
6161

6262
void SavedTypeVariableBinding::restore() {
@@ -2683,6 +2683,8 @@ void ConstraintSystem::print(raw_ostream &out) {
26832683
tv->getImpl().print(out);
26842684
if (tv->getImpl().canBindToLValue())
26852685
out << " [lvalue allowed]";
2686+
if (tv->getImpl().canBeInOut())
2687+
out << " [inout allowed]";
26862688
if (tv->getImpl().mustBeMaterializable())
26872689
out << " [must be materializable]";
26882690
auto rep = getRepresentative(tv);

test/expr/closure/inference.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,10 @@ var nestedClosuresWithBrokenInference = { f: Int in {} }
3838
// expected-error@-2 {{consecutive statements on a line must be separated by ';'}} {{44-44=;}}
3939
// expected-error@-3 {{expected expression}}
4040
// expected-error@-4 {{use of unresolved identifier 'f'}}
41+
42+
// SR-1976/SR-3073: Inference of inout
43+
44+
func sr1976<T>(_ closure: (inout T) -> Void) {
45+
}
46+
47+
sr1976({ $0 += 2 })

test/stdlib/UnsafePointerDiagnostics.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,8 @@ func unsafeRawBufferPointerConversions(
137137
_ = UnsafeMutableRawBufferPointer(start: orp, count: 1) // expected-error {{cannot convert value of type 'UnsafeRawPointer?' to expected argument type 'UnsafeMutableRawPointer?'}}
138138
_ = UnsafeRawBufferPointer(start: orp, count: 1)
139139
}
140+
141+
func pointerInoutEquality(i: Int, p: UnsafeMutablePointer<Int>?) {
142+
var i = i
143+
_ = (p == &i)
144+
}

0 commit comments

Comments
 (0)