Skip to content

Commit c01360d

Browse files
committed
[Sema] reimplement ~C as an general inverse constraint
1 parent 68ae729 commit c01360d

File tree

11 files changed

+145
-38
lines changed

11 files changed

+145
-38
lines changed

include/swift/AST/TypeRepr.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,34 @@ class ExistentialTypeRepr: public TypeRepr {
13211321
friend class TypeRepr;
13221322
};
13231323

1324+
/// A type repr represeting the inverse of some constraint. For example,
1325+
/// ~Copyable
1326+
/// where `Copyable` is the constraint type.
1327+
class InverseTypeRepr : public TypeRepr {
1328+
TypeRepr *Constraint;
1329+
SourceLoc TildeLoc;
1330+
1331+
public:
1332+
InverseTypeRepr(SourceLoc tildeLoc, TypeRepr *constraint)
1333+
: TypeRepr(TypeReprKind::Inverse), Constraint(constraint),
1334+
TildeLoc(tildeLoc) {}
1335+
1336+
TypeRepr *getConstraint() const { return Constraint; }
1337+
SourceLoc getTildeLoc() const { return TildeLoc; }
1338+
1339+
static bool classof(const TypeRepr *T) {
1340+
return T->getKind() == TypeReprKind::Inverse;
1341+
}
1342+
static bool classof(const InverseTypeRepr *T) { return true; }
1343+
1344+
private:
1345+
SourceLoc getStartLocImpl() const { return TildeLoc; }
1346+
SourceLoc getEndLocImpl() const { return Constraint->getEndLoc(); }
1347+
SourceLoc getLocImpl() const { return TildeLoc; }
1348+
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
1349+
friend class TypeRepr;
1350+
};
1351+
13241352
/// TypeRepr for a user-specified placeholder (essentially, a user-facing
13251353
/// representation of an anonymous type variable.
13261354
///
@@ -1459,6 +1487,7 @@ inline bool TypeRepr::isSimple() const {
14591487
case TypeReprKind::Dictionary:
14601488
case TypeReprKind::Optional:
14611489
case TypeReprKind::ImplicitlyUnwrappedOptional:
1490+
case TypeReprKind::Inverse:
14621491
case TypeReprKind::Vararg:
14631492
case TypeReprKind::PackExpansion:
14641493
case TypeReprKind::Pack:

include/swift/AST/TypeReprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ TYPEREPR(Protocol, TypeRepr)
6565
TYPEREPR(OpaqueReturn, TypeRepr)
6666
TYPEREPR(NamedOpaqueReturn, TypeRepr)
6767
TYPEREPR(Existential, TypeRepr)
68+
TYPEREPR(Inverse, TypeRepr)
6869
TYPEREPR(Pack, TypeRepr)
6970
TYPEREPR(PackElement, TypeRepr)
7071
TYPEREPR(Placeholder, TypeRepr)

include/swift/Parse/Parser.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ class Parser {
158158
bool InSwiftKeyPath = false;
159159
bool InFreestandingMacroArgument = false;
160160

161+
// A cached answer to
162+
// Context.LangOpts.hasFeature(Feature::NoncopyableGenerics)
163+
// to ensure there's no parsing performance regression.
164+
bool EnabledNoncopyableGenerics;
165+
161166
/// Whether we should delay parsing nominal type, extension, and function
162167
/// bodies.
163168
bool isDelayedParsingEnabled() const;
@@ -2058,6 +2063,11 @@ class Parser {
20582063

20592064
void performIDEInspectionSecondPassImpl(
20602065
IDEInspectionDelayedDeclState &info);
2066+
2067+
/// Returns true if the caller should skip calling `parseType` afterwards.
2068+
bool parseLegacyTildeCopyable(SourceLoc *parseTildeCopyable,
2069+
ParserStatus &Status,
2070+
SourceLoc &TildeCopyableLoc);
20612071
};
20622072

20632073
/// Describes a parsed declaration name.

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3221,6 +3221,12 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, StringRef>,
32213221
printFoot();
32223222
}
32233223

3224+
void visitInverseTypeRepr(InverseTypeRepr *T, StringRef label) {
3225+
printCommon("inverse", label);
3226+
printRec(T->getConstraint());
3227+
printFoot();
3228+
}
3229+
32243230
void visitArrayTypeRepr(ArrayTypeRepr *T, StringRef label) {
32253231
printCommon("type_array", label);
32263232
printRec(T->getBase());

lib/AST/ASTWalker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,6 +2210,10 @@ bool Traversal::visitExistentialTypeRepr(ExistentialTypeRepr *T) {
22102210
return doIt(T->getConstraint());
22112211
}
22122212

2213+
bool Traversal::visitInverseTypeRepr(InverseTypeRepr *T) {
2214+
return doIt(T->getConstraint());
2215+
}
2216+
22132217
bool Traversal::visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) {
22142218
return false;
22152219
}

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,6 +3018,7 @@ directReferencesForTypeRepr(Evaluator &evaluator,
30183018
case TypeReprKind::OpaqueReturn:
30193019
case TypeReprKind::NamedOpaqueReturn:
30203020
case TypeReprKind::Existential:
3021+
case TypeReprKind::Inverse:
30213022
return { };
30223023

30233024
case TypeReprKind::Fixed:

lib/AST/TypeRepr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,12 @@ void NamedOpaqueReturnTypeRepr::printImpl(ASTPrinter &Printer,
588588
printTypeRepr(Base, Printer, Opts);
589589
}
590590

591+
void InverseTypeRepr::printImpl(ASTPrinter &Printer,
592+
const PrintOptions &Opts) const {
593+
Printer << "~";
594+
printTypeRepr(Constraint, Printer, Opts);
595+
}
596+
591597
void SpecifierTypeRepr::printImpl(ASTPrinter &Printer,
592598
const PrintOptions &Opts) const {
593599
switch (getKind()) {

lib/Parse/ParseDecl.cpp

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6142,6 +6142,9 @@ static void addMoveOnlyAttrIf(SourceLoc const &parsedTildeCopyable,
61426142
if (parsedTildeCopyable.isInvalid())
61436143
return;
61446144

6145+
if (Context.LangOpts.hasFeature(Feature::NoncopyableGenerics))
6146+
llvm_unreachable("unexpected use of legacy ~Copyable parsing");
6147+
61456148
auto &attrs = decl->getAttrs();
61466149

61476150
// Don't add if it's already explicitly written on the decl, but error about
@@ -6159,6 +6162,51 @@ static void addMoveOnlyAttrIf(SourceLoc const &parsedTildeCopyable,
61596162
attrs.add(new(Context) MoveOnlyAttr(/*IsImplicit=*/true));
61606163
}
61616164

6165+
bool Parser::parseLegacyTildeCopyable(SourceLoc *parseTildeCopyable,
6166+
ParserStatus &Status,
6167+
SourceLoc &TildeCopyableLoc) {
6168+
// Is suppression permitted?
6169+
if (parseTildeCopyable) {
6170+
// Try to find '~' 'Copyable'
6171+
//
6172+
// We do this knowing that Copyable is not a real type as of now, so we
6173+
// can't rely on parseType.
6174+
if (Tok.isTilde()) {
6175+
const auto &nextTok = peekToken(); // lookahead
6176+
if (isIdentifier(nextTok, Context.Id_Copyable.str())) {
6177+
auto tildeLoc = consumeToken();
6178+
consumeToken(); // the 'Copyable' token
6179+
6180+
if (TildeCopyableLoc)
6181+
diagnose(tildeLoc, diag::already_suppressed, Context.Id_Copyable);
6182+
else
6183+
TildeCopyableLoc = tildeLoc;
6184+
6185+
return true;
6186+
} else if (nextTok.is(tok::code_complete)) {
6187+
consumeToken(); // consume '~'
6188+
Status.setHasCodeCompletionAndIsError();
6189+
if (CodeCompletionCallbacks) {
6190+
CodeCompletionCallbacks->completeWithoutConstraintType();
6191+
}
6192+
consumeToken(tok::code_complete);
6193+
}
6194+
6195+
// can't suppress whatever is between '~' and ',' or '{'.
6196+
diagnose(Tok, diag::only_suppress_copyable);
6197+
consumeToken();
6198+
}
6199+
6200+
} else if (Tok.isTilde()) {
6201+
// a suppression isn't allowed here, so emit an error eat the token to
6202+
// prevent further parsing errors.
6203+
diagnose(Tok, diag::cannot_suppress_here);
6204+
consumeToken();
6205+
}
6206+
6207+
return false;
6208+
}
6209+
61626210
/// Parse an inheritance clause.
61636211
///
61646212
/// \verbatim
@@ -6234,43 +6282,11 @@ ParserStatus Parser::parseInheritance(
62346282
continue;
62356283
}
62366284

6237-
// Is suppression permitted?
6238-
if (parseTildeCopyable) {
6239-
// Try to find '~' 'Copyable'
6240-
//
6241-
// We do this knowing that Copyable is not a real type as of now, so we
6242-
// can't rely on parseType.
6243-
if (Tok.isTilde()) {
6244-
const auto &nextTok = peekToken(); // lookahead
6245-
if (isIdentifier(nextTok, Context.Id_Copyable.str())) {
6246-
auto tildeLoc = consumeToken();
6247-
consumeToken(); // the 'Copyable' token
6248-
6249-
if (TildeCopyableLoc)
6250-
diagnose(tildeLoc, diag::already_suppressed, Context.Id_Copyable);
6251-
else
6252-
TildeCopyableLoc = tildeLoc;
6253-
6254-
continue;
6255-
} else if (nextTok.is(tok::code_complete)) {
6256-
consumeToken(); // consume '~'
6257-
Status.setHasCodeCompletionAndIsError();
6258-
if (CodeCompletionCallbacks) {
6259-
CodeCompletionCallbacks->completeWithoutConstraintType();
6260-
}
6261-
consumeToken(tok::code_complete);
6262-
}
6263-
6264-
// can't suppress whatever is between '~' and ',' or '{'.
6265-
diagnose(Tok, diag::only_suppress_copyable);
6266-
consumeToken();
6267-
}
6268-
6269-
} else if (Tok.isTilde()) {
6270-
// a suppression isn't allowed here, so emit an error eat the token to
6271-
// prevent further parsing errors.
6272-
diagnose(Tok, diag::cannot_suppress_here);
6273-
consumeToken();
6285+
if (!EnabledNoncopyableGenerics) {
6286+
if (parseLegacyTildeCopyable(parseTildeCopyable,
6287+
Status,
6288+
TildeCopyableLoc))
6289+
continue;
62746290
}
62756291

62766292
auto ParsedTypeResult = parseType();

lib/Parse/ParseType.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
158158

159159
// Prevent the use of ~ as prefix for a type. We specially parse them
160160
// in inheritance clauses elsewhere.
161-
if (Tok.isTilde()) {
161+
if (!EnabledNoncopyableGenerics && Tok.isTilde()) {
162162
auto tildeLoc = consumeToken();
163163
diagnose(tildeLoc, diag::cannot_suppress_here)
164164
.fixItRemoveChars(tildeLoc, tildeLoc);
@@ -639,10 +639,19 @@ ParserResult<TypeRepr> Parser::parseType(
639639
new (Context) PackExpansionTypeRepr(repeatLoc, ty.get()));
640640
}
641641

642+
// Parse inverse '~'
643+
SourceLoc tildeLoc;
644+
if (EnabledNoncopyableGenerics && Tok.isTilde())
645+
tildeLoc = consumeToken();
646+
642647
auto ty = parseTypeScalar(MessageID, reason);
643648
if (ty.isNull())
644649
return ty;
645650

651+
// Attach `~` tightly to the parsed type.
652+
if (tildeLoc)
653+
ty = makeParserResult(ty, new(Context) InverseTypeRepr(tildeLoc, ty.get()));
654+
646655
// Parse vararg type 'T...'.
647656
if (Tok.isEllipsis()) {
648657
Tok.setKind(tok::ellipsis);

lib/Parse/Parser.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,9 @@ Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
497497
// Set the token to a sentinel so that we know the lexer isn't primed yet.
498498
// This cannot be tok::unknown, since that is a token the lexer could produce.
499499
Tok.setKind(tok::NUM_TOKENS);
500+
501+
EnabledNoncopyableGenerics =
502+
Context.LangOpts.hasFeature(Feature::NoncopyableGenerics);
500503
}
501504

502505
Parser::~Parser() {

lib/Sema/TypeCheckType.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,8 @@ namespace {
21302130
TypeResolutionOptions options);
21312131
NeverNullType resolveMetatypeType(MetatypeTypeRepr *repr,
21322132
TypeResolutionOptions options);
2133+
NeverNullType resolveInverseType(InverseTypeRepr *repr,
2134+
TypeResolutionOptions options);
21332135
NeverNullType resolveProtocolType(ProtocolTypeRepr *repr,
21342136
TypeResolutionOptions options);
21352137
NeverNullType resolveSILBoxType(SILBoxTypeRepr *repr,
@@ -2479,6 +2481,9 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
24792481
case TypeReprKind::Metatype:
24802482
return resolveMetatypeType(cast<MetatypeTypeRepr>(repr), options);
24812483

2484+
case TypeReprKind::Inverse:
2485+
return resolveInverseType(cast<InverseTypeRepr>(repr), options);
2486+
24822487
case TypeReprKind::Protocol:
24832488
return resolveProtocolType(cast<ProtocolTypeRepr>(repr), options);
24842489

@@ -5035,6 +5040,22 @@ NeverNullType TypeResolver::buildMetatypeType(
50355040
}
50365041
}
50375042

5043+
NeverNullType TypeResolver::resolveInverseType(InverseTypeRepr *repr,
5044+
TypeResolutionOptions options) {
5045+
auto ty = resolveType(repr->getConstraint(), options);
5046+
if (ty->hasError())
5047+
return ErrorType::get(getASTContext());
5048+
5049+
// TODO: more user-friendly verification
5050+
5051+
if (auto protoTy = ty->getAs<ProtocolType>())
5052+
if (auto protoDecl = protoTy->getDecl())
5053+
if (protoDecl->isSpecificProtocol(KnownProtocolKind::Copyable))
5054+
return ty;
5055+
5056+
llvm_unreachable("todo: verification");
5057+
}
5058+
50385059
NeverNullType TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr,
50395060
TypeResolutionOptions options) {
50405061
// The instance type of a metatype is always abstract, not SIL-lowered.
@@ -5248,6 +5269,7 @@ class ExistentialTypeVisitor
52485269
case TypeReprKind::Member:
52495270
case TypeReprKind::Dictionary:
52505271
case TypeReprKind::ImplicitlyUnwrappedOptional:
5272+
case TypeReprKind::Inverse:
52515273
case TypeReprKind::Tuple:
52525274
case TypeReprKind::Fixed:
52535275
case TypeReprKind::Self:

0 commit comments

Comments
 (0)