Skip to content

Commit 867cf28

Browse files
authored
Merge pull request swiftlang#77928 from DmT021/wp/error-wrapped-in-warn
Add DiagGroupID to Diagnostic
2 parents 00f6df9 + d56b7df commit 867cf28

File tree

9 files changed

+94
-36
lines changed

9 files changed

+94
-36
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/ActorIsolation.h"
2222
#include "swift/AST/DeclNameLoc.h"
2323
#include "swift/AST/DiagnosticConsumer.h"
24+
#include "swift/AST/DiagnosticGroups.h"
2425
#include "swift/AST/TypeLoc.h"
2526
#include "swift/Basic/PrintDiagnosticNamesMode.h"
2627
#include "swift/Basic/Statistic.h"
@@ -498,6 +499,7 @@ namespace swift {
498499

499500
private:
500501
DiagID ID;
502+
DiagGroupID GroupID;
501503
SmallVector<DiagnosticArgument, 3> Args;
502504
SmallVector<CharSourceRange, 2> Ranges;
503505
SmallVector<FixIt, 2> FixIts;
@@ -510,7 +512,10 @@ namespace swift {
510512
friend DiagnosticEngine;
511513
friend class InFlightDiagnostic;
512514

513-
Diagnostic(DiagID ID) : ID(ID) {}
515+
Diagnostic(DiagID ID, DiagGroupID GroupID) : ID(ID), GroupID(GroupID) {}
516+
517+
/// Constructs a Diagnostic with DiagGroupID infered from DiagID.
518+
Diagnostic(DiagID ID);
514519

515520
public:
516521
// All constructors are intentionally implicit.
@@ -535,6 +540,7 @@ namespace swift {
535540

536541
// Accessors.
537542
DiagID getID() const { return ID; }
543+
DiagGroupID getGroupID() const { return GroupID; }
538544
ArrayRef<DiagnosticArgument> getArgs() const { return Args; }
539545
ArrayRef<CharSourceRange> getRanges() const { return Ranges; }
540546
ArrayRef<FixIt> getFixIts() const { return FixIts; }
@@ -1434,7 +1440,8 @@ namespace swift {
14341440

14351441
/// Generate DiagnosticInfo for a Diagnostic to be passed to consumers.
14361442
std::optional<DiagnosticInfo>
1437-
diagnosticInfoForDiagnostic(const Diagnostic &diagnostic);
1443+
diagnosticInfoForDiagnostic(const Diagnostic &diagnostic,
1444+
bool includeDiagnosticName);
14381445

14391446
/// Send \c diag to all diagnostic consumers.
14401447
void emitDiagnostic(const Diagnostic &diag);
@@ -1460,9 +1467,16 @@ namespace swift {
14601467
public:
14611468
DiagnosticKind declaredDiagnosticKindFor(const DiagID id);
14621469

1463-
llvm::StringRef
1464-
diagnosticStringFor(const DiagID id,
1465-
PrintDiagnosticNamesMode printDiagnosticNamesMode);
1470+
/// Get a localized format string for a given `DiagID`. If no localization
1471+
/// available returns the default string for that `DiagID`.
1472+
llvm::StringRef diagnosticStringFor(DiagID id);
1473+
1474+
/// Get a localized format string with an optional diagnostic name appended
1475+
/// to it. The diagnostic name type is defined by
1476+
/// `PrintDiagnosticNamesMode`.
1477+
llvm::StringRef diagnosticStringWithNameFor(
1478+
DiagID id, DiagGroupID groupID,
1479+
PrintDiagnosticNamesMode printDiagnosticNamesMode);
14661480

14671481
static llvm::StringRef diagnosticIDStringFor(const DiagID id);
14681482

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ GROUP(no_group, "")
2525
GROUP(DeprecatedDeclaration, "DeprecatedDeclaration.md")
2626
GROUP(Unsafe, "Unsafe.md")
2727
GROUP(UnknownWarningGroup, "UnknownWarningGroup.md")
28+
GROUP(DeclarationUnavailableFromAsynchronousContext, "DeclarationUnavailableFromAsynchronousContext.md")
2829

2930
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
3031
#include "swift/AST/DefineDiagnosticGroupsMacros.h"

include/swift/AST/DiagnosticsCommon.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ ERROR(error_no_group_info,none,
4747
NOTE(brace_stmt_suggest_do,none,
4848
"did you mean to use a 'do' statement?", ())
4949

50+
// `error_in_future_swift_version` does not have a group because warnings of this kind
51+
// inherit the group from the wrapped error.
5052
WARNING(error_in_future_swift_version,none,
5153
"%0; this is an error in the Swift %1 language mode",
5254
(DiagnosticInfo *, unsigned))
5355

56+
// `error_in_a_future_swift_version` does not have a group because warnings of this kind
57+
// inherit the group from the wrapped error.
5458
WARNING(error_in_a_future_swift_version,none,
5559
"%0; this will be an error in a future Swift language mode",
5660
(DiagnosticInfo *))

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5950,7 +5950,7 @@ ERROR(async_decl_must_be_available_from_async,none,
59505950
ERROR(async_named_decl_must_be_available_from_async,none,
59515951
"asynchronous %kind0 must be available from asynchronous contexts",
59525952
(const ValueDecl *))
5953-
ERROR(async_unavailable_decl,none,
5953+
GROUPED_ERROR(async_unavailable_decl,DeclarationUnavailableFromAsynchronousContext,none,
59545954
"%kindbase0 is unavailable from asynchronous contexts%select{|; %1}1",
59555955
(const ValueDecl *, StringRef))
59565956

lib/AST/DiagnosticEngine.cpp

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ DiagnosticState::DiagnosticState() {
179179
warningsAsErrors.resize(LocalDiagID::NumDiags);
180180
}
181181

182+
Diagnostic::Diagnostic(DiagID ID)
183+
: Diagnostic(ID, storedDiagnosticInfos[(unsigned)ID].groupID) {}
184+
182185
static CharSourceRange toCharSourceRange(SourceManager &SM, SourceRange SR) {
183186
return CharSourceRange(SM, SR.Start, Lexer::getLocForEndOfToken(SM, SR.End));
184187
}
@@ -464,8 +467,8 @@ InFlightDiagnostic::wrapIn(const Diagnostic &wrapper) {
464467
limit(Engine->getActiveDiagnostic().BehaviorLimit,
465468
DiagnosticBehavior::Unspecified);
466469

467-
Engine->WrappedDiagnostics.push_back(
468-
*Engine->diagnosticInfoForDiagnostic(Engine->getActiveDiagnostic()));
470+
Engine->WrappedDiagnostics.push_back(*Engine->diagnosticInfoForDiagnostic(
471+
Engine->getActiveDiagnostic(), /* includeDiagnosticName= */ false));
469472

470473
Engine->state.swap(tempState);
471474

@@ -478,6 +481,7 @@ InFlightDiagnostic::wrapIn(const Diagnostic &wrapper) {
478481
// Overwrite the ID and argument with those from the wrapper.
479482
Engine->getActiveDiagnostic().ID = wrapper.ID;
480483
Engine->getActiveDiagnostic().Args = wrapper.Args;
484+
// Intentionally keeping the original GroupID here
481485

482486
// Set the argument to the diagnostic being wrapped.
483487
assert(wrapper.getArgs().front().getKind() == DiagnosticArgumentKind::Diagnostic);
@@ -1294,7 +1298,8 @@ void DiagnosticEngine::forwardTentativeDiagnosticsTo(
12941298
}
12951299

12961300
std::optional<DiagnosticInfo>
1297-
DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
1301+
DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic,
1302+
bool includeDiagnosticName) {
12981303
auto behavior = state.determineBehavior(diagnostic);
12991304
if (behavior == DiagnosticBehavior::Ignore)
13001305
return std::nullopt;
@@ -1347,12 +1352,19 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
13471352
}
13481353
}
13491354

1350-
return DiagnosticInfo(
1351-
diagnostic.getID(), loc, toDiagnosticKind(behavior),
1352-
diagnosticStringFor(diagnostic.getID(), getPrintDiagnosticNamesMode()),
1353-
diagnostic.getArgs(), Category, getDefaultDiagnosticLoc(),
1354-
/*child note info*/ {}, diagnostic.getRanges(), fixIts,
1355-
diagnostic.isChildNote());
1355+
llvm::StringRef format;
1356+
if (includeDiagnosticName)
1357+
format =
1358+
diagnosticStringWithNameFor(diagnostic.getID(), diagnostic.getGroupID(),
1359+
getPrintDiagnosticNamesMode());
1360+
else
1361+
format = diagnosticStringFor(diagnostic.getID());
1362+
1363+
return DiagnosticInfo(diagnostic.getID(), loc, toDiagnosticKind(behavior),
1364+
format, diagnostic.getArgs(), Category,
1365+
getDefaultDiagnosticLoc(),
1366+
/*child note info*/ {}, diagnostic.getRanges(), fixIts,
1367+
diagnostic.isChildNote());
13561368
}
13571369

13581370
static DeclName
@@ -1462,7 +1474,9 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
14621474
ArrayRef<Diagnostic> childNotes = diagnostic.getChildNotes();
14631475
std::vector<Diagnostic> extendedChildNotes;
14641476

1465-
if (auto info = diagnosticInfoForDiagnostic(diagnostic)) {
1477+
if (auto info =
1478+
diagnosticInfoForDiagnostic(diagnostic,
1479+
/* includeDiagnosticName= */ true)) {
14661480
// If the diagnostic location is within a buffer containing generated
14671481
// source code, add child notes showing where the generation occurred.
14681482
// We need to avoid doing this if this is itself a child note, as otherwise
@@ -1478,7 +1492,9 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
14781492

14791493
SmallVector<DiagnosticInfo, 1> childInfo;
14801494
for (unsigned i : indices(childNotes)) {
1481-
auto child = diagnosticInfoForDiagnostic(childNotes[i]);
1495+
auto child =
1496+
diagnosticInfoForDiagnostic(childNotes[i],
1497+
/* includeDiagnosticName= */ true);
14821498
assert(child);
14831499
assert(child->Kind == DiagnosticKind::Note &&
14841500
"Expected child diagnostics to all be notes?!");
@@ -1516,12 +1532,18 @@ DiagnosticKind DiagnosticEngine::declaredDiagnosticKindFor(const DiagID id) {
15161532
return storedDiagnosticInfos[(unsigned)id].kind;
15171533
}
15181534

1519-
llvm::StringRef DiagnosticEngine::diagnosticStringFor(
1520-
const DiagID id, PrintDiagnosticNamesMode printDiagnosticNamesMode) {
1535+
llvm::StringRef DiagnosticEngine::diagnosticStringFor(DiagID id) {
15211536
llvm::StringRef message = diagnosticStrings[(unsigned)id];
15221537
if (auto localizationProducer = localization.get()) {
15231538
message = localizationProducer->getMessageOr(id, message);
15241539
}
1540+
return message;
1541+
}
1542+
1543+
llvm::StringRef DiagnosticEngine::diagnosticStringWithNameFor(
1544+
DiagID id, DiagGroupID groupID,
1545+
PrintDiagnosticNamesMode printDiagnosticNamesMode) {
1546+
auto message = diagnosticStringFor(id);
15251547
auto formatMessageWithName = [&](StringRef message, StringRef name) {
15261548
const int additionalCharsLength = 3; // ' ', '[', ']'
15271549
std::string messageWithName;
@@ -1540,7 +1562,6 @@ llvm::StringRef DiagnosticEngine::diagnosticStringFor(
15401562
message = formatMessageWithName(message, diagnosticIDStringFor(id));
15411563
break;
15421564
case PrintDiagnosticNamesMode::Group:
1543-
auto groupID = storedDiagnosticInfos[(unsigned)id].groupID;
15441565
if (groupID != DiagGroupID::no_group) {
15451566
message =
15461567
formatMessageWithName(message, getDiagGroupInfoByID(groupID).name);

lib/IDE/CodeCompletionDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ bool CodeCompletionDiagnostics::getDiagnostics(
6767
typename swift::detail::PassArgument<ArgTypes>::type... VArgs) {
6868
DiagID id = ID.ID;
6969
std::vector<DiagnosticArgument> DiagArgs{std::move(VArgs)...};
70-
auto format = Engine.diagnosticStringFor(id, PrintDiagnosticNamesMode::None);
70+
auto format = Engine.diagnosticStringFor(id);
7171
DiagnosticEngine::formatDiagnosticText(Out, format, DiagArgs);
7272
severity = getSeverity(Engine.declaredDiagnosticKindFor(id));
7373

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,8 +977,8 @@ class ModuleWriter {
977977
const_cast<ValueDecl *>(vd));
978978
// Emit a specific unavailable message when we know why a decl can't be
979979
// exposed, or a generic message otherwise.
980-
auto diagString = M.getASTContext().Diags.diagnosticStringFor(
981-
diag.getID(), PrintDiagnosticNamesMode::None);
980+
auto diagString =
981+
M.getASTContext().Diags.diagnosticStringFor(diag.getID());
982982
DiagnosticEngine::formatDiagnosticText(os, diagString, diag.getArgs(),
983983
DiagnosticFormatOptions());
984984
os << "\");\n";

test/attr/attr_availability_noasync.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -print-diagnostic-groups
22

33
// REQUIRES: concurrency
44

@@ -27,16 +27,16 @@ actor IOActor {
2727

2828
@available(SwiftStdlib 5.5, *)
2929
func asyncFunc() async {
30-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
30+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
3131
basicNoAsync()
3232

33-
// expected-warning@+1{{global function 'messageNoAsync' is unavailable from asynchronous contexts; a message from the author}}
33+
// expected-warning@+1{{global function 'messageNoAsync' is unavailable from asynchronous contexts; a message from the author; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
3434
messageNoAsync()
3535

36-
// expected-warning@+1{{global function 'renamedNoAsync' is unavailable from asynchronous contexts}}{{5-19=asyncReplacement}}
36+
// expected-warning@+1{{global function 'renamedNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}{{5-19=asyncReplacement}}
3737
renamedNoAsync() { _ in }
3838

39-
// expected-warning@+1{{global function 'readStringFromIO' is unavailable from asynchronous contexts}}{{13-29=IOActor.readString}}
39+
// expected-warning@+1{{global function 'readStringFromIO' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}{{13-29=IOActor.readString}}
4040
let _ = readStringFromIO()
4141
}
4242

@@ -76,7 +76,7 @@ func test_defers_sync() {
7676
}
7777

7878
func local_async_func() async {
79-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
79+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
8080
defer { basicNoAsync() }
8181
_ = ()
8282
}
@@ -89,7 +89,7 @@ func test_defers_sync() {
8989

9090
// local async closure
9191
let local_async_closure = { () async -> Void in
92-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
92+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
9393
defer { basicNoAsync() }
9494
_ = ()
9595
}
@@ -102,7 +102,7 @@ func test_defers_sync() {
102102

103103
var local_async_var: Void {
104104
get async {
105-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
105+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
106106
defer { basicNoAsync() }
107107
return ()
108108
}
@@ -112,9 +112,9 @@ func test_defers_sync() {
112112
@available(SwiftStdlib 5.5, *)
113113
func test_defer_async() async {
114114
defer {
115-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
115+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
116116
defer { basicNoAsync() }
117-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
117+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
118118
basicNoAsync()
119119
}
120120

@@ -124,7 +124,7 @@ func test_defer_async() async {
124124
}
125125

126126
func local_async_func() async {
127-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
127+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
128128
defer { basicNoAsync() }
129129
_ = ()
130130
}
@@ -136,7 +136,7 @@ func test_defer_async() async {
136136
_ = local_sync_closure
137137

138138
let local_async_closure = { () async -> Void in
139-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
139+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
140140
defer { basicNoAsync() }
141141
_ = ()
142142
}
@@ -149,7 +149,7 @@ func test_defer_async() async {
149149

150150
var local_async_var: Void {
151151
get async {
152-
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
152+
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode [DeclarationUnavailableFromAsynchronousContext]}}
153153
defer { basicNoAsync() }
154154
return ()
155155
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# `DeclarationUnavailableFromAsynchronousContext`
2+
3+
This diagnostic group includes errors and warnings produced by the compiler when attempting to call a function from an asynchronous context that is marked as unavailable in an asynchronous context.
4+
5+
```swift
6+
@available(*, noasync)
7+
func fNoAsync() {}
8+
9+
// Swift 6 language mode
10+
func test() async {
11+
fNoAsync() // error: global function 'fNoAsync' is unavailable from asynchronous contexts
12+
}
13+
14+
// Swift 5 language mode
15+
func test() async {
16+
fNoAsync() // warning: global function 'fNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode
17+
}
18+
```

0 commit comments

Comments
 (0)