Skip to content

[Typed throws] Make try? and try! into catch nodes #70283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 7, 2023
Merged
466 changes: 321 additions & 145 deletions include/swift/AST/ASTScope.h

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions include/swift/AST/ASTScopeNodes.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//===--- ASTScopeNodes.def - Node kinds for the ASTScope tree ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines all of the kinds of ASTScope nodes.
//
// The primary macro to define before including this file is SCOPE_NODE(Name),
// which provides the name of the scope node (without the "Scope" suffix).
// There are several more specific macros that can be defined to get more
// specific information about certain kinds of nodes:
//
// DECL_SCOPE_NODE(Name) - A scope node associated with a declaration.
// STMT_SCOPE_NODE(Name) - A scope node associated with a statement.
// EXPR_SCOPE_NODE(Name) - A scope node associated with an expression.
// DECL_ATTRIBUTE_SCOPE_NODE(Name) - A scope node associated with a
// declaration attribute.
//
// For each of these that is not defined on inclusion of this file, a
// definition in terms of SCOPE_NODE will be provided, allowing clients to
// define only SCOPE_NODE to deal with all scope nodes.
//===----------------------------------------------------------------------===//

#ifndef SCOPE_NODE
# error "define SCOPE_NODE(Name) when enumerating ASTScope nodes
# define SCOPE_NODE(Name)
#endif

#ifndef DECL_SCOPE_NODE
# define DECL_SCOPE_NODE(Name) SCOPE_NODE(Name)
#endif

#ifndef STMT_SCOPE_NODE
# define STMT_SCOPE_NODE(Name) SCOPE_NODE(Name)
#endif

#ifndef EXPR_SCOPE_NODE
# define EXPR_SCOPE_NODE(Name) SCOPE_NODE(Name)
#endif

#ifndef DECL_ATTRIBUTE_SCOPE_NODE
# define DECL_ATTRIBUTE_SCOPE_NODE(Name) SCOPE_NODE(Name)
#endif

SCOPE_NODE(ASTSourceFile)
DECL_SCOPE_NODE(NominalType)
DECL_SCOPE_NODE(Extension)
DECL_SCOPE_NODE(TypeAlias)
DECL_SCOPE_NODE(OpaqueType)
SCOPE_NODE(GenericParam)
DECL_SCOPE_NODE(AbstractFunctionDecl)
SCOPE_NODE(ParameterList)
DECL_SCOPE_NODE(FunctionBody)
DECL_SCOPE_NODE(DefaultArgumentInitializer)
DECL_ATTRIBUTE_SCOPE_NODE(CustomAttribute)
DECL_SCOPE_NODE(PatternEntryDecl)
DECL_SCOPE_NODE(PatternEntryInitializer)
SCOPE_NODE(ConditionalClausePatternUse)
SCOPE_NODE(ConditionalClauseInitializer)
EXPR_SCOPE_NODE(CaptureList)
EXPR_SCOPE_NODE(ClosureParameters)
DECL_SCOPE_NODE(TopLevelCode)
DECL_ATTRIBUTE_SCOPE_NODE(SpecializeAttribute)
DECL_ATTRIBUTE_SCOPE_NODE(DifferentiableAttribute)
DECL_SCOPE_NODE(SubscriptDecl)
DECL_SCOPE_NODE(EnumElement)
DECL_SCOPE_NODE(MacroDecl)
SCOPE_NODE(MacroDefinition)
DECL_SCOPE_NODE(MacroExpansionDecl)
STMT_SCOPE_NODE(IfStmt)
STMT_SCOPE_NODE(WhileStmt)
STMT_SCOPE_NODE(GuardStmt)
SCOPE_NODE(GuardStmtBody)
STMT_SCOPE_NODE(RepeatWhile)
STMT_SCOPE_NODE(DoStmt)
STMT_SCOPE_NODE(DoCatchStmt)
STMT_SCOPE_NODE(SwitchStmt)
STMT_SCOPE_NODE(ForEachStmt)
SCOPE_NODE(ForEachPattern)
STMT_SCOPE_NODE(CaseStmt)
SCOPE_NODE(CaseLabelItem)
SCOPE_NODE(CaseStmtBody)
STMT_SCOPE_NODE(BraceStmt)
EXPR_SCOPE_NODE(Try)

#undef DECL_ATTRIBUTE_SCOPE_NODE
#undef EXPR_SCOPE_NODE
#undef STMT_SCOPE_NODE
#undef DECL_SCOPE_NODE
#undef SCOPE_NODE
2 changes: 1 addition & 1 deletion include/swift/AST/CatchNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace swift {
/// An AST node that represents a point where a thrown error can be caught and
/// or rethrown, which includes functions do...catch statements.
class CatchNode: public llvm::PointerUnion<
AbstractFunctionDecl *, AbstractClosureExpr *, DoCatchStmt *
AbstractFunctionDecl *, AbstractClosureExpr *, DoCatchStmt *, AnyTryExpr *
> {
public:
using PointerUnion::PointerUnion;
Expand Down
156 changes: 59 additions & 97 deletions lib/AST/ASTScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,66 +98,76 @@ Pattern *AbstractPatternEntryScope::getPattern() const {
}

NullablePtr<AbstractClosureExpr> BraceStmtScope::parentClosureIfAny() const {
return !getParent() ? nullptr : getParent().get()->getClosureIfClosureScope();
}

NullablePtr<const BraceStmtScope> BraceStmtScope::getAsBraceStmtScope() const {
return this;
}
if (auto parent = getParent()) {
if (auto closureScope = dyn_cast<ClosureParametersScope>(parent.get()))
return closureScope->closureExpr;
}

NullablePtr<AbstractClosureExpr> ASTScopeImpl::getClosureIfClosureScope() const {
return nullptr;
}

NullablePtr<const BraceStmtScope> ASTScopeImpl::getAsBraceStmtScope() const {
return nullptr;
}
std::string ASTScopeImpl::getClassName() const {
// GenericTypeOrExtensionScope provides a custom implementation that deals
// with declaration names and "portions".
if (auto generic = dyn_cast<GenericTypeOrExtensionScope>(this))
return generic->getClassName();

std::pair<CatchNode, const BraceStmtScope *>
ASTScopeImpl::getCatchNodeBody() const {
return { nullptr, nullptr };
switch (getKind()) {
#define SCOPE_NODE(Name) case ScopeKind::Name: return #Name "Scope";
#include "swift/AST/ASTScopeNodes.def"
}
}

std::pair<CatchNode, const BraceStmtScope *>
ClosureParametersScope::getCatchNodeBody() const {
const BraceStmtScope *body = nullptr;
const auto &children = getChildren();
if (!children.empty()) {
body = children[0]->getAsBraceStmtScope().getPtrOrNull();
assert(body && "Not a brace statement?");
}
return { const_cast<AbstractClosureExpr *>(closureExpr), body };
std::string GenericTypeOrExtensionScope::getClassName() const {
return declKindName() + portionName() + "Scope";
}

std::pair<CatchNode, const BraceStmtScope *>
FunctionBodyScope::getCatchNodeBody() const {
const BraceStmtScope *body = nullptr;
const auto &children = getChildren();
if (!children.empty()) {
body = children[0]->getAsBraceStmtScope().getPtrOrNull();
assert(body && "Not a brace statement?");
NullablePtr<Decl> ASTScopeImpl::getDeclIfAny() const {
switch (getKind()) {
// Declaration scope nodes extract the decl directly.
#define DECL_SCOPE_NODE(Name) \
case ScopeKind::Name: return cast<Name##Scope>(this)->getDecl();
#define SCOPE_NODE(Name)
#include "swift/AST/ASTScopeNodes.def"

// Everything else returns nullptr.
#define DECL_SCOPE_NODE(Name)
#define SCOPE_NODE(Name) case ScopeKind::Name:
#include "swift/AST/ASTScopeNodes.def"
return nullptr;
}
return { const_cast<AbstractFunctionDecl *>(decl), body };
}

/// Determine whether this is an empty brace statement, which doesn't have a
/// node associated with it.
static bool isEmptyBraceStmt(Stmt *stmt) {
if (auto braceStmt = dyn_cast_or_null<BraceStmt>(stmt))
return braceStmt->empty();
NullablePtr<Stmt> ASTScopeImpl::getStmtIfAny() const {
switch (getKind()) {
// Statement scope nodes extract the statement directly.
#define STMT_SCOPE_NODE(Name) \
case ScopeKind::Name: return cast<Name##Scope>(this)->getStmt();
#define SCOPE_NODE(Name)
#include "swift/AST/ASTScopeNodes.def"

return false;
// Everything else returns nullptr.
#define STMT_SCOPE_NODE(Name)
#define SCOPE_NODE(Name) case ScopeKind::Name:
#include "swift/AST/ASTScopeNodes.def"
return nullptr;
}
}

std::pair<CatchNode, const BraceStmtScope *>
DoCatchStmtScope::getCatchNodeBody() const {
const BraceStmtScope *body = nullptr;
const auto &children = getChildren();
if (!children.empty() && !isEmptyBraceStmt(stmt->getBody())) {
body = children[0]->getAsBraceStmtScope().getPtrOrNull();
assert(body && "Not a brace statement?");
NullablePtr<Expr> ASTScopeImpl::getExprIfAny() const {
switch (getKind()) {
// Expression scope nodes extract the statement directly.
#define EXPR_SCOPE_NODE(Name) \
case ScopeKind::Name: return cast<Name##Scope>(this)->getExpr();
#define SCOPE_NODE(Name)
#include "swift/AST/ASTScopeNodes.def"

// Everything else returns nullptr.
#define EXPR_SCOPE_NODE(Name)
#define SCOPE_NODE(Name) case ScopeKind::Name:
#include "swift/AST/ASTScopeNodes.def"
return nullptr;
}
return { const_cast<DoCatchStmt *>(stmt), body };
}

SourceManager &ASTScopeImpl::getSourceManager() const {
Expand Down Expand Up @@ -185,66 +195,18 @@ LabeledConditionalStmt *GuardStmtScope::getLabeledConditionalStmt() const {
ASTContext &ASTScopeImpl::getASTContext() const {
if (auto d = getDeclIfAny())
return d.get()->getASTContext();
if (auto sfScope = dyn_cast<ASTSourceFileScope>(this))
return sfScope->SF->getASTContext();
return getParent().get()->getASTContext();
}

#pragma mark getClassName

std::string GenericTypeOrExtensionScope::getClassName() const {
return declKindName() + portionName() + "Scope";
}

#define DEFINE_GET_CLASS_NAME(Name) \
std::string Name::getClassName() const { return #Name; }

DEFINE_GET_CLASS_NAME(ASTSourceFileScope)
DEFINE_GET_CLASS_NAME(GenericParamScope)
DEFINE_GET_CLASS_NAME(AbstractFunctionDeclScope)
DEFINE_GET_CLASS_NAME(ParameterListScope)
DEFINE_GET_CLASS_NAME(FunctionBodyScope)
DEFINE_GET_CLASS_NAME(DefaultArgumentInitializerScope)
DEFINE_GET_CLASS_NAME(CustomAttributeScope)
DEFINE_GET_CLASS_NAME(PatternEntryDeclScope)
DEFINE_GET_CLASS_NAME(PatternEntryInitializerScope)
DEFINE_GET_CLASS_NAME(ConditionalClausePatternUseScope)
DEFINE_GET_CLASS_NAME(ConditionalClauseInitializerScope)
DEFINE_GET_CLASS_NAME(CaptureListScope)
DEFINE_GET_CLASS_NAME(ClosureParametersScope)
DEFINE_GET_CLASS_NAME(TopLevelCodeScope)
DEFINE_GET_CLASS_NAME(SpecializeAttributeScope)
DEFINE_GET_CLASS_NAME(DifferentiableAttributeScope)
DEFINE_GET_CLASS_NAME(SubscriptDeclScope)
DEFINE_GET_CLASS_NAME(EnumElementScope)
DEFINE_GET_CLASS_NAME(MacroDeclScope)
DEFINE_GET_CLASS_NAME(MacroDefinitionScope)
DEFINE_GET_CLASS_NAME(MacroExpansionDeclScope)
DEFINE_GET_CLASS_NAME(IfStmtScope)
DEFINE_GET_CLASS_NAME(WhileStmtScope)
DEFINE_GET_CLASS_NAME(GuardStmtScope)
DEFINE_GET_CLASS_NAME(GuardStmtBodyScope)
DEFINE_GET_CLASS_NAME(RepeatWhileScope)
DEFINE_GET_CLASS_NAME(DoStmtScope)
DEFINE_GET_CLASS_NAME(DoCatchStmtScope)
DEFINE_GET_CLASS_NAME(SwitchStmtScope)
DEFINE_GET_CLASS_NAME(ForEachStmtScope)
DEFINE_GET_CLASS_NAME(ForEachPatternScope)
DEFINE_GET_CLASS_NAME(CaseStmtScope)
DEFINE_GET_CLASS_NAME(CaseLabelItemScope)
DEFINE_GET_CLASS_NAME(CaseStmtBodyScope)
DEFINE_GET_CLASS_NAME(BraceStmtScope)

#undef DEFINE_GET_CLASS_NAME

#pragma mark getSourceFile

const SourceFile *ASTScopeImpl::getSourceFile() const {
return getParent().get()->getSourceFile();
}
if (auto sourceFileScope = dyn_cast<ASTSourceFileScope>(this))
return sourceFileScope->SF;

const SourceFile *ASTSourceFileScope::getSourceFile() const { return SF; }

ASTContext &ASTSourceFileScope::getASTContext() const {
return SF->getASTContext();
return getParent().get()->getSourceFile();
}

SourceRange ExtensionScope::getBraces() const { return decl->getBraces(); }
Expand Down
24 changes: 19 additions & 5 deletions lib/AST/ASTScopeCreation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class ScopeCreator final : public ASTAllocated<ScopeCreator> {
ASTScopeAssert(expr,
"If looking for closures, must have an expression to search.");

/// AST walker that finds nested scopes in expressions. This handles both
/// closures and if/switch expressions.
/// AST walker that finds nested scopes in expressions. This handles
/// closures, if/switch expressions, and try/try!/try? expressions.
class NestedExprScopeFinder : public ASTWalker {
ScopeCreator &scopeCreator;
ASTScopeImpl *parent;
Expand Down Expand Up @@ -130,6 +130,13 @@ class ScopeCreator final : public ASTAllocated<ScopeCreator> {
scopeCreator.addToScopeTree(SVE->getStmt(), parent);
return Action::SkipChildren(E);
}

// If we have a try/try!/try?, we need to add a scope for it
if (auto anyTry = dyn_cast<AnyTryExpr>(E)) {
scopeCreator.constructExpandAndInsert<TryScope>(parent, anyTry);
return Action::SkipChildren(E);
}

return Action::Continue(E);
}
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
Expand Down Expand Up @@ -259,7 +266,8 @@ void ASTSourceFileScope::expandFunctionBody(AbstractFunctionDecl *AFD) {

ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
ScopeCreator *scopeCreator)
: SF(SF), scopeCreator(scopeCreator) {
: ASTScopeImpl(ScopeKind::ASTSourceFile), SF(SF),
scopeCreator(scopeCreator) {
if (auto enclosingSF = SF->getEnclosingSourceFile()) {
SourceLoc parentLoc;
auto macroRole = SF->getFulfilledMacroRole();
Expand Down Expand Up @@ -761,6 +769,7 @@ NO_NEW_INSERTION_POINT(MacroDefinitionScope)
NO_NEW_INSERTION_POINT(MacroExpansionDeclScope)
NO_NEW_INSERTION_POINT(SwitchStmtScope)
NO_NEW_INSERTION_POINT(WhileStmtScope)
NO_NEW_INSERTION_POINT(TryScope)

NO_EXPANSION(GenericParamScope)
NO_EXPANSION(SpecializeAttributeScope)
Expand Down Expand Up @@ -1314,8 +1323,8 @@ ASTScopeImpl *LabeledConditionalStmtScope::createNestedConditionalClauseScopes(
}

AbstractPatternEntryScope::AbstractPatternEntryScope(
PatternBindingDecl *declBeingScoped, unsigned entryIndex)
: decl(declBeingScoped), patternEntryIndex(entryIndex) {
ScopeKind kind, PatternBindingDecl *declBeingScoped, unsigned entryIndex)
: ASTScopeImpl(kind), decl(declBeingScoped), patternEntryIndex(entryIndex) {
ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(),
"out of bounds");
}
Expand Down Expand Up @@ -1371,6 +1380,11 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion(
return s->getParent().get();
}

void TryScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(expr->getSubExpr(), this);
}

#pragma mark verification

void ast_scope::simple_display(llvm::raw_ostream &out,
Expand Down
Loading