Skip to content

Commit 8be85c0

Browse files
committed
[Sema] Have isValidTypeExprParent consider its child
With the introduction of the ArgumentList type, argument expressions will be direct decedents of call expressions, without an intermediate TupleExpr. As such, we need to tweak isValidTypeExprParent to consider the child expression such that `T(x)` is permissible, but `x(T)` is not. Change isValidTypeExprParent to take a child expr parameter, and update its use in MiscDiagnostics and PreCheckExpr. For PreCheckExpr, switch from a stack to walking the parent directly, as a stack-based approach would be a bit more fiddly in this case, and walking the parents shouldn't be expensive. This should be NFC, I'm splitting it off from the ArgumentList refactoring to make the rebasing there a little more straightforward.
1 parent 4a058ae commit 8be85c0

File tree

4 files changed

+35
-35
lines changed

4 files changed

+35
-35
lines changed

include/swift/AST/Expr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,8 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
558558
/// the parent map.
559559
llvm::DenseMap<Expr *, Expr *> getParentMap();
560560

561-
/// Whether this expression is a valid parent for a TypeExpr.
562-
bool isValidTypeExprParent() const;
561+
/// Whether this expression is a valid parent for a given TypeExpr.
562+
bool isValidParentOfTypeExpr(Expr *typeExpr) const;
563563

564564
SWIFT_DEBUG_DUMP;
565565
void dump(raw_ostream &OS, unsigned Indent = 0) const;

lib/AST/Expr.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ llvm::DenseMap<Expr *, Expr *> Expr::getParentMap() {
736736
return parentMap;
737737
}
738738

739-
bool Expr::isValidTypeExprParent() const {
739+
bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
740740
// Allow references to types as a part of:
741741
// - member references T.foo, T.Type, T.self, etc.
742742
// - constructor calls T()
@@ -746,7 +746,6 @@ bool Expr::isValidTypeExprParent() const {
746746
switch (getKind()) {
747747
case ExprKind::Error:
748748
case ExprKind::DotSelf:
749-
case ExprKind::Call:
750749
case ExprKind::MemberRef:
751750
case ExprKind::UnresolvedMember:
752751
case ExprKind::DotSyntaxCall:
@@ -755,9 +754,15 @@ bool Expr::isValidTypeExprParent() const {
755754
case ExprKind::DotSyntaxBaseIgnored:
756755
case ExprKind::UnresolvedSpecialize:
757756
case ExprKind::OpenExistential:
758-
case ExprKind::Subscript:
759757
return true;
760758

759+
// For these cases we need to ensure the type expr is the function or base.
760+
// We do not permit e.g 'foo(T)'.
761+
case ExprKind::Call:
762+
return cast<CallExpr>(this)->getFn() == typeExpr;
763+
case ExprKind::Subscript:
764+
return cast<SubscriptExpr>(this)->getBase() == typeExpr;
765+
761766
case ExprKind::NilLiteral:
762767
case ExprKind::BooleanLiteral:
763768
case ExprKind::IntegerLiteral:

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
621621
DiagnosticBehavior behavior = DiagnosticBehavior::Error;
622622

623623
if (auto *ParentExpr = Parent.getAsExpr()) {
624-
if (ParentExpr->isValidTypeExprParent())
624+
if (ParentExpr->isValidParentOfTypeExpr(E))
625625
return;
626626

627627
if (!Ctx.LangOpts.isSwiftVersionAtLeast(6)) {

lib/Sema/PreCheckExpr.cpp

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -902,13 +902,6 @@ namespace {
902902
/// insert RebindSelfInConstructorExpr nodes.
903903
llvm::SmallVector<Expr *, 8> ExprStack;
904904

905-
/// A stack, corresponding to \c ExprStack above, that indicates at each
906-
/// level whether the enclosing context is plausibly something that will
907-
/// be folded into a \c TypeExpr after \c simplifyTypeExpr is called.
908-
/// This helps us determine whether '_' should become a placeholder type or
909-
/// not, which lets us produce better diagnostics during type checking.
910-
llvm::SmallVector<bool, 8> PossibleTypeContextStack;
911-
912905
/// The 'self' variable to use when rebinding 'self' in a constructor.
913906
VarDecl *UnresolvedCtorSelf = nullptr;
914907

@@ -942,12 +935,12 @@ namespace {
942935
/// the type conforms to the expected literal protocol.
943936
Expr *simplifyTypeConstructionWithLiteralArg(Expr *E);
944937

945-
/// Whether we are in a context that might turn out to be a \c TypeExpr
946-
/// after \c simplifyTypeExpr is called up the tree. This function allows
947-
/// us to make better guesses about whether invalid uses of '_' were
948-
/// "supposed" to be \c DiscardAssignmentExprs or patterns, which results
949-
/// in better diagnostics after type checking.
950-
bool possiblyInTypeContext();
938+
/// Whether the current expression \p E is in a context that might turn out
939+
/// to be a \c TypeExpr after \c simplifyTypeExpr is called up the tree.
940+
/// This function allows us to make better guesses about whether invalid
941+
/// uses of '_' were "supposed" to be \c DiscardAssignmentExprs or patterns,
942+
/// which results in better diagnostics after type checking.
943+
bool possiblyInTypeContext(Expr *E);
951944

952945
/// Whether we can simplify the given discard assignment expr. Not possible
953946
/// if it's been marked "valid" or if the current state of the AST disallows
@@ -1170,17 +1163,7 @@ namespace {
11701163
if (recursive) {
11711164
if (isa<SequenceExpr>(expr))
11721165
SequenceExprDepth++;
1173-
1174-
// The next level is considered a type context if either:
1175-
// - The expression is a valid parent for a TypeExpr, or
1176-
// - The current level is a type context and the expression "looks
1177-
// like" a type (and is not a call arg).
1178-
bool shouldEnterTypeContext = expr->isValidTypeExprParent();
1179-
bool shouldContinueTypeContext = possiblyInTypeContext() &&
1180-
exprLooksLikeAType(expr) && !CallArgs.count(expr);
11811166
ExprStack.push_back(expr);
1182-
PossibleTypeContextStack.push_back(shouldEnterTypeContext ||
1183-
shouldContinueTypeContext);
11841167
}
11851168

11861169
return std::make_pair(recursive, expr);
@@ -1302,7 +1285,6 @@ namespace {
13021285
// Remove this expression from the stack.
13031286
assert(ExprStack.back() == expr);
13041287
ExprStack.pop_back();
1305-
PossibleTypeContextStack.pop_back();
13061288

13071289
// Mark the direct callee as being a callee.
13081290
if (auto *call = dyn_cast<ApplyExpr>(expr))
@@ -1591,17 +1573,30 @@ TypeExpr *PreCheckExpression::simplifyUnresolvedSpecializeExpr(
15911573
return nullptr;
15921574
}
15931575

1594-
bool PreCheckExpression::possiblyInTypeContext() {
1595-
return !PossibleTypeContextStack.empty() && PossibleTypeContextStack.back();
1576+
bool PreCheckExpression::possiblyInTypeContext(Expr *E) {
1577+
// Walk back up the stack of parents looking for a valid type context.
1578+
for (auto *ParentExpr : llvm::reverse(ExprStack)) {
1579+
// We're considered to be in a type context if either:
1580+
// - We have a valid parent for a TypeExpr, or
1581+
// - The parent "looks like" a type (and is not a call arg), and we can
1582+
// reach a valid parent for a TypeExpr if we continue walking.
1583+
if (ParentExpr->isValidParentOfTypeExpr(E))
1584+
return true;
1585+
1586+
if (!exprLooksLikeAType(ParentExpr) || CallArgs.count(ParentExpr))
1587+
return false;
1588+
1589+
E = ParentExpr;
1590+
}
1591+
return false;
15961592
}
15971593

15981594
/// Only allow simplification of a DiscardAssignmentExpr if it hasn't already
15991595
/// been explicitly marked as correct, and the current AST state allows it.
16001596
bool PreCheckExpression::canSimplifyDiscardAssignmentExpr(
16011597
DiscardAssignmentExpr *DAE) {
1602-
return !CorrectDiscardAssignmentExprs.count(DAE) &&
1603-
possiblyInTypeContext() &&
1604-
SequenceExprDepth == 0;
1598+
return !CorrectDiscardAssignmentExprs.count(DAE) && SequenceExprDepth == 0 &&
1599+
possiblyInTypeContext(DAE);
16051600
}
16061601

16071602
/// Simplify expressions which are type sugar productions that got parsed

0 commit comments

Comments
 (0)