Skip to content

Commit e337a39

Browse files
xedinahoppen
authored andcommitted
[ConstraintSystem] Implement tap expression checking in the solver
Generate a conjunction for each tap expression body as soon as it gets a contextual type instead of separate post-factum type-checking via `typeCheckTapBody`.
1 parent 2ba70df commit e337a39

File tree

6 files changed

+144
-6
lines changed

6 files changed

+144
-6
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ class TypeVariableType::Implementation {
472472
/// Determine whether this type variable represents a closure type.
473473
bool isClosureType() const;
474474

475+
/// Determine whether this type variable represents a type of tap expression.
476+
bool isTapType() const;
477+
475478
/// Determine whether this type variable represents one of the
476479
/// parameter types associated with a closure.
477480
bool isClosureParameterType() const;
@@ -3951,6 +3954,20 @@ class ConstraintSystem {
39513954
/// \returns `true` if pack expansion has been resolved, `false` otherwise.
39523955
bool resolvePackExpansion(TypeVariableType *typeVar, Type contextualType);
39533956

3957+
/// Bind tap expression to the given contextual type and generate
3958+
/// constraints for its body.
3959+
///
3960+
/// \param typeVar The type variable representing the tap expression.
3961+
/// \param contextualType The contextual type this tap expression
3962+
/// would be bound to.
3963+
/// \param locator The locator associated with contextual type.
3964+
///
3965+
/// \returns `true` if it was possible to generate constraints for
3966+
/// the body and assign fixed type to the tap expression, `false`
3967+
/// otherwise.
3968+
bool resolveTapBody(TypeVariableType *typeVar, Type contextualType,
3969+
ConstraintLocatorBuilder locator);
3970+
39543971
/// Assign a fixed type to the given type variable.
39553972
///
39563973
/// \param typeVar The type variable to bind.
@@ -4354,6 +4371,14 @@ class ConstraintSystem {
43544371
FreeTypeVariableBinding allowFreeTypeVariables =
43554372
FreeTypeVariableBinding::Disallow);
43564373

4374+
/// Generate constraints for the body of the given tap expression.
4375+
///
4376+
/// \param tap the tap expression
4377+
///
4378+
/// \returns \c true if constraint generation failed, \c false otherwise
4379+
LLVM_NODISCARD
4380+
bool generateConstraints(TapExpr *tap);
4381+
43574382
/// Generate constraints for the body of the given function or closure.
43584383
///
43594384
/// \param fn The function or closure expression
@@ -5285,6 +5310,21 @@ class ConstraintSystem {
52855310
llvm::Optional<SyntacticElementTarget>(SyntacticElementTarget)>
52865311
rewriteTarget);
52875312

5313+
/// Apply the given solution to the given tap expression.
5314+
///
5315+
/// \param solution The solution to apply.
5316+
/// \param tapExpr The tap expression to which the solution is being applied.
5317+
/// \param currentDC The declaration context in which transformations
5318+
/// will be applied.
5319+
/// \param rewriteTarget Function that performs a rewrite of any
5320+
/// solution application target within the context.
5321+
///
5322+
/// \returns true if solution cannot be applied.
5323+
bool applySolutionToBody(
5324+
Solution &solution, TapExpr *tapExpr, DeclContext *&currentDC,
5325+
std::function<Optional<SyntacticElementTarget>(SyntacticElementTarget)>
5326+
rewriteTarget);
5327+
52885328
/// Reorder the disjunctive clauses for a given expression to
52895329
/// increase the likelihood that a favored constraint will be successfully
52905330
/// resolved before any others.

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8638,7 +8638,17 @@ namespace {
86388638
for (const auto &tuple : TapsToTypeCheck) {
86398639
auto tap = std::get<0>(tuple);
86408640
auto tapDC = std::get<1>(tuple);
8641-
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
8641+
8642+
hadError |= cs.applySolutionToBody(
8643+
solution, tap, tapDC, [&](SolutionApplicationTarget target) {
8644+
auto resultTarget = rewriteTarget(target);
8645+
if (resultTarget) {
8646+
if (auto expr = resultTarget->getAsExpr())
8647+
solution.setExprTypes(expr);
8648+
}
8649+
8650+
return resultTarget;
8651+
});
86428652
}
86438653
TapsToTypeCheck.clear();
86448654
}

lib/Sema/CSGen.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,15 +1236,34 @@ namespace {
12361236
return nullptr;
12371237
}
12381238

1239-
auto interpolationTV = DependentMemberType::get(tv, associatedTypeDecl);
1239+
auto interpolationTV =
1240+
CS.createTypeVariable(locator, TVO_CanBindToNoEscape);
1241+
auto interpolationType =
1242+
DependentMemberType::get(tv, associatedTypeDecl);
1243+
1244+
CS.addConstraint(ConstraintKind::Equal, interpolationTV,
1245+
interpolationType, locator);
12401246

12411247
auto appendingExprType = CS.getType(appendingExpr);
12421248
auto appendingLocator = CS.getConstraintLocator(appendingExpr);
12431249

1244-
// Must be Conversion; if it's Equal, then in semi-rare cases, the
1250+
SmallVector<TypeVariableType *, 2> referencedVars;
1251+
1252+
// If tap expression is located in a closure, let's connect them
1253+
// because interpolation could use parameters.
1254+
if (auto *tap = getAsExpr<TapExpr>(appendingExpr)) {
1255+
auto *tapDC = tap->getVar()->getDeclContext();
1256+
if (auto *closure = dyn_cast<ClosureExpr>(tapDC)) {
1257+
referencedVars.push_back(
1258+
CS.getType(closure)->castTo<TypeVariableType>());
1259+
}
1260+
}
1261+
1262+
// Must be Conversion; if it's Equal, then in semi-rare cases, the
12451263
// interpolation temporary variable cannot be @lvalue.
1246-
CS.addConstraint(ConstraintKind::Conversion, appendingExprType,
1247-
interpolationTV, appendingLocator);
1264+
CS.addUnsolvedConstraint(Constraint::create(
1265+
CS, ConstraintKind::Conversion, appendingExprType, interpolationTV,
1266+
appendingLocator, referencedVars));
12481267
}
12491268

12501269
return tv;

lib/Sema/CSSimplify.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4413,6 +4413,12 @@ ConstraintSystem::matchTypesBindTypeVar(
44134413
: getTypeMatchFailure(locator);
44144414
}
44154415

4416+
if (typeVar->getImpl().isTapType()) {
4417+
return resolveTapBody(typeVar, type, locator)
4418+
? getTypeMatchSuccess()
4419+
: getTypeMatchFailure(locator);
4420+
}
4421+
44164422
assignFixedType(typeVar, type, /*updateState=*/true,
44174423
/*notifyInference=*/!flags.contains(TMF_BindingTypeVariable));
44184424

@@ -11508,6 +11514,23 @@ bool ConstraintSystem::resolvePackExpansion(TypeVariableType *typeVar,
1150811514
return true;
1150911515
}
1151011516

11517+
bool ConstraintSystem::resolveTapBody(TypeVariableType *typeVar,
11518+
Type contextualType,
11519+
ConstraintLocatorBuilder locator) {
11520+
auto *tapLoc = typeVar->getImpl().getLocator();
11521+
auto *tapExpr = castToExpr<TapExpr>(tapLoc->getAnchor());
11522+
11523+
// Assign a type to tap expression itself.
11524+
assignFixedType(typeVar, contextualType, getConstraintLocator(locator));
11525+
// Set type to `$interpolation` variable declared in the body of tap
11526+
// expression.
11527+
setType(tapExpr->getVar(), contextualType);
11528+
11529+
// With all of the contextual information recorded in the constraint system,
11530+
// it's time to generate constraints for the body of this tap expression.
11531+
return !generateConstraints(tapExpr);
11532+
}
11533+
1151111534
ConstraintSystem::SolutionKind
1151211535
ConstraintSystem::simplifyDynamicTypeOfConstraint(
1151311536
Type type1, Type type2,

lib/Sema/CSSyntacticElement.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,17 @@ static void createConjunction(ConstraintSystem &cs,
359359
isIsolated = true;
360360
}
361361

362+
if (locator->directlyAt<TapExpr>()) {
363+
auto *tap = castToExpr<TapExpr>(locator->getAnchor());
364+
auto *tapDC = tap->getVar()->getDeclContext();
365+
366+
referencedVars.push_back(cs.getType(tap)->castTo<TypeVariableType>());
367+
368+
if (auto *closure = dyn_cast<ClosureExpr>(tapDC)) {
369+
referencedVars.push_back(cs.getType(closure)->castTo<TypeVariableType>());
370+
}
371+
}
372+
362373
UnresolvedVarCollector paramCollector(cs);
363374

364375
for (const auto &entry : elements) {
@@ -1375,6 +1386,22 @@ class SyntacticElementConstraintGenerator
13751386
};
13761387
}
13771388

1389+
bool ConstraintSystem::generateConstraints(TapExpr *tap) {
1390+
SyntacticElementConstraintGenerator generator(
1391+
*this, SyntacticElementContext::forTapExpr(tap),
1392+
getConstraintLocator(tap));
1393+
1394+
auto *body = tap->getBody();
1395+
1396+
if (!body) {
1397+
assert(tap->getSubExpr());
1398+
return false;
1399+
}
1400+
1401+
generator.visit(tap->getBody());
1402+
return generator.hadError;
1403+
}
1404+
13781405
bool ConstraintSystem::generateConstraints(AnyFunctionRef fn, BraceStmt *body) {
13791406
NullablePtr<ConstraintLocator> locator;
13801407

@@ -2538,8 +2565,23 @@ bool ConstraintSystem::applySolutionToBody(Solution &solution,
25382565
return false;
25392566
}
25402567

2568+
bool ConstraintSystem::applySolutionToBody(Solution &solution, TapExpr *tapExpr,
2569+
DeclContext *&currentDC,
2570+
RewriteTargetFn rewriteTarget) {
2571+
SyntacticElementSolutionApplication application(
2572+
solution, SyntacticElementContext::forTapExpr(tapExpr), rewriteTarget);
2573+
2574+
auto body = application.apply();
2575+
2576+
if (!body || application.hadError)
2577+
return true;
2578+
2579+
tapExpr->setBody(castToStmt<BraceStmt>(body));
2580+
return false;
2581+
}
2582+
25412583
bool ConjunctionElement::mightContainCodeCompletionToken(
2542-
const ConstraintSystem &cs) const {
2584+
const ConstraintSystem &cs) const {
25432585
if (Element->getKind() == ConstraintKind::SyntacticElement) {
25442586
if (Element->getSyntacticElement().getSourceRange().isInvalid()) {
25452587
return true;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ bool TypeVariableType::Implementation::isClosureType() const {
120120
return isExpr<ClosureExpr>(locator->getAnchor()) && locator->getPath().empty();
121121
}
122122

123+
bool TypeVariableType::Implementation::isTapType() const {
124+
return locator && locator->directlyAt<TapExpr>();
125+
}
126+
123127
bool TypeVariableType::Implementation::isClosureParameterType() const {
124128
if (!(locator && locator->getAnchor()))
125129
return false;

0 commit comments

Comments
 (0)