Skip to content

Commit 6085e1d

Browse files
committed
[CodeCompletion] Reset diagnostics when reusing an ASTContext for completion
The diagnosticc engine is keeping track of state which might modify parsing/typechecking behaviour. In the added test case the `fatalErrorOccurred` flag was during the first completion. The flag was still `true` for the second completion, causing parsing/typechecking to behave slightly differently. Because of this, the ExprRewriter failed when applying a constraint system solution, not properly cleaning up its `ExprStack`. This PR tackles both issues: 1) Reset the `hadError` flags in the diagnostics engine 2) Clean up the `ExprRewriter`’s `ExprStack` when rewriting a target fails. Either of these changes fixes the crash in the test case but I think both could manifest through different code paths in different scenarios. Fixes rdar://76051976 [SR-14430]
1 parent 5cf19e4 commit 6085e1d

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

lib/IDE/CompletionInstance.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ bool CompletionInstance::performCachedOperationIfPossible(
493493
{
494494
PrettyStackTraceDeclContext trace("performing cached completion", traceDC);
495495

496+
// The diagnostic engine is keeping track of state which might modify
497+
// parsing and type checking behaviour. Clear the flags.
498+
CI.getDiags().resetHadAnyError();
499+
496500
if (DiagC)
497501
CI.addDiagnosticConsumer(DiagC);
498502

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8517,6 +8517,17 @@ static Optional<SolutionApplicationTarget> applySolutionToForEachStmt(
85178517

85188518
Optional<SolutionApplicationTarget>
85198519
ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
8520+
// Rewriting the target might abort in case one of visit methods returns
8521+
// nullptr. In this case, no more walkToExprPost calls are issues and thus
8522+
// nodes which were pushed on the Rewriter's ExprStack in walkToExprPre are
8523+
// not popped of the stack again in walkTokExprPost. Usually, that's not an
8524+
// issue if rewriting completely terminates because the ExprStack is never
8525+
// used again. Here, however, we recover from a rewriting failure and continue
8526+
// using the Rewriter. To make sure we don't continue with an ExprStack that
8527+
// is still in the state when rewriting was aborted, save it here and restore
8528+
// it once rewritingt this target has finished.
8529+
llvm::SaveAndRestore<SmallVector<Expr *, 8>> RestoreExprStack(
8530+
Rewriter.ExprStack);
85208531
auto &solution = Rewriter.solution;
85218532

85228533
// Apply the solution to the target.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Check that we are not crashing
2+
// RUN: %sourcekitd-test -req=complete -pos=48:28 %s -- %s == -req=complete -pos=48:16 %s -- %s
3+
4+
let abcde = "abc"
5+
6+
public struct MyEmptyView : MyView {
7+
public typealias Body = Never
8+
public var body: Never { fatalError() }
9+
}
10+
11+
extension Never : MyView {}
12+
13+
@resultBuilder public struct MyViewBuilder {
14+
public static func buildBlock() -> MyEmptyView {
15+
return MyEmptyView()
16+
}
17+
public static func buildBlock<Content>(_ content: Content) -> Content where Content : MyView {
18+
content
19+
}
20+
}
21+
22+
public protocol MyView {
23+
associatedtype Body : MyView
24+
@MyViewBuilder var body: Self.Body { get }
25+
}
26+
27+
public struct MyHStack<Content> : MyView {
28+
public init(@MyViewBuilder content: () -> Content) {}
29+
public typealias Body = Swift.Never
30+
public var body: Never { fatalError() }
31+
}
32+
33+
public struct MyText : MyView {
34+
public init(_ content: Swift.String) {}
35+
public typealias Body = Never
36+
public var body: Never { fatalError() }
37+
}
38+
39+
extension MyView {
40+
public func padding(_ insets: Bool) -> some MyView { return MyEmptyView() }
41+
public func padding(_ length: Float) -> some MyView { return MyEmptyView() }
42+
public func padding() -> some MyView { return MyEmptyView() }
43+
}
44+
45+
struct RoundedBadge : MyView {
46+
var body: some MyView {
47+
MyHStack {
48+
MyText(abcde).padding()
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)