Skip to content

Commit a6dad00

Browse files
joewillsherDougGregor
authored andcommitted
[SE-0095] Initial parsing implementation for '&' composition syntax
This commit defines the ‘Any’ keyword, implements parsing for composing types with an infix ‘&’, and provides a fixit to convert ‘protocol<>’ - Updated tests & stdlib for new composition syntax - Provide errors when compositions used in inheritance. Any is treated as a contextual keyword. The name ‘Any’ is used emit the empty composition type. We have to stop user declaring top level types spelled ‘Any’ too.
1 parent 5a8271c commit a6dad00

File tree

98 files changed

+570
-491
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+570
-491
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,6 @@ class ASTContext {
443443
/// Retrieve the declaration of Swift.Void.
444444
TypeAliasDecl *getVoidDecl() const;
445445

446-
/// Retrieve the declaration of Swift.Any.
447446
TypeAliasDecl *getAnyDecl() const;
448447

449448
/// Retrieve the declaration of ObjectiveC.ObjCBool.
@@ -568,7 +567,8 @@ class ASTContext {
568567
// Builtin type and simple types that are used frequently.
569568
const CanType TheErrorType; /// This is the ErrorType singleton.
570569
const CanType TheUnresolvedType; /// This is the UnresolvedType singleton.
571-
const CanType TheEmptyTupleType; /// This is "()", aka Void
570+
const CanType TheEmptyTupleType; /// This is '()', aka Void
571+
const CanType TheAnyType; /// This is 'Any', the empty protocol composition
572572
const CanType TheNativeObjectType; /// Builtin.NativeObject
573573
const CanType TheBridgeObjectType; /// Builtin.BridgeObject
574574
const CanType TheUnknownObjectType; /// Builtin.UnknownObject

include/swift/AST/DiagnosticsParse.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,11 @@ ERROR(expected_rangle_protocol,PointsToFirstBadToken,
655655
ERROR(disallowed_protocol_composition,PointsToFirstBadToken,
656656
"protocol composition is neither allowed nor needed here", ())
657657

658+
WARNING(deprecated_protocol_composition,PointsToFirstBadToken,
659+
"'protocol<...>' composition syntax is deprecated; use infix '&' instead", ())
660+
WARNING(deprecated_any_composition,PointsToFirstBadToken,
661+
"'protocol<>' syntax is deprecated; use 'Any' instead", ())
662+
658663
//------------------------------------------------------------------------------
659664
// Pattern parsing diagnostics
660665
//------------------------------------------------------------------------------

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ ERROR(reserved_member_name,none,
517517
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
518518
NOTE(invalid_redecl_prev,none,
519519
"%0 previously declared here", (DeclName))
520+
ERROR(invalid_redecl_any,none,"invalid redeclaration of 'Any'; cannot override type keyword", ())
520521

521522
ERROR(ambiguous_type_base,none,
522523
"%0 is ambiguous for type lookup in this context", (Identifier))
@@ -1387,7 +1388,7 @@ ERROR(circular_protocol_def,none,
13871388
NOTE(protocol_here,none,
13881389
"protocol %0 declared here", (Identifier))
13891390
ERROR(protocol_composition_not_protocol,none,
1390-
"non-protocol type %0 cannot be used within 'protocol<...>'", (Type))
1391+
"non-protocol type %0 cannot be used within a protocol composition", (Type))
13911392
ERROR(objc_protocol_inherits_non_objc_protocol,none,
13921393
"@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type))
13931394

@@ -2683,7 +2684,7 @@ ERROR(objc_convention_invalid,none,
26832684
ERROR(function_type_no_parens,none,
26842685
"single argument function types require parentheses", ())
26852686
NOTE(not_objc_empty_protocol_composition,none,
2686-
"'protocol<>' is not considered '@objc'; use 'AnyObject' instead", ())
2687+
"'Any' is not considered '@objc'; use 'AnyObject' instead", ())
26872688
NOTE(not_objc_protocol,none,
26882689
"protocol %0 is not '@objc'", (Type))
26892690
NOTE(not_objc_empty_tuple,none,

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ IDENTIFIER(RawValue)
6060
IDENTIFIER(Selector)
6161
IDENTIFIER(self)
6262
IDENTIFIER(Self)
63+
IDENTIFIER(Any)
6364
IDENTIFIER(setObject)
6465
IDENTIFIER(simd)
6566
IDENTIFIER(some)

include/swift/AST/TypeRepr.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -613,38 +613,38 @@ class NamedTypeRepr : public TypeRepr {
613613

614614
/// \brief A protocol composite type.
615615
/// \code
616-
/// protocol<Foo, Bar>
616+
/// Foo & Bar
617617
/// \endcode
618618
class ProtocolCompositionTypeRepr : public TypeRepr {
619619
ArrayRef<IdentTypeRepr *> Protocols;
620-
SourceLoc ProtocolLoc;
621-
SourceRange AngleBrackets;
620+
SourceLoc FirstTypeLoc;
621+
SourceRange CompositionRange;
622622

623623
public:
624624
ProtocolCompositionTypeRepr(ArrayRef<IdentTypeRepr *> Protocols,
625-
SourceLoc ProtocolLoc,
626-
SourceRange AngleBrackets)
625+
SourceLoc FirstTypeLoc,
626+
SourceRange CompositionRange)
627627
: TypeRepr(TypeReprKind::ProtocolComposition), Protocols(Protocols),
628-
ProtocolLoc(ProtocolLoc), AngleBrackets(AngleBrackets) {
628+
FirstTypeLoc(FirstTypeLoc), CompositionRange(CompositionRange) {
629629
}
630630

631631
ArrayRef<IdentTypeRepr *> getProtocols() const { return Protocols; }
632-
SourceLoc getProtocolLoc() const { return ProtocolLoc; }
633-
SourceRange getAngleBrackets() const { return AngleBrackets; }
632+
SourceLoc getStartLoc() const { return FirstTypeLoc; }
633+
SourceRange getCompositionRange() const { return CompositionRange; }
634634

635635
static ProtocolCompositionTypeRepr *create(ASTContext &C,
636636
ArrayRef<IdentTypeRepr*> Protocols,
637-
SourceLoc ProtocolLoc,
638-
SourceRange AngleBrackets);
637+
SourceLoc FirstTypeLoc,
638+
SourceRange CompositionRange);
639639

640640
static bool classof(const TypeRepr *T) {
641641
return T->getKind() == TypeReprKind::ProtocolComposition;
642642
}
643643
static bool classof(const ProtocolCompositionTypeRepr *T) { return true; }
644644

645645
private:
646-
SourceLoc getStartLocImpl() const { return ProtocolLoc; }
647-
SourceLoc getEndLocImpl() const { return AngleBrackets.End; }
646+
SourceLoc getStartLocImpl() const { return FirstTypeLoc; }
647+
SourceLoc getEndLocImpl() const { return CompositionRange.End; }
648648
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
649649
friend class TypeRepr;
650650
};

include/swift/Parse/Parser.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,7 @@ class Parser {
414414
}
415415

416416
SourceLoc consumeIdentifier(Identifier *Result = nullptr) {
417-
assert(Tok.is(tok::identifier) || Tok.is(tok::kw_self) ||
418-
Tok.is(tok::kw_Self) || Tok.is(tok::kw_throws));
417+
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self, tok::kw_throws));
419418
if (Result)
420419
*Result = Context.getIdentifier(Tok.getText());
421420
return consumeToken();
@@ -877,9 +876,10 @@ class Parser {
877876
bool parseGenericArguments(SmallVectorImpl<TypeRepr*> &Args,
878877
SourceLoc &LAngleLoc,
879878
SourceLoc &RAngleLoc);
879+
880880
ParserResult<IdentTypeRepr> parseTypeIdentifier();
881+
ParserResult<TypeRepr> parseTypeIdentifierOrTypeComposition();
881882

882-
ParserResult<ProtocolCompositionTypeRepr> parseTypeComposition();
883883
ParserResult<TupleTypeRepr> parseTypeTupleBody();
884884
ParserResult<TypeRepr> parseTypeArray(TypeRepr *Base);
885885

@@ -1082,6 +1082,7 @@ class Parser {
10821082

10831083
bool canParseType();
10841084
bool canParseTypeIdentifier();
1085+
bool canParseTypeIdentifierOrTypeComposition();
10851086
bool canParseTypeComposition();
10861087
bool canParseTypeTupleBody();
10871088
bool canParseTypeAttribute();

lib/AST/ASTContext.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts,
423423
TheUnresolvedType(new (*this, AllocationArena::Permanent)
424424
UnresolvedType(*this)),
425425
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
426+
TheAnyType(ProtocolCompositionType::get(*this, ArrayRef<Type>())),
426427
TheNativeObjectType(new (*this, AllocationArena::Permanent)
427428
BuiltinNativeObjectType(*this)),
428429
TheBridgeObjectType(new (*this, AllocationArena::Permanent)
@@ -801,26 +802,24 @@ TypeAliasDecl *ASTContext::getVoidDecl() const {
801802
return Impl.VoidDecl;
802803
}
803804

804-
805805
TypeAliasDecl *ASTContext::getAnyDecl() const {
806-
if (Impl.AnyDecl) {
807-
return Impl.AnyDecl;
806+
if (Impl.VoidDecl) {
807+
return Impl.VoidDecl;
808808
}
809809

810-
// Go find 'Any' in the Swift module.
810+
// Go find 'Void' in the Swift module.
811811
SmallVector<ValueDecl *, 1> results;
812812
lookupInSwiftModule("Any", results);
813813
for (auto result : results) {
814814
if (auto typeAlias = dyn_cast<TypeAliasDecl>(result)) {
815-
Impl.AnyDecl = typeAlias;
816-
break;
815+
Impl.VoidDecl = typeAlias;
816+
return typeAlias;
817817
}
818818
}
819819

820-
return Impl.AnyDecl;
820+
return Impl.VoidDecl;
821821
}
822822

823-
824823
StructDecl *ASTContext::getObjCBoolDecl() {
825824
if (!Impl.ObjCBoolDecl) {
826825
SmallVector<ValueDecl *, 1> results;

lib/AST/TypeRepr.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ TypeRepr *CloneVisitor::visitProtocolCompositionTypeRepr(
210210
}
211211

212212
return new (Ctx) ProtocolCompositionTypeRepr(protocols,
213-
T->getProtocolLoc(),
214-
T->getAngleBrackets());
213+
T->getStartLoc(),
214+
T->getCompositionRange());
215215
}
216216

217217
TypeRepr *CloneVisitor::visitMetatypeTypeRepr(MetatypeTypeRepr *T) {
@@ -426,10 +426,10 @@ void NamedTypeRepr::printImpl(ASTPrinter &Printer,
426426
ProtocolCompositionTypeRepr *
427427
ProtocolCompositionTypeRepr::create(ASTContext &C,
428428
ArrayRef<IdentTypeRepr *> Protocols,
429-
SourceLoc ProtocolLoc,
430-
SourceRange AngleBrackets) {
429+
SourceLoc FirstTypeLoc,
430+
SourceRange CompositionRange) {
431431
return new (C) ProtocolCompositionTypeRepr(C.AllocateCopy(Protocols),
432-
ProtocolLoc, AngleBrackets);
432+
FirstTypeLoc, CompositionRange);
433433
}
434434

435435
void ProtocolCompositionTypeRepr::printImpl(ASTPrinter &Printer,

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
15991599
if (isVariadic) {
16001600
auto paramTy =
16011601
BoundGenericType::get(SwiftContext.getArrayDecl(), Type(),
1602-
{SwiftContext.getAnyDecl()->getDeclaredType()});
1602+
{SwiftContext.TheAnyType});
16031603
auto name = SwiftContext.getIdentifier("varargs");
16041604
auto param = new (SwiftContext)
16051605
ParamDecl(true, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),

lib/IDE/SyntaxModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
9292
LiteralStartLoc = Optional<SourceLoc>();
9393
continue;
9494
}
95-
95+
9696
switch(Tok.getKind()) {
9797
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
9898
#include "swift/Parse/Tokens.def"

lib/Parse/ParseDecl.cpp

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,35 +2433,42 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
24332433
continue;
24342434
}
24352435

2436-
// Provide a nice error if protocol composition is used.
2437-
if (Tok.is(tok::kw_protocol) && startsWithLess(peekToken())) {
2438-
auto compositionResult = parseTypeComposition();
2439-
Status |= compositionResult;
2440-
if (auto composition = compositionResult.getPtrOrNull()) {
2441-
// Record the protocols inside the composition.
2442-
Inherited.append(composition->getProtocols().begin(),
2443-
composition->getProtocols().end());
2444-
2436+
auto usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
2437+
2438+
auto compositionResult = parseTypeIdentifierOrTypeComposition();
2439+
Status |= compositionResult;
2440+
2441+
if (auto composition = dyn_cast_or_null<ProtocolCompositionTypeRepr>(compositionResult.getPtrOrNull())) {
2442+
// Record the protocols inside the composition.
2443+
Inherited.append(composition->getProtocols().begin(),
2444+
composition->getProtocols().end());
2445+
if (usesDeprecatedCompositionSyntax) {
24452446
// Provide fixits to remove the composition, leaving the types intact.
2446-
auto angleRange = composition->getAngleBrackets();
2447-
diagnose(composition->getProtocolLoc(),
2447+
auto compositionRange = composition->getCompositionRange();
2448+
diagnose(composition->getStartLoc(),
2449+
diag::disallowed_protocol_composition)
2450+
.highlight({composition->getStartLoc(), compositionRange.End})
2451+
.fixItRemove({composition->getStartLoc(), compositionRange.Start})
2452+
.fixItRemove(startsWithGreater(L->getTokenAt(compositionRange.End))
2453+
? compositionRange.End
2454+
: SourceLoc());
2455+
} else {
2456+
diagnose(composition->getStartLoc(),
24482457
diag::disallowed_protocol_composition)
2449-
.fixItRemove({composition->getProtocolLoc(), angleRange.Start})
2450-
.fixItRemove(startsWithGreater(L->getTokenAt(angleRange.End))
2451-
? angleRange.End
2452-
: SourceLoc());
2458+
.highlight(composition->getCompositionRange());
2459+
// TODO: Decompose 'A & B & C' list to 'A, B, C'
24532460
}
2454-
24552461
continue;
2462+
} else {
2463+
// Parse the inherited type (which must be a protocol).
2464+
ParserResult<TypeRepr> Ty = compositionResult;
2465+
Status |= Ty;
2466+
// Record the type.
2467+
if (Ty.isNonNull())
2468+
Inherited.push_back(Ty.get());
24562469
}
24572470

2458-
// Parse the inherited type (which must be a protocol).
2459-
ParserResult<TypeRepr> Ty = parseTypeIdentifier();
2460-
Status |= Ty;
2461-
2462-
// Record the type.
2463-
if (Ty.isNonNull())
2464-
Inherited.push_back(Ty.get());
2471+
24652472

24662473
// Check for a ',', which indicates that there are more protocols coming.
24672474
} while (consumeIf(tok::comma, prevComma));

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,8 +1752,7 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
17521752
// Consume the base name.
17531753
Identifier baseName = Context.getIdentifier(Tok.getText());
17541754
SourceLoc baseNameLoc;
1755-
if (Tok.is(tok::identifier) || Tok.is(tok::kw_Self) ||
1756-
Tok.is(tok::kw_self)) {
1755+
if (Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_self)) {
17571756
baseNameLoc = consumeIdentifier(&baseName);
17581757
} else if (afterDot && Tok.isKeyword()) {
17591758
baseNameLoc = consumeToken();
@@ -1851,9 +1850,7 @@ static bool shouldAddSelfFixit(DeclContext* Current, DeclName Name,
18511850
/// expr-identifier:
18521851
/// unqualified-decl-name generic-args?
18531852
Expr *Parser::parseExprIdentifier() {
1854-
assert(Tok.is(tok::identifier) || Tok.is(tok::kw_self) ||
1855-
Tok.is(tok::kw_Self));
1856-
1853+
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self));
18571854
Token IdentTok = Tok;
18581855

18591856
// Parse the unqualified-decl-name.

lib/Parse/ParseGeneric.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,10 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
6969
if (Tok.is(tok::colon)) {
7070
(void)consumeToken();
7171
ParserResult<TypeRepr> Ty;
72-
if (Tok.getKind() == tok::identifier ||
73-
Tok.getKind() == tok::code_complete) {
74-
Ty = parseTypeIdentifier();
75-
} else if (Tok.getKind() == tok::kw_protocol) {
76-
Ty = parseTypeComposition();
77-
} else if (Tok.getKind() == tok::kw_class) {
72+
73+
if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol)) {
74+
Ty = parseTypeIdentifierOrTypeComposition();
75+
} else if (Tok.is(tok::kw_class)) {
7876
diagnose(Tok, diag::unexpected_class_constraint);
7977
diagnose(Tok, diag::suggest_anyobject, Name)
8078
.fixItReplace(Tok.getLoc(), "AnyObject");
@@ -212,12 +210,8 @@ ParserStatus Parser::parseGenericWhereClause(
212210
SourceLoc ColonLoc = consumeToken();
213211

214212
// Parse the protocol or composition.
215-
ParserResult<TypeRepr> Protocol;
216-
if (Tok.is(tok::kw_protocol)) {
217-
Protocol = parseTypeComposition();
218-
} else {
219-
Protocol = parseTypeIdentifier();
220-
}
213+
ParserResult<TypeRepr> Protocol = parseTypeIdentifierOrTypeComposition();
214+
221215
if (Protocol.isNull()) {
222216
Status.setIsParseError();
223217
if (Protocol.hasCodeCompletion())

0 commit comments

Comments
 (0)