Skip to content

Commit 8e5ae4c

Browse files
authored
Merge pull request #29432 from DougGregor/contextual-conditions-for-function-builders
[Constraint system] Set the contextual type for condition expressions.
2 parents 8f3d2b2 + 465e5da commit 8e5ae4c

File tree

4 files changed

+52
-15
lines changed

4 files changed

+52
-15
lines changed

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,6 +3821,7 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
38213821
return true;
38223822
}
38233823

3824+
Type boolTy = boolDecl->getDeclaredType();
38243825
for (const auto &condElement : condition) {
38253826
switch (condElement.getKind()) {
38263827
case StmtConditionElement::CK_Availability:
@@ -3829,15 +3830,18 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
38293830

38303831
case StmtConditionElement::CK_Boolean: {
38313832
Expr *condExpr = condElement.getBoolean();
3833+
setContextualType(condExpr, TypeLoc::withoutLoc(boolTy), CTP_Condition);
3834+
38323835
condExpr = generateConstraints(condExpr, dc);
38333836
if (!condExpr) {
38343837
return true;
38353838
}
38363839

38373840
addConstraint(ConstraintKind::Conversion,
38383841
getType(condExpr),
3839-
boolDecl->getDeclaredType(),
3840-
getConstraintLocator(condExpr));
3842+
boolTy,
3843+
getConstraintLocator(condExpr,
3844+
LocatorPathElt::ContextualType()));
38413845
continue;
38423846
}
38433847

lib/Sema/CSSolver.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ Solution ConstraintSystem::finalize() {
168168
solution.addedNodeTypes.insert(nodeType);
169169
}
170170

171+
// Remember contextual types.
172+
solution.contextualTypes.assign(
173+
contextualTypes.begin(), contextualTypes.end());
174+
171175
for (auto &e : CheckedConformances)
172176
solution.Conformances.push_back({e.first, e.second});
173177

@@ -232,6 +236,14 @@ void ConstraintSystem::applySolution(const Solution &solution) {
232236
setType(nodeType.first, nodeType.second);
233237
}
234238

239+
// Add the contextual types.
240+
for (const auto &contextualType : solution.contextualTypes) {
241+
if (!getContextualTypeInfo(contextualType.first)) {
242+
setContextualType(contextualType.first, contextualType.second.typeLoc,
243+
contextualType.second.purpose);
244+
}
245+
}
246+
235247
// Register the conformances checked along the way to arrive to solution.
236248
for (auto &conformance : solution.Conformances)
237249
CheckedConformances.push_back(conformance);

lib/Sema/ConstraintSystem.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,15 @@ using OpenedType = std::pair<GenericTypeParamType *, TypeVariableType *>;
787787
using OpenedTypeMap =
788788
llvm::DenseMap<GenericTypeParamType *, TypeVariableType *>;
789789

790+
/// Describes contextual type information about a particular expression
791+
/// within a constraint system.
792+
struct ContextualTypeInfo {
793+
TypeLoc typeLoc;
794+
ContextualTypePurpose purpose;
795+
796+
Type getType() const { return typeLoc.getType(); }
797+
};
798+
790799
/// A complete solution to a constraint system.
791800
///
792801
/// A solution to a constraint system consists of type variable bindings to
@@ -849,6 +858,9 @@ class Solution {
849858
/// The node -> type mappings introduced by this solution.
850859
llvm::MapVector<TypedNode, Type> addedNodeTypes;
851860

861+
/// Contextual types introduced by this solution.
862+
std::vector<std::pair<const Expr *, ContextualTypeInfo>> contextualTypes;
863+
852864
std::vector<std::pair<ConstraintLocator *, ProtocolConformanceRef>>
853865
Conformances;
854866

@@ -1300,13 +1312,6 @@ class ConstraintSystem {
13001312
llvm::DenseMap<std::pair<const KeyPathExpr *, unsigned>, TypeBase *>
13011313
KeyPathComponentTypes;
13021314

1303-
struct ContextualTypeInfo {
1304-
TypeLoc typeLoc;
1305-
ContextualTypePurpose purpose;
1306-
1307-
Type getType() const { return typeLoc.getType(); }
1308-
};
1309-
13101315
/// Contextual type information for expressions that are part of this
13111316
/// constraint system.
13121317
llvm::MapVector<const Expr *, ContextualTypeInfo> contextualTypes;
@@ -2174,35 +2179,36 @@ class ConstraintSystem {
21742179
return E;
21752180
}
21762181

2177-
void setContextualType(Expr *expr, TypeLoc T, ContextualTypePurpose purpose) {
2182+
void setContextualType(
2183+
const Expr *expr, TypeLoc T, ContextualTypePurpose purpose) {
21782184
assert(expr != nullptr && "Expected non-null expression!");
21792185
assert(contextualTypes.count(expr) == 0 &&
21802186
"Already set this contextual type");
21812187
contextualTypes[expr] = { T, purpose };
21822188
}
21832189

2184-
Optional<ContextualTypeInfo> getContextualTypeInfo(Expr *expr) const {
2190+
Optional<ContextualTypeInfo> getContextualTypeInfo(const Expr *expr) const {
21852191
auto known = contextualTypes.find(expr);
21862192
if (known == contextualTypes.end())
21872193
return None;
21882194
return known->second;
21892195
}
21902196

2191-
Type getContextualType(Expr *expr) const {
2197+
Type getContextualType(const Expr *expr) const {
21922198
auto result = getContextualTypeInfo(expr);
21932199
if (result)
21942200
return result->typeLoc.getType();
21952201
return Type();
21962202
}
21972203

2198-
TypeLoc getContextualTypeLoc(Expr *expr) const {
2204+
TypeLoc getContextualTypeLoc(const Expr *expr) const {
21992205
auto result = getContextualTypeInfo(expr);
22002206
if (result)
22012207
return result->typeLoc;
22022208
return TypeLoc();
22032209
}
22042210

2205-
ContextualTypePurpose getContextualTypePurpose(Expr *expr) const {
2211+
ContextualTypePurpose getContextualTypePurpose(const Expr *expr) const {
22062212
auto result = getContextualTypeInfo(expr);
22072213
if (result)
22082214
return result->purpose;

test/Constraints/function_builder_diags.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ struct MyTuplifiedStruct {
257257
}
258258
}
259259

260-
// Check that we're performing syntactic use diagnostics/
260+
// Check that we're performing syntactic use diagnostics.
261261
func acceptMetatype<T>(_: T.Type) -> Bool { true }
262262

263263
func syntacticUses<T>(_: T) {
@@ -269,3 +269,18 @@ func syntacticUses<T>(_: T) {
269269
}
270270
}
271271
}
272+
273+
// Check custom diagnostics within "if" conditions.
274+
struct HasProperty {
275+
var property: Bool = false
276+
}
277+
278+
func checkConditions(cond: Bool) {
279+
var x = HasProperty()
280+
281+
tuplify(cond) { value in
282+
if x.property = value { // expected-error{{use of '=' in a boolean context, did you mean '=='?}}
283+
"matched it"
284+
}
285+
}
286+
}

0 commit comments

Comments
 (0)