[AST] Add a enum for type checking state of ClosureExpr's body

This commit is contained in:
Rintaro Ishizaki
2020-07-01 16:04:15 -07:00
parent 0ec7a91e38
commit b1eec26653
8 changed files with 45 additions and 22 deletions

View File

@@ -3759,7 +3759,25 @@ public:
/// { [weak c] (a : Int) -> Int in a + c!.getFoo() } /// { [weak c] (a : Int) -> Int in a + c!.getFoo() }
/// \endcode /// \endcode
class ClosureExpr : public AbstractClosureExpr { 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. /// The range of the brackets of the capture list, if present.
SourceRange BracketRange; SourceRange BracketRange;
@@ -3783,8 +3801,7 @@ class ClosureExpr : public AbstractClosureExpr {
SourceLoc InLoc; SourceLoc InLoc;
/// The explicitly-specified result type. /// The explicitly-specified result type.
llvm::PointerIntPair<TypeExpr *, 1, bool> llvm::PointerIntPair<TypeExpr *, 2, BodyState> ExplicitResultTypeAndBodyState;
ExplicitResultTypeAndSeparatelyChecked;
/// The body of the closure, along with a bit indicating whether it /// The body of the closure, along with a bit indicating whether it
/// was originally just a single expression. /// was originally just a single expression.
@@ -3799,7 +3816,7 @@ public:
BracketRange(bracketRange), BracketRange(bracketRange),
CapturedSelfDecl(capturedSelfDecl), CapturedSelfDecl(capturedSelfDecl),
ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc),
ExplicitResultTypeAndSeparatelyChecked(explicitResultType, false), ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
Body(nullptr) { Body(nullptr) {
setParameterList(params); setParameterList(params);
Bits.ClosureExpr.HasAnonymousClosureVars = false; Bits.ClosureExpr.HasAnonymousClosureVars = false;
@@ -3854,15 +3871,13 @@ public:
Type getExplicitResultType() const { Type getExplicitResultType() const {
assert(hasExplicitResultType() && "No explicit result type"); assert(hasExplicitResultType() && "No explicit result type");
return ExplicitResultTypeAndSeparatelyChecked.getPointer() return ExplicitResultTypeAndBodyState.getPointer()->getInstanceType();
->getInstanceType();
} }
void setExplicitResultType(Type ty); void setExplicitResultType(Type ty);
TypeRepr *getExplicitResultTypeRepr() const { TypeRepr *getExplicitResultTypeRepr() const {
assert(hasExplicitResultType() && "No explicit result type"); assert(hasExplicitResultType() && "No explicit result type");
return ExplicitResultTypeAndSeparatelyChecked.getPointer() return ExplicitResultTypeAndBodyState.getPointer()->getTypeRepr();
->getTypeRepr();
} }
/// Determine whether the closure has a single expression for its /// Determine whether the closure has a single expression for its
@@ -3904,14 +3919,20 @@ public:
/// captured non-weakly). /// captured non-weakly).
bool capturesSelfEnablingImplictSelf() const; bool capturesSelfEnablingImplictSelf() const;
/// Whether this closure's body was type checked separately from its
/// enclosing expression. /// Get the type checking state of this closure's body.
bool wasSeparatelyTypeChecked() const { BodyState getBodyState() const {
return ExplicitResultTypeAndSeparatelyChecked.getInt(); return ExplicitResultTypeAndBodyState.getInt();
}
void setBodyState(BodyState v) {
ExplicitResultTypeAndBodyState.setInt(v);
} }
void setSeparatelyTypeChecked(bool flag = true) { /// Whether this closure's body is/was type checked separately from its
ExplicitResultTypeAndSeparatelyChecked.setInt(flag); /// enclosing expression.
bool isSeparatelyTypeChecked() const {
return getBodyState() == BodyState::SeparatelyTypeChecked ||
getBodyState() == BodyState::ReadyForTypeChecking;
} }
static bool classof(const Expr *E) { static bool classof(const Expr *E) {

View File

@@ -825,7 +825,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
// If the closure was separately type checked and we don't want to // If the closure was separately type checked and we don't want to
// visit separately-checked closure bodies, bail out now. // visit separately-checked closure bodies, bail out now.
if (expr->wasSeparatelyTypeChecked() && if (expr->isSeparatelyTypeChecked() &&
!Walker.shouldWalkIntoSeparatelyCheckedClosure(expr)) !Walker.shouldWalkIntoSeparatelyCheckedClosure(expr))
return expr; return expr;

View File

@@ -1975,7 +1975,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const {
void ClosureExpr::setExplicitResultType(Type ty) { void ClosureExpr::setExplicitResultType(Type ty) {
assert(ty && !ty->hasTypeVariable()); assert(ty && !ty->hasTypeVariable());
ExplicitResultTypeAndSeparatelyChecked.getPointer() ExplicitResultTypeAndBodyState.getPointer()
->setType(MetatypeType::get(ty)); ->setType(MetatypeType::get(ty));
} }

View File

@@ -345,11 +345,13 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
ClosureConstraintApplication application( ClosureConstraintApplication application(
solution, closure, closureFnType->getResult(), rewriteTarget); solution, closure, closureFnType->getResult(), rewriteTarget);
application.visit(fn.getBody()); application.visit(fn.getBody());
closure->setBodyState(ClosureExpr::BodyState::TypeCheckedAtOnce);
return SolutionApplicationToFunctionResult::Success; return SolutionApplicationToFunctionResult::Success;
} }
// Otherwise, we need to delay type checking of the closure until later. // Otherwise, we need to delay type checking of the closure until later.
solution.setExprTypes(closure); solution.setExprTypes(closure);
closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
return SolutionApplicationToFunctionResult::Delay; return SolutionApplicationToFunctionResult::Delay;
} }

View File

@@ -86,7 +86,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
bool walkToDeclPre(Decl *D) override { bool walkToDeclPre(Decl *D) override {
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext())) if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
return !closure->wasSeparatelyTypeChecked(); return !closure->isSeparatelyTypeChecked();
return false; return false;
} }
@@ -1497,7 +1497,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
// Don't walk into nested decls. // Don't walk into nested decls.
bool walkToDeclPre(Decl *D) override { bool walkToDeclPre(Decl *D) override {
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext())) if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
return !closure->wasSeparatelyTypeChecked(); return !closure->isSeparatelyTypeChecked();
return false; return false;
} }

View File

@@ -1136,7 +1136,7 @@ static void findAvailabilityFixItNodes(SourceRange ReferenceRange,
if (Expr *ParentExpr = Parent.getAsExpr()) { if (Expr *ParentExpr = Parent.getAsExpr()) {
auto *ParentClosure = dyn_cast<ClosureExpr>(ParentExpr); auto *ParentClosure = dyn_cast<ClosureExpr>(ParentExpr);
if (!ParentClosure || if (!ParentClosure ||
ParentClosure->wasSeparatelyTypeChecked()) { ParentClosure->isSeparatelyTypeChecked()) {
return false; return false;
} }
} else if (auto *ParentStmt = Parent.getAsStmt()) { } else if (auto *ParentStmt = Parent.getAsStmt()) {

View File

@@ -2008,7 +2008,7 @@ public:
performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false); performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false);
if (auto closure = dyn_cast<ClosureExpr>(expr)) { if (auto closure = dyn_cast<ClosureExpr>(expr)) {
if (closure->wasSeparatelyTypeChecked()) { if (closure->isSeparatelyTypeChecked()) {
dcStack.push_back(closure); dcStack.push_back(closure);
return {true, expr}; return {true, expr};
} }
@@ -2019,7 +2019,7 @@ public:
Expr *walkToExprPost(Expr *expr) override { Expr *walkToExprPost(Expr *expr) override {
if (auto closure = dyn_cast<ClosureExpr>(expr)) { if (auto closure = dyn_cast<ClosureExpr>(expr)) {
if (closure->wasSeparatelyTypeChecked()) { if (closure->isSeparatelyTypeChecked()) {
assert(dcStack.back() == closure); assert(dcStack.back() == closure);
dcStack.pop_back(); dcStack.pop_back();
} }

View File

@@ -143,7 +143,7 @@ namespace {
// If the closure was type checked within its enclosing context, // If the closure was type checked within its enclosing context,
// we need to walk into it with a new sequence. // we need to walk into it with a new sequence.
// Otherwise, it'll have been separately type-checked. // Otherwise, it'll have been separately type-checked.
if (!CE->wasSeparatelyTypeChecked()) if (!CE->isSeparatelyTypeChecked())
CE->getBody()->walk(ContextualizeClosures(CE)); CE->getBody()->walk(ContextualizeClosures(CE));
TypeChecker::computeCaptures(CE); TypeChecker::computeCaptures(CE);
@@ -1976,7 +1976,7 @@ bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
if (body) { if (body) {
closure->setBody(body, closure->hasSingleExpressionBody()); closure->setBody(body, closure->hasSingleExpressionBody());
} }
closure->setSeparatelyTypeChecked(); closure->setBodyState(ClosureExpr::BodyState::SeparatelyTypeChecked);
return HadError; return HadError;
} }