Skip to content

Commit 40e599e

Browse files
committed
[Type checker] Move for-each application logic into constraint system.
Move the various "application" logic for the for-each loop out of the visitor in TypeCheckStmt and into the constraint system's handling of for-each bindings.
1 parent 97b5a0d commit 40e599e

File tree

3 files changed

+68
-103
lines changed

3 files changed

+68
-103
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,8 +2892,7 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
28922892
return hadError;
28932893
}
28942894

2895-
auto TypeChecker::typeCheckForEachBinding(
2896-
DeclContext *dc, ForEachStmt *stmt) -> Optional<ForEachBinding> {
2895+
bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
28972896
/// Type checking listener for for-each binding.
28982897
class BindingListener : public ExprTypeCheckListener {
28992898
/// The for-each statement.
@@ -3001,6 +3000,7 @@ auto TypeChecker::typeCheckForEachBinding(
30013000
Expr *appliedSolution(Solution &solution, Expr *expr) override {
30023001
// Figure out what types the constraints decided on.
30033002
auto &cs = solution.getConstraintSystem();
3003+
ASTContext &ctx = cs.getASTContext();
30043004
InitType = solution.simplifyType(InitType);
30053005
SequenceType = solution.simplifyType(SequenceType);
30063006
ElementType = solution.simplifyType(ElementType);
@@ -3012,6 +3012,7 @@ auto TypeChecker::typeCheckForEachBinding(
30123012

30133013
cs.cacheExprTypes(expr);
30143014
Stmt->setSequence(expr);
3015+
solution.setExprTypes(expr);
30153016

30163017
// Apply the solution to the iteration pattern as well.
30173018
Pattern *pattern = Stmt->getPattern();
@@ -3032,12 +3033,67 @@ auto TypeChecker::typeCheckForEachBinding(
30323033
"Couldn't find sequence conformance");
30333034
Stmt->setSequenceConformance(SequenceConformance);
30343035

3035-
solution.setExprTypes(expr);
3036-
return expr;
3037-
}
3036+
// Check the
3037+
// FIXME: This should be pulled into the constraint system itself.
3038+
if (auto *Where = Stmt->getWhere()) {
3039+
if (!TypeChecker::typeCheckCondition(Where, cs.DC))
3040+
Stmt->setWhere(Where);
3041+
}
3042+
3043+
// Invoke iterator() to get an iterator from the sequence.
3044+
VarDecl *iterator;
3045+
Type nextResultType = OptionalType::get(ElementType);
3046+
{
3047+
// Create a local variable to capture the iterator.
3048+
std::string name;
3049+
if (auto np = dyn_cast_or_null<NamedPattern>(Stmt->getPattern()))
3050+
name = "$"+np->getBoundName().str().str();
3051+
name += "$generator";
3052+
3053+
iterator = new (ctx) VarDecl(
3054+
/*IsStatic*/ false, VarDecl::Introducer::Var,
3055+
/*IsCaptureList*/ false, Stmt->getInLoc(),
3056+
ctx.getIdentifier(name), cs.DC);
3057+
iterator->setInterfaceType(IteratorType->mapTypeOutOfContext());
3058+
iterator->setImplicit();
3059+
Stmt->setIteratorVar(iterator);
3060+
3061+
auto genPat = new (ctx) NamedPattern(iterator);
3062+
genPat->setImplicit();
3063+
3064+
// TODO: test/DebugInfo/iteration.swift requires this extra info to
3065+
// be around.
3066+
PatternBindingDecl::createImplicit(
3067+
ctx, StaticSpellingKind::None, genPat,
3068+
new (ctx) OpaqueValueExpr(Stmt->getInLoc(), nextResultType),
3069+
cs.DC, /*VarLoc*/ Stmt->getForLoc());
3070+
}
30383071

3039-
ForEachBinding getBinding() const {
3040-
return { SequenceType, SequenceConformance, IteratorType, ElementType };
3072+
// Create the iterator variable.
3073+
auto *varRef = TypeChecker::buildCheckedRefExpr(
3074+
iterator, cs.DC, DeclNameLoc(Stmt->getInLoc()), /*implicit*/ true);
3075+
if (varRef)
3076+
Stmt->setIteratorVarRef(varRef);
3077+
3078+
// Convert that Optional<Element> value to the type of the pattern.
3079+
auto optPatternType = OptionalType::get(Stmt->getPattern()->getType());
3080+
if (!optPatternType->isEqual(nextResultType)) {
3081+
OpaqueValueExpr *elementExpr =
3082+
new (ctx) OpaqueValueExpr(Stmt->getInLoc(), nextResultType,
3083+
/*isPlaceholder=*/true);
3084+
Expr *convertElementExpr = elementExpr;
3085+
if (TypeChecker::typeCheckExpression(
3086+
convertElementExpr, cs.DC,
3087+
TypeLoc::withoutLoc(optPatternType),
3088+
CTP_CoerceOperand).isNull()) {
3089+
return nullptr;
3090+
}
3091+
elementExpr->setIsPlaceholder(false);
3092+
Stmt->setElementExpr(elementExpr);
3093+
Stmt->setConvertElementExpr(convertElementExpr);
3094+
}
3095+
3096+
return expr;
30413097
}
30423098
};
30433099

@@ -3048,8 +3104,8 @@ auto TypeChecker::typeCheckForEachBinding(
30483104
// Type-check the for-each loop sequence and element pattern.
30493105
auto resultTy = TypeChecker::typeCheckExpression(seq, dc, &listener);
30503106
if (!resultTy)
3051-
return None;
3052-
return listener.getBinding();
3107+
return true;
3108+
return false;
30533109
}
30543110

30553111
bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -749,91 +749,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
749749
return nullptr;
750750
}
751751

752-
auto binding = TypeChecker::typeCheckForEachBinding(DC, S);
753-
if (!binding)
752+
if (TypeChecker::typeCheckForEachBinding(DC, S))
754753
return nullptr;
755754

756-
if (auto *Where = S->getWhere()) {
757-
if (TypeChecker::typeCheckCondition(Where, DC))
758-
return nullptr;
759-
S->setWhere(Where);
760-
}
761-
762-
763-
// Retrieve the 'Sequence' protocol.
764-
ProtocolDecl *sequenceProto = TypeChecker::getProtocol(
765-
getASTContext(), S->getForLoc(), KnownProtocolKind::Sequence);
766-
if (!sequenceProto) {
767-
return nullptr;
768-
}
769-
770-
// Retrieve the 'Iterator' protocol.
771-
ProtocolDecl *iteratorProto = TypeChecker::getProtocol(
772-
getASTContext(), S->getForLoc(), KnownProtocolKind::IteratorProtocol);
773-
if (!iteratorProto) {
774-
return nullptr;
775-
}
776-
777-
// Invoke iterator() to get an iterator from the sequence.
778-
Type iteratorTy = binding->iteratorType;
779-
VarDecl *iterator;
780-
Type nextResultType = OptionalType::get(binding->elementType);
781-
{
782-
// Create a local variable to capture the iterator.
783-
std::string name;
784-
if (auto np = dyn_cast_or_null<NamedPattern>(S->getPattern()))
785-
name = "$"+np->getBoundName().str().str();
786-
name += "$generator";
787-
788-
iterator = new (getASTContext()) VarDecl(
789-
/*IsStatic*/ false, VarDecl::Introducer::Var,
790-
/*IsCaptureList*/ false, S->getInLoc(),
791-
getASTContext().getIdentifier(name), DC);
792-
iterator->setInterfaceType(iteratorTy->mapTypeOutOfContext());
793-
iterator->setImplicit();
794-
S->setIteratorVar(iterator);
795-
796-
auto genPat = new (getASTContext()) NamedPattern(iterator);
797-
genPat->setImplicit();
798-
799-
// TODO: test/DebugInfo/iteration.swift requires this extra info to
800-
// be around.
801-
PatternBindingDecl::createImplicit(
802-
getASTContext(), StaticSpellingKind::None, genPat,
803-
new (getASTContext()) OpaqueValueExpr(S->getInLoc(), nextResultType),
804-
DC, /*VarLoc*/ S->getForLoc());
805-
}
806-
807-
// Working with iterators requires Optional.
808-
if (TypeChecker::requireOptionalIntrinsics(getASTContext(), S->getForLoc()))
809-
return nullptr;
810-
811-
// Create the iterator variable.
812-
auto *varRef = TypeChecker::buildCheckedRefExpr(iterator, DC,
813-
DeclNameLoc(S->getInLoc()),
814-
/*implicit*/ true);
815-
if (!varRef)
816-
return nullptr;
817-
S->setIteratorVarRef(varRef);
818-
819-
// Convert that Optional<Element> value to the type of the pattern.
820-
auto optPatternType = OptionalType::get(S->getPattern()->getType());
821-
if (!optPatternType->isEqual(nextResultType)) {
822-
OpaqueValueExpr *elementExpr =
823-
new (getASTContext()) OpaqueValueExpr(S->getInLoc(), nextResultType,
824-
/*isPlaceholder=*/true);
825-
Expr *convertElementExpr = elementExpr;
826-
if (TypeChecker::typeCheckExpression(
827-
convertElementExpr, DC,
828-
TypeLoc::withoutLoc(optPatternType),
829-
CTP_CoerceOperand).isNull()) {
830-
return nullptr;
831-
}
832-
elementExpr->setIsPlaceholder(false);
833-
S->setElementExpr(elementExpr);
834-
S->setConvertElementExpr(convertElementExpr);
835-
}
836-
837755
// Type-check the body of the loop.
838756
AddLabeledStmt loopNest(*this, S);
839757
BraceStmt *Body = S->getBody();

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,19 +1032,10 @@ class TypeChecker final {
10321032
static bool typeCheckBinding(Pattern *&P, Expr *&Init, DeclContext *DC);
10331033
static bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber);
10341034

1035-
/// Information about a type-checked for-each binding.
1036-
struct ForEachBinding {
1037-
Type sequenceType;
1038-
ProtocolConformanceRef sequenceConformance;
1039-
Type iteratorType;
1040-
Type elementType;
1041-
};
1042-
10431035
/// Type-check a for-each loop's pattern binding and sequence together.
10441036
///
1045-
/// \returns the binding, if successful.
1046-
static Optional<ForEachBinding> typeCheckForEachBinding(
1047-
DeclContext *dc, ForEachStmt *stmt);
1037+
/// \returns true if a failure occurred.
1038+
static bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt);
10481039

10491040
/// Compute the set of captures for the given function or closure.
10501041
static void computeCaptures(AnyFunctionRef AFR);

0 commit comments

Comments
 (0)