Skip to content

Commit db7a400

Browse files
authored
Merge pull request #69821 from kavon/ncgenerics-feature-guard-parsing
[NCGenerics] allow feature-guarded uses of ~Copyable
2 parents 273937a + dbd17c5 commit db7a400

13 files changed

+172
-86
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,9 @@ namespace swift {
509509
void addChildNote(Diagnostic &&D);
510510
void insertChildNote(unsigned beforeIndex, Diagnostic &&D);
511511
};
512+
513+
/// A diagnostic that has no input arguments, so it is trivially-destructable.
514+
using ZeroArgDiagnostic = Diag<>;
512515

513516
/// Describes an in-flight diagnostic, which is currently active
514517
/// within the diagnostic engine and can be augmented within additional

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,8 +961,8 @@ ERROR(cannot_suppress_here,none,
961961
ERROR(only_suppress_copyable,none,
962962
"can only suppress 'Copyable'", ())
963963

964-
ERROR(already_suppressed,none,
965-
"duplicate suppression of %0", (Identifier))
964+
ERROR(already_suppressed_copyable,none,
965+
"duplicate suppression of 'Copyable'", ())
966966

967967
//------------------------------------------------------------------------------
968968
// MARK: Pattern parsing diagnostics

include/swift/AST/TypeRepr.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/Attr.h"
2121
#include "swift/AST/DeclContext.h"
22+
#include "swift/AST/DiagnosticEngine.h"
2223
#include "swift/AST/GenericSignature.h"
2324
#include "swift/AST/Identifier.h"
2425
#include "swift/AST/Type.h"
@@ -195,17 +196,35 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
195196
/// A TypeRepr for a type with a syntax error. Can be used both as a
196197
/// top-level TypeRepr and as a part of other TypeRepr.
197198
///
198-
/// The client should make sure to emit a diagnostic at the construction time
199-
/// (in the parser). All uses of this type should be ignored and not
200-
/// re-diagnosed.
199+
/// The client can either emit a detailed diagnostic at the construction time
200+
/// (in the parser) or store a zero-arg diagnostic in this TypeRepr to be
201+
/// emitted after parsing, during type resolution.
202+
///
203+
/// All uses of this type should be ignored and not re-diagnosed.
201204
class ErrorTypeRepr : public TypeRepr {
202205
SourceRange Range;
206+
llvm::Optional<ZeroArgDiagnostic> DelayedDiag;
207+
208+
ErrorTypeRepr(SourceRange Range, llvm::Optional<ZeroArgDiagnostic> Diag)
209+
: TypeRepr(TypeReprKind::Error), Range(Range), DelayedDiag(Diag) {}
203210

204211
public:
205-
ErrorTypeRepr() : TypeRepr(TypeReprKind::Error) {}
206-
ErrorTypeRepr(SourceLoc Loc) : TypeRepr(TypeReprKind::Error), Range(Loc) {}
207-
ErrorTypeRepr(SourceRange Range)
208-
: TypeRepr(TypeReprKind::Error), Range(Range) {}
212+
static ErrorTypeRepr *
213+
create(ASTContext &Context, SourceRange Range,
214+
llvm::Optional<ZeroArgDiagnostic> DelayedDiag = llvm::None) {
215+
assert((!DelayedDiag || Range) && "diagnostic needs a location");
216+
return new (Context) ErrorTypeRepr(Range, DelayedDiag);
217+
}
218+
219+
static ErrorTypeRepr *
220+
create(ASTContext &Context, SourceLoc Loc = SourceLoc(),
221+
llvm::Optional<ZeroArgDiagnostic> DelayedDiag = llvm::None) {
222+
return create(Context, SourceRange(Loc), DelayedDiag);
223+
}
224+
225+
/// If there is a delayed diagnostic stored in this TypeRepr, consumes and
226+
/// emits that diagnostic.
227+
void dischargeDiagnostic(ASTContext &Context);
209228

210229
static bool classof(const TypeRepr *T) {
211230
return T->getKind() == TypeReprKind::Error;

include/swift/Parse/Parser.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace llvm {
4242

4343
namespace swift {
4444
class IdentTypeRepr;
45+
class ErrorTypeRepr;
4546
class CodeCompletionCallbacks;
4647
class DoneParsingCallback;
4748
class IDEInspectionCallbacksFactory;
@@ -2035,11 +2036,6 @@ class Parser {
20352036
void performIDEInspectionSecondPassImpl(
20362037
IDEInspectionDelayedDeclState &info);
20372038

2038-
/// Returns true if the caller should skip calling `parseType` afterwards.
2039-
bool parseLegacyTildeCopyable(SourceLoc *parseTildeCopyable,
2040-
ParserStatus &Status,
2041-
SourceLoc &TildeCopyableLoc);
2042-
20432039
//===--------------------------------------------------------------------===//
20442040
// ASTGen support.
20452041

lib/AST/DiagnosticEngine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242

4343
using namespace swift;
4444

45+
static_assert(IsTriviallyDestructible<ZeroArgDiagnostic>::value,
46+
"ZeroArgDiagnostic is meant to be trivially destructable");
47+
4548
namespace {
4649
enum class DiagnosticOptions {
4750
/// No options.

lib/AST/TypeRepr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,15 @@ void SILBoxTypeRepr::printImpl(ASTPrinter &Printer,
653653
Printer.printKeyword("sil_box", Opts);
654654
}
655655

656+
void ErrorTypeRepr::dischargeDiagnostic(swift::ASTContext &Context) {
657+
if (!DelayedDiag)
658+
return;
659+
660+
// Consume and emit the diagnostic.
661+
Context.Diags.diagnose(Range.Start, *DelayedDiag).highlight(Range);
662+
DelayedDiag = llvm::None;
663+
}
664+
656665
// See swift/Basic/Statistic.h for declaration: this enables tracing
657666
// TypeReprs, is defined here to avoid too much layering violation / circular
658667
// linkage dependency.

lib/Parse/ParseDecl.cpp

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6426,51 +6426,6 @@ static void addMoveOnlyAttrIf(SourceLoc const &parsedTildeCopyable,
64266426
attrs.add(new(Context) MoveOnlyAttr(/*IsImplicit=*/true));
64276427
}
64286428

6429-
bool Parser::parseLegacyTildeCopyable(SourceLoc *parseTildeCopyable,
6430-
ParserStatus &Status,
6431-
SourceLoc &TildeCopyableLoc) {
6432-
// Is suppression permitted?
6433-
if (parseTildeCopyable) {
6434-
// Try to find '~' 'Copyable'
6435-
//
6436-
// We do this knowing that Copyable is not a real type as of now, so we
6437-
// can't rely on parseType.
6438-
if (Tok.isTilde()) {
6439-
const auto &nextTok = peekToken(); // lookahead
6440-
if (isIdentifier(nextTok, Context.Id_Copyable.str())) {
6441-
auto tildeLoc = consumeToken();
6442-
consumeToken(); // the 'Copyable' token
6443-
6444-
if (TildeCopyableLoc)
6445-
diagnose(tildeLoc, diag::already_suppressed, Context.Id_Copyable);
6446-
else
6447-
TildeCopyableLoc = tildeLoc;
6448-
6449-
return true;
6450-
} else if (nextTok.is(tok::code_complete)) {
6451-
consumeToken(); // consume '~'
6452-
Status.setHasCodeCompletionAndIsError();
6453-
if (CodeCompletionCallbacks) {
6454-
CodeCompletionCallbacks->completeWithoutConstraintType();
6455-
}
6456-
consumeToken(tok::code_complete);
6457-
}
6458-
6459-
// can't suppress whatever is between '~' and ',' or '{'.
6460-
diagnose(Tok, diag::only_suppress_copyable);
6461-
consumeToken();
6462-
}
6463-
6464-
} else if (Tok.isTilde()) {
6465-
// a suppression isn't allowed here, so emit an error eat the token to
6466-
// prevent further parsing errors.
6467-
diagnose(Tok, diag::cannot_suppress_here);
6468-
consumeToken();
6469-
}
6470-
6471-
return false;
6472-
}
6473-
64746429
/// Parse an inheritance clause.
64756430
///
64766431
/// \verbatim
@@ -6546,11 +6501,47 @@ ParserStatus Parser::parseInheritance(
65466501
continue;
65476502
}
65486503

6549-
if (!EnabledNoncopyableGenerics) {
6550-
if (parseLegacyTildeCopyable(parseTildeCopyable,
6551-
Status,
6552-
TildeCopyableLoc))
6553-
continue;
6504+
if (!EnabledNoncopyableGenerics && Tok.isTilde()) {
6505+
ErrorTypeRepr *error = nullptr;
6506+
if (parseTildeCopyable) {
6507+
const auto &nextTok = peekToken(); // lookahead
6508+
if (isIdentifier(nextTok, Context.Id_Copyable.str())) {
6509+
auto tildeLoc = consumeToken();
6510+
consumeToken(); // the 'Copyable' token
6511+
6512+
if (TildeCopyableLoc)
6513+
Inherited.push_back(InheritedEntry(
6514+
ErrorTypeRepr::create(Context, tildeLoc,
6515+
diag::already_suppressed_copyable)));
6516+
else
6517+
TildeCopyableLoc = tildeLoc;
6518+
6519+
continue; // success
6520+
}
6521+
6522+
if (nextTok.is(tok::code_complete)) {
6523+
consumeToken(); // consume '~'
6524+
Status.setHasCodeCompletionAndIsError();
6525+
if (CodeCompletionCallbacks) {
6526+
CodeCompletionCallbacks->completeWithoutConstraintType();
6527+
}
6528+
consumeToken(tok::code_complete);
6529+
}
6530+
6531+
// can't suppress whatever is between '~' and ',' or '{'.
6532+
error = ErrorTypeRepr::create(Context, consumeToken(),
6533+
diag::only_suppress_copyable);
6534+
} else {
6535+
// Otherwise, a suppression isn't allowed here unless noncopyable
6536+
// generics is enabled, so record a delayed error diagnostic and
6537+
// eat the token to prevent further parsing errors.
6538+
error = ErrorTypeRepr::create(Context, consumeToken(),
6539+
diag::cannot_suppress_here);
6540+
}
6541+
6542+
// Record the error parsing ~Copyable, but continue on to parseType.
6543+
if (error)
6544+
Inherited.push_back(InheritedEntry(error));
65546545
}
65556546

65566547
auto ParsedTypeResult = parseType();
@@ -9665,7 +9656,7 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
96659656

96669657
if (ElementTy.isNull()) {
96679658
// Always set an element type.
9668-
ElementTy = makeParserResult(ElementTy, new (Context) ErrorTypeRepr());
9659+
ElementTy = makeParserResult(ElementTy, ErrorTypeRepr::create(Context));
96699660
}
96709661
}
96719662

lib/Parse/ParseGeneric.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ ParserStatus Parser::parseGenericWhereClause(
339339
ParserResult<TypeRepr> Protocol = parseType();
340340
Status |= Protocol;
341341
if (Protocol.isNull())
342-
Protocol = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));
342+
Protocol = makeParserResult(ErrorTypeRepr::create(Context, PreviousLoc));
343343

344344
// Add the requirement.
345345
Requirements.push_back(RequirementRepr::getTypeConstraint(
@@ -358,7 +358,7 @@ ParserStatus Parser::parseGenericWhereClause(
358358
ParserResult<TypeRepr> SecondType = parseType();
359359
Status |= SecondType;
360360
if (SecondType.isNull())
361-
SecondType = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));
361+
SecondType = makeParserResult(ErrorTypeRepr::create(Context, PreviousLoc));
362362

363363
// Add the requirement
364364
if (FirstType.hasCodeCompletion()) {
@@ -373,7 +373,7 @@ ParserStatus Parser::parseGenericWhereClause(
373373
// completion token in the TypeRepr.
374374
Requirements.push_back(RequirementRepr::getTypeConstraint(
375375
FirstType.get(), EqualLoc,
376-
new (Context) ErrorTypeRepr(SecondType.get()->getLoc()),
376+
ErrorTypeRepr::create(Context, SecondType.get()->getLoc()),
377377
isRequirementExpansion));
378378
} else {
379379
Requirements.push_back(RequirementRepr::getSameType(
@@ -383,7 +383,7 @@ ParserStatus Parser::parseGenericWhereClause(
383383
} else if (FirstType.hasCodeCompletion()) {
384384
// Recover by adding dummy constraint.
385385
Requirements.push_back(RequirementRepr::getTypeConstraint(
386-
FirstType.get(), PreviousLoc, new (Context) ErrorTypeRepr(PreviousLoc),
386+
FirstType.get(), PreviousLoc, ErrorTypeRepr::create(Context, PreviousLoc),
387387
isRequirementExpansion));
388388
} else {
389389
diagnose(Tok, diag::expected_requirement_delim);

lib/Parse/ParsePattern.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ ParserResult<Pattern> Parser::parseTypedPattern() {
10531053
}
10541054
}
10551055
} else {
1056-
Ty = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));
1056+
Ty = makeParserResult(ErrorTypeRepr::create(Context, PreviousLoc));
10571057
}
10581058

10591059
result = makeParserResult(result,
@@ -1278,7 +1278,7 @@ parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result) {
12781278

12791279
TypeRepr *repr = Ty.getPtrOrNull();
12801280
if (!repr)
1281-
repr = new (Context) ErrorTypeRepr(PreviousLoc);
1281+
repr = ErrorTypeRepr::create(Context, PreviousLoc);
12821282

12831283
return makeParserResult(status, new (Context) TypedPattern(P, repr));
12841284
}

lib/Parse/ParseType.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,6 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
172172
SourceLoc tildeLoc;
173173
if (Tok.isTilde() && !isInSILMode()) {
174174
tildeLoc = consumeToken();
175-
if (!EnabledNoncopyableGenerics)
176-
diagnose(tildeLoc, diag::cannot_suppress_here)
177-
.fixItRemoveChars(tildeLoc, tildeLoc);
178175
}
179176

180177
switch (Tok.getKind()) {
@@ -232,7 +229,7 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
232229
CodeCompletionCallbacks->completeTypeSimpleBeginning();
233230
}
234231
return makeParserCodeCompletionResult<TypeRepr>(
235-
new (Context) ErrorTypeRepr(consumeToken(tok::code_complete)));
232+
ErrorTypeRepr::create(Context, consumeToken(tok::code_complete)));
236233
case tok::l_square: {
237234
ty = parseTypeCollection();
238235
break;
@@ -255,7 +252,7 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
255252
diag.fixItInsert(getEndOfPreviousLoc(), " <#type#>");
256253
}
257254
if (Tok.isKeyword() && !Tok.isAtStartOfLine()) {
258-
ty = makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc()));
255+
ty = makeParserErrorResult(ErrorTypeRepr::create(Context, Tok.getLoc()));
259256
consumeToken();
260257
return ty;
261258
}
@@ -310,9 +307,15 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
310307
}
311308

312309
// Wrap in an InverseTypeRepr if needed.
313-
if (EnabledNoncopyableGenerics && tildeLoc) {
314-
ty = makeParserResult(ty,
315-
new(Context) InverseTypeRepr(tildeLoc, ty.get()));
310+
if (tildeLoc) {
311+
TypeRepr *repr;
312+
if (EnabledNoncopyableGenerics)
313+
repr = new (Context) InverseTypeRepr(tildeLoc, ty.get());
314+
else
315+
repr =
316+
ErrorTypeRepr::create(Context, tildeLoc, diag::cannot_suppress_here);
317+
318+
ty = makeParserResult(ty, repr);
316319
}
317320

318321
return ty;
@@ -685,8 +688,8 @@ ParserResult<TypeRepr> Parser::parseDeclResultType(Diag<> MessageID) {
685688
auto diag = diagnose(Tok, diag::extra_rbracket);
686689
diag.fixItInsert(result.get()->getStartLoc(), getTokenText(tok::l_square));
687690
consumeToken();
688-
return makeParserErrorResult(new (Context)
689-
ErrorTypeRepr(getTypeErrorLoc()));
691+
return makeParserErrorResult(ErrorTypeRepr::create(Context,
692+
getTypeErrorLoc()));
690693
}
691694

692695
if (Tok.is(tok::colon)) {
@@ -702,8 +705,8 @@ ParserResult<TypeRepr> Parser::parseDeclResultType(Diag<> MessageID) {
702705
diag.fixItInsertAfter(secondType.get()->getEndLoc(), getTokenText(tok::r_square));
703706
}
704707
}
705-
return makeParserErrorResult(new (Context)
706-
ErrorTypeRepr(getTypeErrorLoc()));
708+
return makeParserErrorResult(ErrorTypeRepr::create(Context,
709+
getTypeErrorLoc()));
707710
}
708711
}
709712
return result;

lib/Sema/PreCheckExpr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,7 +2010,7 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) {
20102010
Ctx.Diags.diagnose(AE->getArgsExpr()->getLoc(),
20112011
diag::expected_type_before_arrow);
20122012
auto ArgRange = AE->getArgsExpr()->getSourceRange();
2013-
auto ErrRepr = new (Ctx) ErrorTypeRepr(ArgRange);
2013+
auto ErrRepr = ErrorTypeRepr::create(Ctx, ArgRange);
20142014
ArgsTypeRepr =
20152015
TupleTypeRepr::create(Ctx, {ErrRepr}, ArgRange);
20162016
}
@@ -2025,8 +2025,8 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) {
20252025
if (!ResultTypeRepr) {
20262026
Ctx.Diags.diagnose(AE->getResultExpr()->getLoc(),
20272027
diag::expected_type_after_arrow);
2028-
ResultTypeRepr = new (Ctx)
2029-
ErrorTypeRepr(AE->getResultExpr()->getSourceRange());
2028+
ResultTypeRepr =
2029+
ErrorTypeRepr::create(Ctx, AE->getResultExpr()->getSourceRange());
20302030
}
20312031

20322032
auto NewTypeRepr = new (Ctx)

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,7 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
24312431

24322432
switch (repr->getKind()) {
24332433
case TypeReprKind::Error:
2434+
cast<ErrorTypeRepr>(repr)->dischargeDiagnostic(getASTContext());
24342435
return ErrorType::get(getASTContext());
24352436

24362437
case TypeReprKind::Attributed:

0 commit comments

Comments
 (0)