Skip to content

Commit bb77323

Browse files
author
Nathan Hawes
committed
[Parse][CodeCompletion] Stop code completion within a closure causing parser recovery after the closure.
For example, the completion below would trigger error recovery within the closure, which we recover from by skipping to the first inner closure's right brace. The fact that we recovered though, was not recorded. The closure is treated as still being an error, triggering another recovery after it that skips over the 'Thing' token, giving a lone closure expression, rather than a call. CreateThings { Thing { point in print("hello") point.#^HERE^# } Thing { _ in } } This isn't an issue for code completion when the outer closure is a regular closure, but when it's a function builder, invalid elements result in no types being applied (no valid solutions) and we end up with no completion results. The fix here is removing the error status from the parser result after the initial parser recovery.
1 parent a61e704 commit bb77323

File tree

11 files changed

+170
-119
lines changed

11 files changed

+170
-119
lines changed

include/swift/Parse/ParserResult.h

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ template <typename T> class ParserResult {
3939
IsCodeCompletion = 0x2,
4040
};
4141

42-
template <typename U> friend class ParserResult;
42+
template <typename U>
43+
friend class ParserResult;
44+
45+
template <typename U>
46+
friend inline ParserResult<U> makeParserResult(ParserStatus Status,
47+
U *Result);
4348

4449
public:
4550
/// Construct a null result with error bit set.
@@ -78,21 +83,35 @@ template <typename T> class ParserResult {
7883
/// Return the AST node or a null pointer.
7984
T *getPtrOrNull() const { return PtrAndBits.getPointer(); }
8085

81-
/// Return true if there was a parse error.
86+
/// Return true if there was a parse error that the parser has not yet
87+
/// recovered from.
8288
///
8389
/// Note that we can still have an AST node which was constructed during
8490
/// recovery.
8591
bool isParseError() const { return PtrAndBits.getInt() & IsError; }
8692

93+
/// Return true if there was a parse error that the parser has not yet
94+
/// recovered from, or if we found a code completion token while parsing.
95+
///
96+
/// Note that we can still have an AST node which was constructed during
97+
/// recovery.
98+
bool isParseErrorOrHasCompletion() const {
99+
return PtrAndBits.getInt() & (IsError | IsCodeCompletion);
100+
}
101+
87102
/// Return true if we found a code completion token while parsing this.
88103
bool hasCodeCompletion() const {
89104
return PtrAndBits.getInt() & IsCodeCompletion;
90105
}
91106

92107
void setIsParseError() { PtrAndBits.setInt(PtrAndBits.getInt() | IsError); }
108+
void setHasCodeCompletionAndIsError() {
109+
PtrAndBits.setInt(PtrAndBits.getInt() | IsError | IsCodeCompletion);
110+
}
93111

112+
private:
94113
void setHasCodeCompletion() {
95-
PtrAndBits.setInt(PtrAndBits.getInt() | IsError | IsCodeCompletion);
114+
PtrAndBits.setInt(PtrAndBits.getInt() | IsCodeCompletion);
96115
}
97116
};
98117

@@ -119,7 +138,7 @@ static inline ParserResult<T> makeParserCodeCompletionResult(T *Result =
119138
ParserResult<T> PR;
120139
if (Result)
121140
PR = ParserResult<T>(Result);
122-
PR.setHasCodeCompletion();
141+
PR.setHasCodeCompletionAndIsError();
123142
return PR;
124143
}
125144

@@ -145,27 +164,32 @@ class ParserStatus {
145164
if (Result.isParseError())
146165
setIsParseError();
147166
if (Result.hasCodeCompletion())
148-
setHasCodeCompletion();
167+
IsCodeCompletion = true;
149168
}
150169

170+
/// Return true if either 1) no errors were encountered while parsing this,
171+
/// or 2) there were errors but the the parser already recovered from them.
151172
bool isSuccess() const { return !isError(); }
152-
bool isError() const { return IsError; }
173+
bool isErrorOrHasCompletion() const { return IsError || IsCodeCompletion; }
153174

154175
/// Return true if we found a code completion token while parsing this.
155176
bool hasCodeCompletion() const { return IsCodeCompletion; }
156177

178+
/// Return true if we encountered any errors while parsing this that the
179+
/// parser hasn't yet recovered from.
180+
bool isError() const { return IsError; }
181+
157182
void setIsParseError() {
158183
IsError = true;
159184
}
160185

161-
void setHasCodeCompletion() {
162-
IsError = true;
163-
IsCodeCompletion = true;
186+
void clearIsError() {
187+
IsError = false;
164188
}
165189

166-
/// True if we should stop parsing for any reason.
167-
bool shouldStopParsing() const {
168-
return IsError || IsCodeCompletion;
190+
void setHasCodeCompletionAndIsError() {
191+
IsError = true;
192+
IsCodeCompletion = true;
169193
}
170194

171195
ParserStatus &operator|=(ParserStatus RHS) {
@@ -196,19 +220,21 @@ static inline ParserStatus makeParserError() {
196220
/// Create a status with error and code completion bits set.
197221
static inline ParserStatus makeParserCodeCompletionStatus() {
198222
ParserStatus Status;
199-
Status.setHasCodeCompletion();
223+
Status.setHasCodeCompletionAndIsError();
200224
return Status;
201225
}
202226

203227
/// Create a parser result with specified bits.
204228
template <typename T>
205229
static inline ParserResult<T> makeParserResult(ParserStatus Status,
206230
T *Result) {
207-
if (Status.isSuccess())
208-
return makeParserResult(Result);
231+
ParserResult<T> PR = Status.isError()
232+
? makeParserErrorResult(Result)
233+
: makeParserResult(Result);
234+
209235
if (Status.hasCodeCompletion())
210-
return makeParserCodeCompletionResult(Result);
211-
return makeParserErrorResult(Result);
236+
PR.setHasCodeCompletion();
237+
return PR;
212238
}
213239

214240
template <typename T> ParserResult<T>::ParserResult(ParserStatus Status) {

include/swift/Parse/SyntaxParserResult.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,16 @@ template <typename Syntax, typename AST> class SyntaxParserResult {
4444

4545
bool isNull() const { return ASTResult.isNull(); }
4646
bool isNonNull() const { return ASTResult.isNonNull(); }
47-
bool isParseError() const { return ASTResult.isParseError(); }
47+
bool isParseError() const {
48+
return ASTResult.isParseError();
49+
}
50+
bool isParseErrorOrHasCompletion() const {
51+
return ASTResult.isParseErrorOrHasCompletion();
52+
}
4853
bool hasCodeCompletion() const { return ASTResult.hasCodeCompletion(); }
4954

5055
void setIsParseError() { return ASTResult.setIsParserError(); }
51-
void setHasCodeCompletion() { return ASTResult.setHasCodeCompletion(); }
56+
void setHasCodeCompletionAndIsError() { return ASTResult.setHasCodeCompletionAndIsError(); }
5257

5358
const ParserResult<AST> &getASTResult() { return ASTResult; }
5459

@@ -92,7 +97,7 @@ makeSyntaxCodeCompletionResult(AST *Result = nullptr) {
9297
SyntaxParserResult<Syntax, AST> SR;
9398
if (Result)
9499
SR = SyntaxParserResult<Syntax, AST>(None, Result);
95-
SR.setHasCodeCompletion();
100+
SR.setHasCodeCompletionAndIsError();
96101
return SR;
97102
}
98103

0 commit comments

Comments
 (0)