@@ -236,8 +236,21 @@ static EnumDecl *addImplicitCodingKeys(NominalTypeDecl *target) {
236
236
return addImplicitCodingKeys (target, caseIdentifiers, C.Id_CodingKeys );
237
237
}
238
238
239
+ namespace {
240
+ // / Container for a set of functions that produces notes used when a
241
+ // / synthesized conformance fails.
242
+ struct DelayedNotes : public std ::vector<std::function<void ()>> {
243
+ ~DelayedNotes () {
244
+ for (const auto &fn : *this ) {
245
+ fn ();
246
+ }
247
+ }
248
+ };
249
+ }
250
+
239
251
static EnumDecl *validateCodingKeysType (const DerivedConformance &derived,
240
- TypeDecl *_codingKeysTypeDecl) {
252
+ TypeDecl *_codingKeysTypeDecl,
253
+ DelayedNotes &delayedNotes) {
241
254
auto &C = derived.Context ;
242
255
// CodingKeys may be a typealias. If so, follow the alias to its canonical
243
256
// type. We are creating a copy here, so we can hold on to the original
@@ -258,17 +271,22 @@ static EnumDecl *validateCodingKeysType(const DerivedConformance &derived,
258
271
SourceLoc loc = codingKeysTypeDecl ? codingKeysTypeDecl->getLoc ()
259
272
: cast<TypeDecl>(_codingKeysTypeDecl)->getLoc ();
260
273
261
- C.Diags .diagnose (loc, diag::codable_codingkeys_type_does_not_conform_here,
262
- derived.getProtocolType ());
274
+ delayedNotes.push_back ([=] {
275
+ ASTContext &C = derived.getProtocolType ()->getASTContext ();
276
+ C.Diags .diagnose (loc, diag::codable_codingkeys_type_does_not_conform_here,
277
+ derived.getProtocolType ());
278
+ });
263
279
return nullptr ;
264
280
}
265
281
266
282
auto *codingKeysDecl =
267
283
dyn_cast_or_null<EnumDecl>(codingKeysType->getAnyNominal ());
268
284
if (!codingKeysDecl) {
269
- codingKeysTypeDecl->diagnose (
270
- diag::codable_codingkeys_type_is_not_an_enum_here,
271
- derived.getProtocolType ());
285
+ delayedNotes.push_back ([=] {
286
+ codingKeysTypeDecl->diagnose (
287
+ diag::codable_codingkeys_type_is_not_an_enum_here,
288
+ derived.getProtocolType ());
289
+ });
272
290
return nullptr ;
273
291
}
274
292
@@ -282,8 +300,10 @@ static EnumDecl *validateCodingKeysType(const DerivedConformance &derived,
282
300
// / \param codingKeysTypeDecl The \c CodingKeys enum decl to validate.
283
301
static bool validateCodingKeysEnum (const DerivedConformance &derived,
284
302
llvm::SmallMapVector<Identifier, VarDecl *, 8 > varDecls,
285
- TypeDecl *codingKeysTypeDecl) {
286
- auto *codingKeysDecl = validateCodingKeysType (derived, codingKeysTypeDecl);
303
+ TypeDecl *codingKeysTypeDecl,
304
+ DelayedNotes &delayedNotes) {
305
+ auto *codingKeysDecl = validateCodingKeysType (
306
+ derived, codingKeysTypeDecl, delayedNotes);
287
307
if (!codingKeysDecl)
288
308
return false ;
289
309
@@ -297,8 +317,10 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived,
297
317
for (auto elt : codingKeysDecl->getAllElements ()) {
298
318
auto it = varDecls.find (elt->getBaseIdentifier ());
299
319
if (it == varDecls.end ()) {
300
- elt->diagnose (diag::codable_extraneous_codingkey_case_here,
301
- elt->getBaseIdentifier ());
320
+ delayedNotes.push_back ([=] {
321
+ elt->diagnose (diag::codable_extraneous_codingkey_case_here,
322
+ elt->getBaseIdentifier ());
323
+ });
302
324
// TODO: Investigate typo-correction here; perhaps the case name was
303
325
// misspelled and we can provide a fix-it.
304
326
varDeclsAreValid = false ;
@@ -315,8 +337,13 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived,
315
337
it->second ->getTypeReprOrParentPatternTypeRepr (),
316
338
it->second ->getType (),
317
339
};
318
- it->second ->diagnose (diag::codable_non_conforming_property_here,
319
- derived.getProtocolType (), typeLoc);
340
+
341
+ auto var = it->second ;
342
+ auto proto = derived.getProtocolType ();
343
+ delayedNotes.push_back ([=] {
344
+ var->diagnose (diag::codable_non_conforming_property_here,
345
+ proto, typeLoc);
346
+ });
320
347
varDeclsAreValid = false ;
321
348
} else {
322
349
// The property was valid. Remove it from the list.
@@ -350,16 +377,19 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived,
350
377
// The var was not default initializable, and did not have an explicit
351
378
// initial value.
352
379
varDeclsAreValid = false ;
353
- entry.second ->diagnose (diag::codable_non_decoded_property_here,
354
- derived.getProtocolType (), entry.first );
380
+ delayedNotes.push_back ([=] {
381
+ entry.second ->diagnose (diag::codable_non_decoded_property_here,
382
+ derived.getProtocolType (), entry.first );
383
+ });
355
384
}
356
385
}
357
386
358
387
return varDeclsAreValid;
359
388
}
360
389
361
390
static bool validateCodingKeysEnum_enum (const DerivedConformance &derived,
362
- TypeDecl *codingKeysTypeDecl) {
391
+ TypeDecl *codingKeysTypeDecl,
392
+ DelayedNotes &delayedNotes) {
363
393
auto *enumDecl = dyn_cast<EnumDecl>(derived.Nominal );
364
394
if (!enumDecl) {
365
395
return false ;
@@ -369,16 +399,18 @@ static bool validateCodingKeysEnum_enum(const DerivedConformance &derived,
369
399
caseNames.insert (elt->getBaseIdentifier ());
370
400
}
371
401
372
- auto *codingKeysDecl = validateCodingKeysType (derived,
373
- codingKeysTypeDecl);
402
+ auto *codingKeysDecl = validateCodingKeysType (
403
+ derived, codingKeysTypeDecl, delayedNotes );
374
404
if (!codingKeysDecl)
375
405
return false ;
376
406
377
407
bool casesAreValid = true ;
378
408
for (auto *elt : codingKeysDecl->getAllElements ()) {
379
409
if (!caseNames.contains (elt->getBaseIdentifier ())) {
380
- elt->diagnose (diag::codable_extraneous_codingkey_case_here,
381
- elt->getBaseIdentifier ());
410
+ delayedNotes.push_back ([=] {
411
+ elt->diagnose (diag::codable_extraneous_codingkey_case_here,
412
+ elt->getBaseIdentifier ());
413
+ });
382
414
casesAreValid = false ;
383
415
}
384
416
}
@@ -388,7 +420,8 @@ static bool validateCodingKeysEnum_enum(const DerivedConformance &derived,
388
420
389
421
// / Looks up and validates a CodingKeys enum for the given DerivedConformance.
390
422
// / If a CodingKeys enum does not exist, one will be derived.
391
- static bool validateCodingKeysEnum (const DerivedConformance &derived) {
423
+ static bool validateCodingKeysEnum (const DerivedConformance &derived,
424
+ DelayedNotes &delayedNotes) {
392
425
auto &C = derived.Context ;
393
426
394
427
auto codingKeysDecls =
@@ -403,13 +436,16 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived) {
403
436
: codingKeysDecls.front ();
404
437
auto *codingKeysTypeDecl = dyn_cast<TypeDecl>(result);
405
438
if (!codingKeysTypeDecl) {
406
- result->diagnose (diag::codable_codingkeys_type_is_not_an_enum_here,
407
- derived.getProtocolType ());
439
+ delayedNotes.push_back ([=] {
440
+ result->diagnose (diag::codable_codingkeys_type_is_not_an_enum_here,
441
+ derived.getProtocolType ());
442
+ });
408
443
return false ;
409
444
}
410
445
411
446
if (dyn_cast<EnumDecl>(derived.Nominal )) {
412
- return validateCodingKeysEnum_enum (derived, codingKeysTypeDecl);
447
+ return validateCodingKeysEnum_enum (
448
+ derived, codingKeysTypeDecl, delayedNotes);
413
449
} else {
414
450
415
451
// Look through all var decls in the given type.
@@ -426,7 +462,8 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived) {
426
462
properties[getVarNameForCoding (varDecl)] = varDecl;
427
463
}
428
464
429
- return validateCodingKeysEnum (derived, properties, codingKeysTypeDecl);
465
+ return validateCodingKeysEnum (
466
+ derived, properties, codingKeysTypeDecl, delayedNotes);
430
467
}
431
468
}
432
469
@@ -435,7 +472,8 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived) {
435
472
// /
436
473
// / \param elementDecl The \c EnumElementDecl to validate against.
437
474
static bool validateCaseCodingKeysEnum (const DerivedConformance &derived,
438
- EnumElementDecl *elementDecl) {
475
+ EnumElementDecl *elementDecl,
476
+ DelayedNotes &delayedNotes) {
439
477
auto &C = derived.Context ;
440
478
auto *enumDecl = dyn_cast<EnumDecl>(derived.Nominal );
441
479
if (!enumDecl) {
@@ -471,8 +509,10 @@ static bool validateCaseCodingKeysEnum(const DerivedConformance &derived,
471
509
472
510
auto *codingKeysTypeDecl = dyn_cast<TypeDecl>(result);
473
511
if (!codingKeysTypeDecl) {
474
- result->diagnose (diag::codable_codingkeys_type_is_not_an_enum_here,
475
- derived.getProtocolType ());
512
+ delayedNotes.push_back ([=] {
513
+ result->diagnose (diag::codable_codingkeys_type_is_not_an_enum_here,
514
+ derived.getProtocolType ());
515
+ });
476
516
return false ;
477
517
}
478
518
@@ -490,7 +530,8 @@ static bool validateCaseCodingKeysEnum(const DerivedConformance &derived,
490
530
}
491
531
}
492
532
493
- return validateCodingKeysEnum (derived, properties, codingKeysTypeDecl);
533
+ return validateCodingKeysEnum (
534
+ derived, properties, codingKeysTypeDecl, delayedNotes);
494
535
}
495
536
496
537
// / Creates a new var decl representing
@@ -1815,7 +1856,8 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
1815
1856
// / not, attempts to synthesize one for it.
1816
1857
// /
1817
1858
// / \param requirement The requirement we want to synthesize.
1818
- static bool canSynthesize (DerivedConformance &derived, ValueDecl *requirement) {
1859
+ static bool canSynthesize (DerivedConformance &derived, ValueDecl *requirement,
1860
+ DelayedNotes &delayedNotes) {
1819
1861
// Before we attempt to look up (or more importantly, synthesize) a CodingKeys
1820
1862
// entity on target, we need to make sure the type is otherwise valid.
1821
1863
//
@@ -1851,8 +1893,11 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
1851
1893
1852
1894
if (result.empty ()) {
1853
1895
// No super initializer for us to call.
1854
- superclassDecl->diagnose (diag::decodable_no_super_init_here,
1855
- requirement->getName (), memberName);
1896
+ delayedNotes.push_back ([=] {
1897
+ superclassDecl->diagnose (diag::decodable_no_super_init_here,
1898
+ requirement->getName (), memberName);
1899
+ });
1900
+
1856
1901
return false ;
1857
1902
} else if (result.size () > 1 ) {
1858
1903
// There are multiple results for this lookup. We'll end up producing a
@@ -1865,28 +1910,35 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
1865
1910
auto conformanceDC = derived.getConformanceContext ();
1866
1911
if (!initializer->isDesignatedInit ()) {
1867
1912
// We must call a superclass's designated initializer.
1868
- initializer->diagnose (diag::decodable_super_init_not_designated_here,
1869
- requirement->getName (), memberName);
1913
+ delayedNotes.push_back ([=] {
1914
+ initializer->diagnose (
1915
+ diag::decodable_super_init_not_designated_here,
1916
+ requirement->getName (), memberName);
1917
+ });
1870
1918
return false ;
1871
1919
} else if (!initializer->isAccessibleFrom (conformanceDC)) {
1872
1920
// Cannot call an inaccessible method.
1873
- auto accessScope = initializer->getFormalAccessScope (conformanceDC);
1874
- initializer->diagnose (diag::decodable_inaccessible_super_init_here,
1875
- requirement->getName (), memberName,
1876
- accessScope.accessLevelForDiagnostics ());
1921
+ delayedNotes.push_back ([=] {
1922
+ auto accessScope = initializer->getFormalAccessScope (conformanceDC);
1923
+ initializer->diagnose (diag::decodable_inaccessible_super_init_here,
1924
+ requirement->getName (), memberName,
1925
+ accessScope.accessLevelForDiagnostics ());
1926
+ });
1877
1927
return false ;
1878
1928
} else if (initializer->isFailable ()) {
1879
1929
// We can't call super.init() if it's failable, since init(from:)
1880
1930
// isn't failable.
1881
- initializer->diagnose (diag::decodable_super_init_is_failable_here,
1882
- requirement->getName (), memberName);
1931
+ delayedNotes.push_back ([=] {
1932
+ initializer->diagnose (diag::decodable_super_init_is_failable_here,
1933
+ requirement->getName (), memberName);
1934
+ });
1883
1935
return false ;
1884
1936
}
1885
1937
}
1886
1938
}
1887
1939
}
1888
1940
1889
- if (!validateCodingKeysEnum (derived)) {
1941
+ if (!validateCodingKeysEnum (derived, delayedNotes )) {
1890
1942
return false ;
1891
1943
}
1892
1944
@@ -1896,10 +1948,12 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
1896
1948
for (auto *elementDecl : enumDecl->getAllElements ()) {
1897
1949
bool duplicate = false ;
1898
1950
if (!caseNames.insert (elementDecl->getBaseIdentifier ())) {
1899
- elementDecl->diagnose (diag::codable_enum_duplicate_case_name_here,
1900
- derived.getProtocolType (),
1901
- derived.Nominal ->getDeclaredType (),
1902
- elementDecl->getBaseIdentifier ());
1951
+ delayedNotes.push_back ([=] {
1952
+ elementDecl->diagnose (diag::codable_enum_duplicate_case_name_here,
1953
+ derived.getProtocolType (),
1954
+ derived.Nominal ->getDeclaredType (),
1955
+ elementDecl->getBaseIdentifier ());
1956
+ });
1903
1957
allValid = false ;
1904
1958
duplicate = true ;
1905
1959
}
@@ -1925,17 +1979,20 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
1925
1979
userDefinedParam = inserted.first ->second ;
1926
1980
}
1927
1981
1928
- userDefinedParam->diagnose (diag::codable_enum_duplicate_parameter_name_here,
1929
- derived.getProtocolType (),
1930
- derived.Nominal ->getDeclaredType (),
1931
- paramIdentifier,
1932
- elementDecl->getBaseIdentifier ());
1982
+ delayedNotes.push_back ([=] {
1983
+ userDefinedParam->diagnose (diag::codable_enum_duplicate_parameter_name_here,
1984
+ derived.getProtocolType (),
1985
+ derived.Nominal ->getDeclaredType (),
1986
+ paramIdentifier,
1987
+ elementDecl->getBaseIdentifier ());
1988
+ });
1933
1989
allValid = false ;
1934
1990
}
1935
1991
}
1936
1992
}
1937
1993
1938
- if (!duplicate && !validateCaseCodingKeysEnum (derived, elementDecl)) {
1994
+ if (!duplicate &&
1995
+ !validateCaseCodingKeysEnum (derived, elementDecl, delayedNotes)) {
1939
1996
allValid = false ;
1940
1997
}
1941
1998
}
@@ -1989,7 +2046,8 @@ ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
1989
2046
1990
2047
// Check other preconditions for synthesized conformance.
1991
2048
// This synthesizes a CodingKeys enum if possible.
1992
- if (!canSynthesize (*this , requirement)) {
2049
+ DelayedNotes delayedNotes;
2050
+ if (!canSynthesize (*this , requirement, delayedNotes)) {
1993
2051
ConformanceDecl->diagnose (diag::type_does_not_conform,
1994
2052
Nominal->getDeclaredType (), getProtocolType ());
1995
2053
requirement->diagnose (diag::no_witnesses, diag::RequirementKind::Func,
@@ -1998,6 +2056,7 @@ ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
1998
2056
1999
2057
return nullptr ;
2000
2058
}
2059
+ assert (delayedNotes.empty ());
2001
2060
2002
2061
return deriveEncodable_encode (*this );
2003
2062
}
@@ -2019,7 +2078,8 @@ ValueDecl *DerivedConformance::deriveDecodable(ValueDecl *requirement) {
2019
2078
2020
2079
// Check other preconditions for synthesized conformance.
2021
2080
// This synthesizes a CodingKeys enum if possible.
2022
- if (!canSynthesize (*this , requirement)) {
2081
+ DelayedNotes delayedNotes;
2082
+ if (!canSynthesize (*this , requirement, delayedNotes)) {
2023
2083
ConformanceDecl->diagnose (diag::type_does_not_conform,
2024
2084
Nominal->getDeclaredType (), getProtocolType ());
2025
2085
requirement->diagnose (diag::no_witnesses, diag::RequirementKind::Constructor,
@@ -2028,6 +2088,7 @@ ValueDecl *DerivedConformance::deriveDecodable(ValueDecl *requirement) {
2028
2088
2029
2089
return nullptr ;
2030
2090
}
2091
+ assert (delayedNotes.empty ());
2031
2092
2032
2093
return deriveDecodable_init (*this );
2033
2094
}
0 commit comments