Skip to content

[5.3][Parse] Don't drop parsed error types in where clause from AST #31258

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
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4582,8 +4582,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
return whereStatus;
trailingWhereHadCodeCompletion = true;
}

if (whereStatus.isSuccess()) {
if (!requirements.empty()) {
trailingWhereClause = TrailingWhereClause::create(Context, whereLoc,
requirements);
}
Expand Down
23 changes: 10 additions & 13 deletions lib/Parse/ParseGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,13 +332,9 @@ ParserStatus Parser::parseGenericWhereClause(
} else {
// Parse the protocol or composition.
ParserResult<TypeRepr> Protocol = parseType();

if (Protocol.isNull()) {
Status.setIsParseError();
if (Protocol.hasCodeCompletion())
Status.setHasCodeCompletion();
break;
}
Status |= Protocol;
if (Protocol.isNull())
Protocol = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));

// Add the requirement.
Requirements.push_back(RequirementRepr::getTypeConstraint(
Expand All @@ -356,17 +352,18 @@ ParserStatus Parser::parseGenericWhereClause(

// Parse the second type.
ParserResult<TypeRepr> SecondType = parseType();
if (SecondType.isNull()) {
Status.setIsParseError();
if (SecondType.hasCodeCompletion())
Status.setHasCodeCompletion();
break;
}
Status |= SecondType;
if (SecondType.isNull())
SecondType = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));

// Add the requirement
Requirements.push_back(RequirementRepr::getSameType(FirstType.get(),
EqualLoc,
SecondType.get()));
} else if (FirstType.hasCodeCompletion()) {
// Recover by adding dummy constraint.
Requirements.push_back(RequirementRepr::getTypeConstraint(
FirstType.get(), PreviousLoc, new (Context) ErrorTypeRepr(PreviousLoc)));
} else {
BodyContext->setTransparent();
diagnose(Tok, diag::expected_requirement_delim);
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,

// If we didn't parse a type, then we already diagnosed that the type
// was invalid. Remember that.
if (type.isParseError() && !type.hasCodeCompletion())
if (type.isNull() && !type.hasCodeCompletion())
param.isInvalid = true;
} else if (paramContext != Parser::ParameterContextKind::Closure) {
diagnose(Tok, diag::expected_parameter_colon);
Expand Down
27 changes: 11 additions & 16 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,8 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
break;
if (CodeCompletion)
CodeCompletion->completeTypeSimpleBeginning();
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult<TypeRepr>();
return makeParserCodeCompletionResult<TypeRepr>(
new (Context) ErrorTypeRepr(consumeToken(tok::code_complete)));
case tok::l_square: {
auto Result = parseTypeCollection();
if (Result.hasSyntax())
Expand Down Expand Up @@ -407,11 +406,10 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,

ParserResult<TypeRepr> ty =
parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion);
if (ty.hasCodeCompletion())
return makeParserCodeCompletionResult<TypeRepr>();
if (ty.isNull())
return nullptr;
return ty;
auto tyR = ty.get();
auto status = ParserStatus(ty);

// Parse a throws specifier.
// Don't consume 'throws', if the next token is not '->', so we can emit a
Expand Down Expand Up @@ -442,10 +440,11 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
}
ParserResult<TypeRepr> SecondHalf =
parseType(diag::expected_type_function_result);
if (SecondHalf.hasCodeCompletion())
return makeParserCodeCompletionResult<TypeRepr>();
if (SecondHalf.isNull())
return nullptr;
if (SecondHalf.isNull()) {
status.setIsParseError();
return status;
}
status |= SecondHalf;

if (SyntaxContext->isEnabled()) {
ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext);
Expand Down Expand Up @@ -594,8 +593,8 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
if (specifierLoc.isValid() || !attrs.empty())
SyntaxContext->setCreateSyntax(SyntaxKind::AttributedType);

return makeParserResult(applyAttributeToType(tyR, attrs, specifier,
specifierLoc));
return makeParserResult(status, applyAttributeToType(tyR, attrs, specifier,
specifierLoc));
}

ParserResult<TypeRepr> Parser::parseDeclResultType(Diag<> MessageID) {
Expand Down Expand Up @@ -844,8 +843,6 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID,
// Parse the first type
ParserResult<TypeRepr> FirstType = parseTypeSimple(MessageID,
HandleCodeCompletion);
if (FirstType.hasCodeCompletion())
return makeParserCodeCompletionResult<TypeRepr>();
if (FirstType.isNull())
return FirstType;
if (!Tok.isContextualPunctuator("&")) {
Expand Down Expand Up @@ -1255,8 +1252,6 @@ ParserResult<TypeRepr> Parser::parseTypeArray(TypeRepr *Base) {
auto sizeEx = parseExprBasic(diag::expected_expr);
if (sizeEx.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (sizeEx.isNull())
return makeParserErrorResult(Base);
}

SourceLoc rsquareLoc;
Expand Down
20 changes: 20 additions & 0 deletions test/IDE/complete_where_clause.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NOMINAL_TYPEALIAS_NESTED2 | %FileCheck %s -check-prefix=NOMINAL_TYPEALIAS_NESTED2
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NOMINAL_TYPEALIAS_NESTED1_EXT | %FileCheck %s -check-prefix=NOMINAL_TYPEALIAS_NESTED1_EXT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NOMINAL_TYPEALIAS_NESTED2_EXT | %FileCheck %s -check-prefix=NOMINAL_TYPEALIAS_NESTED2_EXT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXT_ASSOC_MEMBER_1 | %FileCheck %s -check-prefix=EXT_ASSOC_MEMBER
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXT_ASSOC_MEMBER_2 | %FileCheck %s -check-prefix=EXT_ASSOC_MEMBER
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXT_SECONDTYPE | %FileCheck %s -check-prefix=EXT_SECONDTYPE

class A1<T1, T2, T3> {}

Expand Down Expand Up @@ -226,3 +229,20 @@ extension TA2.Inner2 where #^NOMINAL_TYPEALIAS_NESTED2_EXT^# {}
// NOMINAL_TYPEALIAS_NESTED2_EXT-DAG: Decl[TypeAlias]/CurrNominal: X1[#T#];
// NOMINAL_TYPEALIAS_NESTED2_EXT-DAG: Decl[TypeAlias]/CurrNominal: X2[#T.Q#];
// NOMINAL_TYPEALIAS_NESTED2_EXT: End completions

protocol WithAssoc {
associatedtype T: Assoc
}
extension WithAssoc where T.#^EXT_ASSOC_MEMBER_1^#
// EXT_ASSOC_MEMBER: Begin completions, 2 items
// EXT_ASSOC_MEMBER-DAG: Decl[AssociatedType]/CurrNominal: Q;
// EXT_ASSOC_MEMBER-DAG: Keyword/None: Type[#Self.T.Type#];
// EXT_ASSOC_MEMBER: End completions

extension WithAssoc where Int == T.#^EXT_ASSOC_MEMBER_2^#
// Same as EXT_ASSOC_MEMBER

extension WithAssoc where Int == #^EXT_SECONDTYPE^#
// EXT_SECONDTYPE: Begin completions
// EXT_SECONDTYPE-DAG: Decl[AssociatedType]/CurrNominal: T;
// EXT_SECONDTYPE: End completions
16 changes: 9 additions & 7 deletions test/Parse/recovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -436,19 +436,22 @@ struct ErrorTypeInVarDeclFunctionType1 {
}

struct ErrorTypeInVarDeclArrayType1 {
var v1 : Int[+] // expected-error {{unexpected ']' in type; did you mean to write an array type?}}
var v1 : Int[+] // expected-error {{array types are now written with the brackets around the element type}}
// expected-error @-1 {{expected expression after unary operator}}
// expected-error @-2 {{expected expression}}
var v2 : Int
}

struct ErrorTypeInVarDeclArrayType2 {
var v1 : Int[+ // expected-error {{unary operator cannot be separated from its operand}}
// expected-error@-1 {{expected ']' in array type}}
// expected-note@-2 {{to match this opening '['}}
var v2 : Int // expected-error {{expected expression}}
}

struct ErrorTypeInVarDeclArrayType3 {
var v1 : Int[
var v1 : Int[ // expected-error {{expected ']' in array type}}
// expected-note@-1 {{to match this opening '['}}
; // expected-error {{expected expression}}
var v2 : Int
}
Expand Down Expand Up @@ -480,8 +483,9 @@ struct ErrorTypeInVarDeclDictionaryType {

struct ErrorInFunctionSignatureResultArrayType1 {
func foo() -> Int[ { // expected-error {{expected '{' in body of function declaration}}
// expected-note@-1 {{to match this opening '['}}
return [0]
}
} // expected-error {{expected ']' in array type}}
func bar() -> Int] { // expected-error {{unexpected ']' in type; did you mean to write an array type?}} {{17-17=[}}
return [0]
}
Expand Down Expand Up @@ -669,10 +673,8 @@ case let (jeb):
// rdar://19605164
// expected-error@+2{{use of undeclared type 'S'}}
struct Foo19605164 {
func a(s: S[{{g) -> Int {}
// expected-error@+2 {{expected parameter name followed by ':'}}
// expected-error@+1 {{expected ',' separator}}
}}}
func a(s: S[{{g) -> Int {} // expected-note {{to match this opening '['}}
}}} // expected-error {{expected ']' in array type}}
#endif


Expand Down