Skip to content

Improve diagnostics for generics in enum case #69055

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

Closed
wants to merge 9 commits into from
Closed
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
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ ERROR(number_cant_start_decl_name,none,
(StringRef))
ERROR(expected_identifier_after_case_comma, PointsToFirstBadToken,
"expected identifier after comma in enum 'case' declaration", ())
ERROR(generic_param_cant_be_used_in_enum_case_decl, PointsToFirstBadToken,
"generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?", ())
ERROR(let_cannot_be_computed_property,none,
"'let' declarations cannot be computed properties", ())
ERROR(let_cannot_be_observing_property,none,
Expand Down
26 changes: 26 additions & 0 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8969,6 +8969,32 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
diagnose(CaseLoc, diag::expected_identifier_in_decl, "enum 'case'");
}
}

// See if there are generic params.
auto genericResults = maybeParseGenericParams()
.getPtrOrNull();
auto enumDecl = dyn_cast<EnumDecl>(CurDeclContext);
if (genericResults && !genericResults->getParams().empty() && enumDecl) {
auto genericParamDecl = genericResults->getParams().front();

std::string fixStr;
llvm::raw_string_ostream OS(fixStr);
genericResults->print(OS);

// Check if enum is already generic.
auto enumGenericParams = enumDecl->getGenericParams();
if (enumGenericParams && !enumGenericParams->getParams().empty()) {
diagnose(genericParamDecl->getStartLoc(), diag::generic_param_cant_be_used_in_enum_case_decl)
.fixItRemove(genericResults->getSourceRange())
.fixItReplace(enumGenericParams->getSourceRange(), fixStr);
} else {
SourceLoc insertLoc = enumDecl->getNameLoc()
.getAdvancedLoc(enumDecl->getName().getLength());
diagnose(genericParamDecl->getStartLoc(), diag::generic_param_cant_be_used_in_enum_case_decl)
.fixItRemove(genericResults->getSourceRange())
.fixItInsert(insertLoc, fixStr);
}
}

// See if there's a following argument type.
ParserResult<ParameterList> ArgParams;
Expand Down
26 changes: 26 additions & 0 deletions test/decl/enum/enumtest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -636,3 +636,29 @@ if case nil = foo1 {} // Okay
if case .none? = foo1 {} // Okay
if case nil = foo2 {} // Okay
if case .none?? = foo2 {} // Okay

enum EnumCaseWithGenericDeclaration {
// expected-error@+1 {{cannot find type 'T' in scope}}
case foo<T>(T) // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-14=}} {{-2:36-36=<T>}}
// expected-error@+1 {{cannot find type 'T' in scope}}
case bar<T>(param: T) // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-14=}} {{-4:36-36=<T>}}
case baz<T> // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-14=}} {{-5:36-36=<T>}}
case one, two<Key> // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{16-21=}} {{-6:36-36=<Key>}}
case three<Element>, four // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{13-22=}} {{-7:36-36=<Element>}}
// expected-error@+1 {{cannot find type 'T' in scope}}
case five<T>(param: T), six // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{12-15=}} {{-9:36-36=<T>}}
// expected-error@+2 {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{13-16=}} {{-12:36-36=<T>}}
// expected-error@+1 {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{23-26=}} {{-12:36-36=<U>}}
case seven<T>, eight<U>
case nine // OK
}

enum EnumWithGenericDeclaration<Element> {
case foo<T> // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-14=}} {{-1:32-41=<T>}}
// expected-error@+1 {{cannot find type 'Key' in scope}}
case bar<Key>(param: Key) // expected-error {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-16=}} {{-3:32-41=<Key>}}
// expected-error@+2 {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{11-14=}} {{-6:32-41=<T>}}
// expected-error@+1 {{generic signature cannot be declared in enum 'case'. did you mean to attach it to enum declaration?}} {{19-22=}} {{-6:32-41=<U>}}
case one<T>, two<U>
case nine // OK
}