Skip to content

[TypeChecker] Incremental multi-statement closure type-checking (disabled by default) #38577

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 76 commits into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
a1c0823
[AST] Add a flag to guard exprimental multi-statement closures feature
xedin Jul 7, 2021
eb8eabf
[ConstraintSystem] Add a skeleton of `ClosureBodyElement` constraint
xedin Jul 9, 2021
2b46910
[ConstraintSystem] Add a skeleton of `Conjunction` constraint
xedin Jul 10, 2021
2377f05
[ConstraintSystem] Add a conjunction element producer
xedin Jul 13, 2021
27275f6
[CSStep] Add an implementation of `ConjunctionStep`
xedin Jul 13, 2021
6aaee59
[ConstraintSystem] Allow conjunction constraints to reference other v…
xedin Jul 13, 2021
73dffb3
[ConstraintSystem] Don't require a type variable per closure body ele…
xedin Jul 14, 2021
ad01027
[ConstraintSystem] Allow `closure body element` constraint to referen…
xedin Jul 14, 2021
f344007
[CSSimplify] Implement conjunction element simplification
xedin Jul 16, 2021
0324a4c
[ConstraintSystem] Implement new required methods in `ConjunctionElem…
xedin Jul 19, 2021
9073d00
[ConstraintSystem] Allow conjunctions marking conjunctions as isolate…
xedin Jul 19, 2021
95119f1
[CSSolver] Don't select disabled conjunctions
xedin Jul 19, 2021
698ea82
[Constraint] Implement `gatherReferencedVariables` for closure body e…
xedin Jul 20, 2021
15aa8ed
[ASTNode] Add a new element - statement condition
xedin Jul 21, 2021
84ca85d
[ConstraintLocator] Add a new element to track closure body elements
xedin Jul 21, 2021
7d48814
[TypeChecker] Integrate experimental multi-statement closures flag in…
xedin Jul 21, 2021
441f807
[ConstraintSystem] Expose type variables referenced by conjunction el…
xedin Jul 22, 2021
28d1bac
[ConstraintSystem] Implement conjunction step
xedin Jul 22, 2021
91eecdb
[CSClosure] Initial support for multi-statement closures
xedin Jul 22, 2021
2b7602e
[CSClosure] Implement constraint generation for closure body elements
xedin Jul 22, 2021
1fa7e1d
[CSStep] Fail conjunction if element attempt fails
xedin Jul 23, 2021
d3967f2
[AST] Allow to acquire a pointer to statement condition
xedin Jul 23, 2021
a2d4ae3
[ConstraintSystem/Closures] Add support for `if` statement
xedin Jul 23, 2021
d814905
[CSClosure] NFC: Simplify creation of non-isolated conjunctions for a…
xedin Jul 23, 2021
a37b546
[CSClosure] Mark empty brace statements as non-viable elements
xedin Jul 23, 2021
f05ec83
[CSStep] Filter solutions after each conjunction step
xedin Jul 24, 2021
405034f
[CSStep] Always restore snapshot once isolated conjunction step is done
xedin Jul 24, 2021
528c696
[Constraint] Don't propagate variables from elements to conjunction
xedin Jul 25, 2021
cedb345
[CSClosure] Further simplify conjunction creation for ASTNode elements
xedin Jul 25, 2021
98a6a84
[CSStep] Conjunction: integrate isolation scope into snapshot
xedin Jul 27, 2021
391b0c6
[ConstraintSystem/Closures] Add support for `guard` statement
xedin Jul 27, 2021
f999fa2
[ConstraintSystem/Closures] Add support for `while` statement
xedin Jul 29, 2021
34538ef
[ConstraintSystem/Closures] Add support for `do` statement
xedin Jul 29, 2021
d74cb79
[ConstraintSystem/Closures] Add support for `repeat .. while` statement
xedin Jul 29, 2021
55bae61
[Constraint] Allow closure body elements to carry contextual information
xedin Aug 2, 2021
9d89ae0
[ConstraintSystem] Let closure body element simplification take advan…
xedin Aug 2, 2021
00e98ff
[ConstraintSystem/Closures] Add support for `fallthrough` statement
xedin Aug 2, 2021
880d862
[ConstraintSystem/Closures] Add support for `defer` statement
xedin Aug 2, 2021
f6398d6
[ConstraintSystem/Closures] Add support for `break` statement
xedin Aug 3, 2021
32b257b
[ConstraintSystem/Closures] Add support for `continue` statement
xedin Aug 3, 2021
305437c
[ConstraintSystem/Closures] Add support for `#assert` statement
xedin Aug 3, 2021
8929d7e
[ConstraintSystem/Closures] Add support for `throw` statement
xedin Aug 3, 2021
7197fac
[ConstraintSystem] Add a new contextual purpose - CTP_ForEachSequence
xedin Aug 4, 2021
b1d6d3a
[ConstraintSystem/Closures] Add support for `for-in` statement
xedin Aug 4, 2021
df00e3e
[ASTNode] Add a new element - case item
xedin Aug 7, 2021
99a9828
[ConstraintSystem] Add a new contextual purpose - CTP_CaseStmt
xedin Aug 7, 2021
c712d07
[PreCheck] Don't attempt to pre-check patterns
xedin Aug 9, 2021
0247652
[ConstraintSystem/Closures] Add support for `case` statement
xedin Aug 9, 2021
1324d1f
[ConstraintSystem/Closures] Add support for `switch` statement
xedin Aug 10, 2021
dea609f
[ConstraintSystem/Closures] Add support for `do-catch` statement
xedin Aug 10, 2021
c68a74a
[ConstraintSystem/Closures] Allow `return` without result expression
xedin Aug 10, 2021
0104080
[PreCheck] Don't walk into any declaration besides `PatternBindingDecl`
xedin Aug 11, 2021
ff4aca3
[ConstraintSystem/Closures] Ignore all unsupported declarations durin…
xedin Aug 11, 2021
c554fca
[CSStep] Isolated conjunctions can't see outer solutions
xedin Aug 24, 2021
e3aa377
[ConstraintSystem] Allow default initialized patterns
xedin Aug 25, 2021
fba8088
[CSClosure] Mark conjunctions representing closure body as isolated
xedin Aug 26, 2021
73f9392
[AST] Allow pattern bindings to be marked as fully verified
xedin Aug 27, 2021
d5e9a39
[CSApply] Mark pattern target as fully verified
xedin Aug 27, 2021
598b850
[CSClosure] Allow all declarations to use `typeCheckDecl`
xedin Aug 27, 2021
10fa811
[CSStep] Conjunctions representing closures affect declaration context
xedin Aug 27, 2021
8867a8d
[CSApply] Delay solution application to multi-statement closure bodies
xedin Aug 31, 2021
fed705d
[CSClosure] Account for partially resolved inner parameter types
xedin Aug 31, 2021
da3cef2
[ResultBuilders] Fix a crash in `PreCheckResultBuilderApplication`
xedin Aug 31, 2021
67a7214
[ConstraintSystem] Compute variables referenced by conjunction elemen…
xedin Sep 1, 2021
dfe6c34
[CSClosure] Avoid creating conjunctions for empty bodies
xedin Sep 1, 2021
bc14f00
[CSClosure] Link closure conjunction with referenced outer parameters
xedin Sep 2, 2021
9087613
[CSApply] Set types for for all delayed closures
xedin Sep 8, 2021
1dd76d8
[CSClosure] Avoid function conversion when closure result type is opt…
xedin Sep 21, 2021
29ec113
[CSClosures] Model `return` statements as solution application targets
xedin Sep 22, 2021
50af68d
[CSClosure] Handle pattern and sequence of for-in loop together
xedin Sep 24, 2021
b7b492f
[CSClosure] Check parameters after solution is applied to the body of…
xedin Sep 24, 2021
e5db01b
[CSClosure] Make sure that `case` body variables get types
xedin Oct 5, 2021
b8cfaf7
[CSClosure] Make sure that partially resolved params/result gets thei…
xedin Oct 6, 2021
18b23aa
[CSClosure] NFC: Add size to a `SmallVector` in `ClosureConstraintGen…
xedin Oct 8, 2021
87f41a9
[CSClosure] Check multi-statement closure attrs only in if inference …
xedin Oct 8, 2021
f074305
[PreCheck] Allow pre-check to walk into patterns when multi-statement…
xedin Oct 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions include/swift/AST/ASTNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef SWIFT_AST_AST_NODE_H
#define SWIFT_AST_AST_NODE_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerUnion.h"
#include "swift/Basic/Debug.h"
#include "swift/AST/TypeAlignments.h"
Expand All @@ -35,13 +36,18 @@ namespace swift {
class SourceLoc;
class SourceRange;
class ASTWalker;
class StmtConditionElement;
class CaseLabelItem;
enum class ExprKind : uint8_t;
enum class DeclKind : uint8_t;
enum class PatternKind : uint8_t;
enum class StmtKind;

struct ASTNode : public llvm::PointerUnion<Expr *, Stmt *, Decl *, Pattern *,
TypeRepr *> {
using StmtCondition = llvm::MutableArrayRef<StmtConditionElement>;

struct ASTNode
: public llvm::PointerUnion<Expr *, Stmt *, Decl *, Pattern *, TypeRepr *,
StmtCondition *, CaseLabelItem *> {
// Inherit the constructors from PointerUnion.
using PointerUnion::PointerUnion;

Expand Down
7 changes: 6 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1805,7 +1805,12 @@ class PatternBindingDecl final : public Decl,
return getPatternList()[i].getPattern();
}

void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext);
void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext,
bool isFullyValidated = false);

bool isFullyValidated(unsigned i) const {
return getPatternList()[i].isFullyValidated();
}

DeclContext *getInitContext(unsigned i) const {
return getPatternList()[i].getInitContext();
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,10 @@ class LabeledConditionalStmt : public LabeledStmt {
StmtCondition getCond() const { return Cond; }
void setCond(StmtCondition e);

/// FIXME: Find a better way to implement this. Allows conditions to be
/// stored in \c ASTNode.
StmtCondition *getCondPointer() { return &Cond; }

static bool classof(const Stmt *S) {
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&
S->getKind() <= StmtKind::Last_LabeledConditionalStmt;
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeAlignments.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace swift {
class TypeDecl;
class TypeRepr;
class ValueDecl;
class CaseLabelItem;

/// We frequently use three tag bits on all of these types.
constexpr size_t AttrAlignInBits = 3;
Expand Down Expand Up @@ -151,6 +152,8 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::AttributeBase, swift::AttrAlignInBits)

LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeRepr, swift::TypeReprAlignInBits)

LLVM_DECLARE_TYPE_ALIGNMENT(swift::CaseLabelItem, swift::PatternAlignInBits);

static_assert(alignof(void*) >= 2, "pointer alignment is too small");

#endif
4 changes: 4 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ namespace swift {
/// parameters of closures.
bool EnableOneWayClosureParameters = false;

/// Enable experimental support for type inference through multi-statement
/// closures.
bool EnableMultiStatementClosureInference = false;

/// See \ref FrontendOptions.PrintFullConvention
bool PrintFullConvention = false;
};
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,10 @@ def experimental_one_way_closure_params :
Flag<["-"], "experimental-one-way-closure-params">,
HelpText<"Enable experimental support for one-way closure parameters">;

def experimental_multi_statement_closures :
Flag<["-"], "experimental-multi-statement-closures">,
HelpText<"Enable experimental support for type inference in multi-statement closures">;

def prebuilt_module_cache_path :
Separate<["-"], "prebuilt-module-cache-path">,
HelpText<"Directory of prebuilt modules for loading module interfaces">;
Expand Down
103 changes: 100 additions & 3 deletions include/swift/Sema/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
#ifndef SWIFT_SEMA_CONSTRAINT_H
#define SWIFT_SEMA_CONSTRAINT_H

#include "swift/AST/ASTNode.h"
#include "swift/AST/FunctionRefKind.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeLoc.h"
#include "swift/Basic/Debug.h"
#include "swift/Sema/ConstraintLocator.h"
#include "swift/Sema/OverloadChoice.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/ilist.h"
Expand All @@ -47,6 +50,23 @@ class ConstraintLocator;
class ConstraintSystem;
enum class TrailingClosureMatching;

/// Describes contextual type information about a particular element
/// (expression, statement etc.) within a constraint system.
struct ContextualTypeInfo {
TypeLoc typeLoc;
ContextualTypePurpose purpose;

ContextualTypeInfo() : typeLoc(TypeLoc()), purpose(CTP_Unused) {}

ContextualTypeInfo(Type contextualTy, ContextualTypePurpose purpose)
: typeLoc(TypeLoc::withoutLoc(contextualTy)), purpose(purpose) {}

ContextualTypeInfo(TypeLoc typeLoc, ContextualTypePurpose purpose)
: typeLoc(typeLoc), purpose(purpose) {}

Type getType() const { return typeLoc.getType(); }
};

/// Describes the kind of constraint placed on one or more types.
enum class ConstraintKind : char {
/// The two types must be bound to the same type. This is the only
Expand Down Expand Up @@ -129,6 +149,9 @@ enum class ConstraintKind : char {
/// A disjunction constraint that specifies that one or more of the
/// stored constraints must hold.
Disjunction,
/// A conjunction constraint that specifies that all of the stored
/// constraints must hold.
Conjunction,
/// The first type is an optional type whose object type is the second
/// type, preserving lvalue-ness.
OptionalObject,
Expand Down Expand Up @@ -192,6 +215,10 @@ enum class ConstraintKind : char {
/// inferred from a conversion, so the check is more relax comparing to
/// `ConformsTo`.
TransitivelyConformsTo,
/// Represents an AST node contained in a body of a closure. It has only
/// one type - type variable representing type of a node, other side is
/// the AST node to infer the type for.
ClosureBodyElement,
};

/// Classification of the different kinds of constraints.
Expand All @@ -208,7 +235,13 @@ enum class ConstraintClassification : char {
TypeProperty,

/// A disjunction constraint.
Disjunction
Disjunction,

/// A conjunction constraint.
Conjunction,

/// An element of a closure body.
ClosureElement,
};

/// Specifies a restriction on the kind of conversion that should be
Expand Down Expand Up @@ -338,6 +371,10 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// in its disjunction.
unsigned IsFavored : 1;

/// Whether or not this constraint should be solved in isolation from
/// the rest of the constraint system. Currently only applies to conjunctions.
unsigned IsIsolated : 1;

/// The number of type variables referenced by this constraint.
///
/// The type variables themselves are tail-allocated.
Expand Down Expand Up @@ -399,6 +436,13 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// The DC in which the use appears.
DeclContext *UseDC;
} Overload;

struct {
/// The node itself.
ASTNode Element;
/// Contextual information associated with the element (if any).
ContextualTypeInfo Context;
} ClosureElement;
};

/// The locator that describes where in the expression this
Expand All @@ -410,7 +454,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
void *operator new(size_t) = delete;

Constraint(ConstraintKind kind, ArrayRef<Constraint *> constraints,
ConstraintLocator *locator,
bool isIsolated, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars);

/// Construct a new constraint.
Expand Down Expand Up @@ -450,6 +494,11 @@ class Constraint final : public llvm::ilist_node<Constraint>,
ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars);

/// Construct a closure body element constraint.
Constraint(ASTNode node, ContextualTypeInfo context,
ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars);

/// Retrieve the type variables buffer, for internal mutation.
MutableArrayRef<TypeVariableType *> getTypeVariablesBuffer() {
return { getTrailingObjects<TypeVariableType *>(), NumTypeVariables };
Expand Down Expand Up @@ -518,12 +567,31 @@ class Constraint final : public llvm::ilist_node<Constraint>,
RememberChoice_t shouldRememberChoice
= ForgetChoice);

/// Create a new conjunction constraint.
///
/// \param isIsolated - Indicates whether given constraint should be
/// solved in isolation from the rest of the constraint system i.e.
/// by removing all of the unrelated type variables and constraints.
static Constraint *
createConjunction(ConstraintSystem &cs, ArrayRef<Constraint *> constraints,
bool isIsolated, ConstraintLocator *locator,
ArrayRef<TypeVariableType *> referencedVars = {});

/// Create a new Applicable Function constraint.
static Constraint *createApplicableFunction(
ConstraintSystem &cs, Type argumentFnType, Type calleeType,
Optional<TrailingClosureMatching> trailingClosureMatching,
ConstraintLocator *locator);

static Constraint *createClosureBodyElement(ConstraintSystem &cs,
ASTNode node,
ConstraintLocator *locator);

static Constraint *createClosureBodyElement(ConstraintSystem &cs,
ASTNode node,
ContextualTypeInfo context,
ConstraintLocator *locator);

/// Determine the kind of constraint.
ConstraintKind getKind() const { return Kind; }

Expand Down Expand Up @@ -629,6 +697,12 @@ class Constraint final : public llvm::ilist_node<Constraint>,

case ConstraintKind::Disjunction:
return ConstraintClassification::Disjunction;

case ConstraintKind::Conjunction:
return ConstraintClassification::Conjunction;

case ConstraintKind::ClosureBodyElement:
return ConstraintClassification::ClosureElement;
}

llvm_unreachable("Unhandled ConstraintKind in switch.");
Expand All @@ -640,6 +714,9 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::Disjunction:
llvm_unreachable("disjunction constraints have no type operands");

case ConstraintKind::Conjunction:
llvm_unreachable("conjunction constraints have no type operands");

case ConstraintKind::BindOverload:
return Overload.First;

Expand All @@ -648,6 +725,9 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::ValueWitness:
return Member.First;

case ConstraintKind::ClosureBodyElement:
llvm_unreachable("closure body element constraint has no type operands");

default:
return Types.First;
}
Expand All @@ -657,7 +737,9 @@ class Constraint final : public llvm::ilist_node<Constraint>,
Type getSecondType() const {
switch (getKind()) {
case ConstraintKind::Disjunction:
case ConstraintKind::Conjunction:
case ConstraintKind::BindOverload:
case ConstraintKind::ClosureBodyElement:
llvm_unreachable("constraint has no second type");

case ConstraintKind::ValueMember:
Expand Down Expand Up @@ -710,7 +792,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,

/// Retrieve the set of constraints in a disjunction.
ArrayRef<Constraint *> getNestedConstraints() const {
assert(Kind == ConstraintKind::Disjunction);
assert(Kind == ConstraintKind::Disjunction ||
Kind == ConstraintKind::Conjunction);
return Nested;
}

Expand All @@ -735,6 +818,10 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// e.g. coercion constraint "as X" which forms a disjunction.
bool isExplicitConversion() const;

/// Determine whether this constraint should be solved in isolation
/// from the rest of the constraint system.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels similar to what one-way constraints effectively do. Can you elaborate on what the difference here is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One-way constraints form a separate component for left-hand side type variable, in contrast isolated closures have to remove all of the inactive constraints and unrelated type variables and preserve only type variables related to parameter and result, they can't be separated into a component like one-way are because all of the constraints around a closure would have to be brought back after the body is type-checked.

bool isIsolated() const { return IsIsolated; }

/// Whether this is a one-way constraint.
bool isOneWayConstraint() const {
return Kind == ConstraintKind::OneWayEqual ||
Expand All @@ -761,6 +848,16 @@ class Constraint final : public llvm::ilist_node<Constraint>,
return Member.UseDC;
}

ASTNode getClosureElement() const {
assert(Kind == ConstraintKind::ClosureBodyElement);
return ClosureElement.Element;
}

ContextualTypeInfo getElementContext() const {
assert(Kind == ConstraintKind::ClosureBodyElement);
return ClosureElement.Context;
}

/// For an applicable function constraint, retrieve the trailing closure
/// matching rule.
Optional<TrailingClosureMatching> getTrailingClosureMatching() const;
Expand Down
53 changes: 53 additions & 0 deletions include/swift/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,15 @@ enum ContextualTypePurpose : uint8_t {
///< result type.
CTP_Condition, ///< Condition expression of various statements e.g.
///< `if`, `for`, `while` etc.
CTP_CaseStmt, ///< A single case statement associated with a `switch` or
/// a `do-catch` statement. It has to be convertible
/// to a type of a switch subject or an `Error` type.
CTP_ForEachStmt, ///< "expression/sequence" associated with 'for-in' loop
///< is expected to conform to 'Sequence' protocol.
CTP_ForEachSequence, ///< Sequence expression associated with `for-in` loop,
/// this element acts slightly differently compared to
/// \c CTP_ForEachStmt in a sence that it would
/// produce conformance constraints.
CTP_WrappedProperty, ///< Property type expected to match 'wrappedValue' type
CTP_ComposedPropertyWrapper, ///< Composed wrapper type expected to match
///< former 'wrappedValue' type
Expand Down Expand Up @@ -953,6 +960,52 @@ class LocatorPathElt::KeyPathType final
}
};

class LocatorPathElt::ClosureBodyElement final
: public StoredPointerElement<void> {
public:
ClosureBodyElement(ASTNode element)
: StoredPointerElement(PathElementKind::ClosureBodyElement,
element.getOpaqueValue()) {
assert(element);
}

ASTNode getElement() const {
// Unfortunately \c getFromOpaqueValue doesn't produce an ASTNode.
auto node = ASTNode::getFromOpaqueValue(getStoredPointer());
if (auto *expr = node.dyn_cast<Expr *>())
return expr;

if (auto *stmt = node.dyn_cast<Stmt *>())
return stmt;

if (auto *decl = node.dyn_cast<Decl *>())
return decl;

if (auto *pattern = node.dyn_cast<Pattern *>())
return pattern;

if (auto *repr = node.dyn_cast<TypeRepr *>())
return repr;

if (auto *cond = node.dyn_cast<StmtCondition *>())
return cond;

if (auto *caseItem = node.dyn_cast<CaseLabelItem *>())
return caseItem;

llvm_unreachable("unhandled ASTNode element kind");
}

Stmt *asStmt() const {
auto node = ASTNode::getFromOpaqueValue(getStoredPointer());
return node.get<Stmt *>();
}

static bool classof(const LocatorPathElt *elt) {
return elt->getKind() == PathElementKind::ClosureBodyElement;
}
};

namespace details {
template <typename CustomPathElement>
class PathElement {
Expand Down
Loading