diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 562f39ddd36..f0c1d51ef63 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3759,7 +3759,25 @@ public: /// { [weak c] (a : Int) -> Int in a + c!.getFoo() } /// \endcode class ClosureExpr : public AbstractClosureExpr { +public: + enum class BodyState { + /// The body was parsed, but not ready for type checking because + /// the closure parameters haven't been type checked. + Parsed, + /// The type of the closure itself was type checked. But the body has not + /// been type checked yet. + ReadyForTypeChecking, + + /// The body was typechecked with the enclosing closure. + /// i.e. single expression closure or function builder closure. + TypeCheckedAtOnce, + + /// The body was type checked separately from the enclosing closure. + SeparatelyTypeChecked, + }; + +private: /// The range of the brackets of the capture list, if present. SourceRange BracketRange; @@ -3783,8 +3801,7 @@ class ClosureExpr : public AbstractClosureExpr { SourceLoc InLoc; /// The explicitly-specified result type. - llvm::PointerIntPair - ExplicitResultTypeAndSeparatelyChecked; + llvm::PointerIntPair ExplicitResultTypeAndBodyState; /// The body of the closure, along with a bit indicating whether it /// was originally just a single expression. @@ -3799,7 +3816,7 @@ public: BracketRange(bracketRange), CapturedSelfDecl(capturedSelfDecl), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), - ExplicitResultTypeAndSeparatelyChecked(explicitResultType, false), + ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed), Body(nullptr) { setParameterList(params); Bits.ClosureExpr.HasAnonymousClosureVars = false; @@ -3854,15 +3871,13 @@ public: Type getExplicitResultType() const { assert(hasExplicitResultType() && "No explicit result type"); - return ExplicitResultTypeAndSeparatelyChecked.getPointer() - ->getInstanceType(); + return ExplicitResultTypeAndBodyState.getPointer()->getInstanceType(); } void setExplicitResultType(Type ty); TypeRepr *getExplicitResultTypeRepr() const { assert(hasExplicitResultType() && "No explicit result type"); - return ExplicitResultTypeAndSeparatelyChecked.getPointer() - ->getTypeRepr(); + return ExplicitResultTypeAndBodyState.getPointer()->getTypeRepr(); } /// Determine whether the closure has a single expression for its @@ -3904,14 +3919,20 @@ public: /// captured non-weakly). bool capturesSelfEnablingImplictSelf() const; - /// Whether this closure's body was type checked separately from its - /// enclosing expression. - bool wasSeparatelyTypeChecked() const { - return ExplicitResultTypeAndSeparatelyChecked.getInt(); + + /// Get the type checking state of this closure's body. + BodyState getBodyState() const { + return ExplicitResultTypeAndBodyState.getInt(); + } + void setBodyState(BodyState v) { + ExplicitResultTypeAndBodyState.setInt(v); } - void setSeparatelyTypeChecked(bool flag = true) { - ExplicitResultTypeAndSeparatelyChecked.setInt(flag); + /// Whether this closure's body is/was type checked separately from its + /// enclosing expression. + bool isSeparatelyTypeChecked() const { + return getBodyState() == BodyState::SeparatelyTypeChecked || + getBodyState() == BodyState::ReadyForTypeChecking; } static bool classof(const Expr *E) { diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index be0fbc3a799..f8756780ae6 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -825,7 +825,7 @@ class Traversal : public ASTVisitorwasSeparatelyTypeChecked() && + if (expr->isSeparatelyTypeChecked() && !Walker.shouldWalkIntoSeparatelyCheckedClosure(expr)) return expr; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 43e5b4aee55..a5e5fc3e78d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1975,7 +1975,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const { void ClosureExpr::setExplicitResultType(Type ty) { assert(ty && !ty->hasTypeVariable()); - ExplicitResultTypeAndSeparatelyChecked.getPointer() + ExplicitResultTypeAndBodyState.getPointer() ->setType(MetatypeType::get(ty)); } diff --git a/lib/Sema/CSClosure.cpp b/lib/Sema/CSClosure.cpp index 0fd1b69529a..ef7871bef91 100644 --- a/lib/Sema/CSClosure.cpp +++ b/lib/Sema/CSClosure.cpp @@ -345,11 +345,13 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution( ClosureConstraintApplication application( solution, closure, closureFnType->getResult(), rewriteTarget); application.visit(fn.getBody()); + closure->setBodyState(ClosureExpr::BodyState::TypeCheckedAtOnce); return SolutionApplicationToFunctionResult::Success; } // Otherwise, we need to delay type checking of the closure until later. solution.setExprTypes(closure); + closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking); return SolutionApplicationToFunctionResult::Delay; } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 2592c6069ae..4a435d51f20 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -86,7 +86,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, bool walkToDeclPre(Decl *D) override { if (auto *closure = dyn_cast(D->getDeclContext())) - return !closure->wasSeparatelyTypeChecked(); + return !closure->isSeparatelyTypeChecked(); return false; } @@ -1497,7 +1497,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // Don't walk into nested decls. bool walkToDeclPre(Decl *D) override { if (auto *closure = dyn_cast(D->getDeclContext())) - return !closure->wasSeparatelyTypeChecked(); + return !closure->isSeparatelyTypeChecked(); return false; } diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index b6c1f91dd7b..88661330d3f 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -1136,7 +1136,7 @@ static void findAvailabilityFixItNodes(SourceRange ReferenceRange, if (Expr *ParentExpr = Parent.getAsExpr()) { auto *ParentClosure = dyn_cast(ParentExpr); if (!ParentClosure || - ParentClosure->wasSeparatelyTypeChecked()) { + ParentClosure->isSeparatelyTypeChecked()) { return false; } } else if (auto *ParentStmt = Parent.getAsStmt()) { diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 2910fe3a96e..7b5a913a245 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2008,7 +2008,7 @@ public: performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false); if (auto closure = dyn_cast(expr)) { - if (closure->wasSeparatelyTypeChecked()) { + if (closure->isSeparatelyTypeChecked()) { dcStack.push_back(closure); return {true, expr}; } @@ -2019,7 +2019,7 @@ public: Expr *walkToExprPost(Expr *expr) override { if (auto closure = dyn_cast(expr)) { - if (closure->wasSeparatelyTypeChecked()) { + if (closure->isSeparatelyTypeChecked()) { assert(dcStack.back() == closure); dcStack.pop_back(); } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 0348f5065f5..2025470624a 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -143,7 +143,7 @@ namespace { // If the closure was type checked within its enclosing context, // we need to walk into it with a new sequence. // Otherwise, it'll have been separately type-checked. - if (!CE->wasSeparatelyTypeChecked()) + if (!CE->isSeparatelyTypeChecked()) CE->getBody()->walk(ContextualizeClosures(CE)); TypeChecker::computeCaptures(CE); @@ -1976,7 +1976,7 @@ bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) { if (body) { closure->setBody(body, closure->hasSingleExpressionBody()); } - closure->setSeparatelyTypeChecked(); + closure->setBodyState(ClosureExpr::BodyState::SeparatelyTypeChecked); return HadError; }