Permalink
Browse files

[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.
  • Loading branch information...
joewillsher authored and DougGregor committed Jun 30, 2016
1 parent 5a8271c commit a6dad0091bbb099b1c44d691204b5861e3332a1d
Showing with 570 additions and 491 deletions.
  1. +2 −2 include/swift/AST/ASTContext.h
  2. +5 −0 include/swift/AST/DiagnosticsParse.def
  3. +3 −2 include/swift/AST/DiagnosticsSema.def
  4. +1 −0 include/swift/AST/KnownIdentifiers.def
  5. +12 −12 include/swift/AST/TypeRepr.h
  6. +4 −3 include/swift/Parse/Parser.h
  7. +7 −8 lib/AST/ASTContext.cpp
  8. +5 −5 lib/AST/TypeRepr.cpp
  9. +1 −1 lib/ClangImporter/ImportType.cpp
  10. +1 −1 lib/IDE/SyntaxModel.cpp
  11. +30 −23 lib/Parse/ParseDecl.cpp
  12. +2 −5 lib/Parse/ParseExpr.cpp
  13. +6 −12 lib/Parse/ParseGeneric.cpp
  14. +136 −59 lib/Parse/ParseType.cpp
  15. +9 −2 lib/Sema/TypeCheckDecl.cpp
  16. +6 −2 lib/Sema/TypeCheckType.cpp
  17. +1 −1 stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
  18. +3 −3 stdlib/public/SDK/Foundation/URL.swift
  19. +5 −5 stdlib/public/core/ClosedRange.swift
  20. +0 −61 stdlib/public/core/Policy.swift
  21. +2 −2 stdlib/public/core/Range.swift.gyb
  22. +1 −1 stdlib/public/core/Slice.swift.gyb
  23. +7 −7 stdlib/public/core/Sort.swift.gyb
  24. +1 −1 test/1_stdlib/ArrayBridge.swift.gyb
  25. +3 −3 test/1_stdlib/PrintDiagnostics.swift
  26. +5 −5 test/1_stdlib/RuntimeObjC.swift
  27. +1 −1 test/1_stdlib/TypeName.swift
  28. +2 −2 test/ClangModules/objc_ir.swift
  29. +1 −1 test/ClangModules/protocol_metatype_object_conversion.swift
  30. +10 −10 test/Constraints/casts.swift
  31. +1 −1 test/Constraints/dynamic_lookup.swift
  32. +5 −5 test/Constraints/existential_metatypes.swift
  33. +3 −3 test/Constraints/generic_protocol_witness.swift
  34. +4 −4 test/Constraints/protocols.swift
  35. +2 −2 test/Constraints/tuple.swift
  36. +1 −1 test/DebugInfo/pcomp.swift
  37. +2 −2 test/DebugInfo/protocol-sugar.swift
  38. +1 −1 test/DebugInfo/protocol.swift
  39. +1 −1 test/Generics/existential_restrictions.swift
  40. +1 −1 test/Generics/function_decls.swift
  41. +2 −2 test/Generics/function_defs.swift
  42. +1 −1 test/Generics/inheritance.swift
  43. +1 −1 test/Generics/invalid.swift
  44. +1 −1 test/IDE/Inputs/mock-sdk/Foo.printed.txt
  45. +1 −1 test/IDE/complete_enum_elements.swift
  46. +1 −1 test/IDE/complete_from_stdlib.swift
  47. +2 −2 test/IDE/complete_from_swift_module.swift
  48. +3 −3 test/IDE/complete_pattern.swift
  49. +10 −10 test/IDE/complete_type.swift
  50. 0 test/IDE/complete_type_any.swift.tmp.types.txt
  51. +6 −6 test/IDE/complete_value_expr.swift
  52. +7 −0 test/IDE/int.complete_type_any.swift.tmp.types.txt
  53. +4 −4 test/IDE/print_ast_tc_decls.swift
  54. +1 −1 test/IDE/print_types.swift
  55. +1 −1 test/IRGen/abitypes.swift
  56. +1 −1 test/IRGen/associated_type_witness.swift
  57. +2 −2 test/IRGen/builtins.swift
  58. +7 −7 test/IRGen/class_bounded_generics.swift
  59. +3 −3 test/IRGen/generic_casts.swift
  60. +1 −1 test/IRGen/objc_property_attrs.swift
  61. +2 −2 test/IRGen/objc_protocols.swift
  62. +2 −2 test/IRGen/objc_type_encoding.swift
  63. +2 −2 test/IRGen/protocol_metadata.swift
  64. +4 −4 test/IRGen/type_layout_reference_storage.swift
  65. +8 −8 test/IRGen/type_layout_reference_storage_objc.swift
  66. +6 −6 test/Interpreter/generic_casts.swift
  67. +2 −2 test/Interpreter/protocol_lookup.swift
  68. +1 −1 test/Interpreter/protocols.swift
  69. +1 −1 test/Parse/generic_disambiguation.swift
  70. +1 −1 test/Parse/matching_patterns.swift
  71. +1 −1 test/Parse/metatype_object_conversion.swift
  72. +28 −8 test/Parse/recovery.swift
  73. +1 −1 test/PrintAsObjC/local-types.swift
  74. +3 −3 test/PrintAsObjC/protocols.swift
  75. +8 −8 test/Reflection/Inputs/TypeLowering.swift
  76. +2 −2 test/RemoteAST/nominal_types.swift
  77. +2 −2 test/SILGen/boxed_existentials.swift
  78. +6 −6 test/SILGen/builtins.swift
  79. +1 −1 test/SILGen/c_function_pointers.swift
  80. +4 −4 test/SILGen/class_bound_protocols.swift
  81. +1 −1 test/SILGen/existential_erasure.swift
  82. +1 −1 test/SILGen/existential_metatypes.swift
  83. +2 −2 test/SILGen/generic_signatures.swift
  84. +3 −3 test/SILGen/mangling.swift
  85. +6 −6 test/SILGen/metatypes.swift
  86. +1 −1 test/SILGen/objc_protocols.swift
  87. +2 −2 test/SILOptimizer/spec_conf2.swift
  88. +1 −1 test/Serialization/Inputs/def_class.swift
  89. +1 −1 test/Serialization/Inputs/def_struct.swift
  90. +55 −55 test/attr/attr_objc.swift
  91. +9 −6 test/decl/inherit/inherit.swift
  92. +2 −2 test/decl/overload.swift
  93. +1 −1 test/expr/cast/as_coerce.swift
  94. +8 −6 test/expr/expressions.swift
  95. +2 −2 test/expr/postfix/call/construction.swift
  96. +1 −1 test/stmt/statements.swift
  97. +24 −18 test/type/protocol_composition.swift
  98. +17 −8 test/type/protocol_types.swift
@@ -443,7 +443,6 @@ class ASTContext {
/// Retrieve the declaration of Swift.Void.
TypeAliasDecl *getVoidDecl() const;
/// Retrieve the declaration of Swift.Any.
TypeAliasDecl *getAnyDecl() const;
/// Retrieve the declaration of ObjectiveC.ObjCBool.
@@ -568,7 +567,8 @@ class ASTContext {
// Builtin type and simple types that are used frequently.
const CanType TheErrorType; /// This is the ErrorType singleton.
const CanType TheUnresolvedType; /// This is the UnresolvedType singleton.
const CanType TheEmptyTupleType; /// This is "()", aka Void
const CanType TheEmptyTupleType; /// This is '()', aka Void
const CanType TheAnyType; /// This is 'Any', the empty protocol composition
const CanType TheNativeObjectType; /// Builtin.NativeObject
const CanType TheBridgeObjectType; /// Builtin.BridgeObject
const CanType TheUnknownObjectType; /// Builtin.UnknownObject
@@ -655,6 +655,11 @@ ERROR(expected_rangle_protocol,PointsToFirstBadToken,
ERROR(disallowed_protocol_composition,PointsToFirstBadToken,
"protocol composition is neither allowed nor needed here", ())
WARNING(deprecated_protocol_composition,PointsToFirstBadToken,
"'protocol<...>' composition syntax is deprecated; use infix '&' instead", ())
WARNING(deprecated_any_composition,PointsToFirstBadToken,
"'protocol<>' syntax is deprecated; use 'Any' instead", ())
//------------------------------------------------------------------------------
// Pattern parsing diagnostics
//------------------------------------------------------------------------------
@@ -517,6 +517,7 @@ ERROR(reserved_member_name,none,
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
NOTE(invalid_redecl_prev,none,
"%0 previously declared here", (DeclName))
ERROR(invalid_redecl_any,none,"invalid redeclaration of 'Any'; cannot override type keyword", ())
ERROR(ambiguous_type_base,none,
"%0 is ambiguous for type lookup in this context", (Identifier))
@@ -1387,7 +1388,7 @@ ERROR(circular_protocol_def,none,
NOTE(protocol_here,none,
"protocol %0 declared here", (Identifier))
ERROR(protocol_composition_not_protocol,none,
"non-protocol type %0 cannot be used within 'protocol<...>'", (Type))
"non-protocol type %0 cannot be used within a protocol composition", (Type))
ERROR(objc_protocol_inherits_non_objc_protocol,none,
"@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type))
@@ -2683,7 +2684,7 @@ ERROR(objc_convention_invalid,none,
ERROR(function_type_no_parens,none,
"single argument function types require parentheses", ())
NOTE(not_objc_empty_protocol_composition,none,
"'protocol<>' is not considered '@objc'; use 'AnyObject' instead", ())
"'Any' is not considered '@objc'; use 'AnyObject' instead", ())
NOTE(not_objc_protocol,none,
"protocol %0 is not '@objc'", (Type))
NOTE(not_objc_empty_tuple,none,
@@ -60,6 +60,7 @@ IDENTIFIER(RawValue)
IDENTIFIER(Selector)
IDENTIFIER(self)
IDENTIFIER(Self)
IDENTIFIER(Any)
IDENTIFIER(setObject)
IDENTIFIER(simd)
IDENTIFIER(some)
@@ -613,38 +613,38 @@ class NamedTypeRepr : public TypeRepr {
/// \brief A protocol composite type.
/// \code
/// protocol<Foo, Bar>
/// Foo & Bar
/// \endcode
class ProtocolCompositionTypeRepr : public TypeRepr {
ArrayRef<IdentTypeRepr *> Protocols;
SourceLoc ProtocolLoc;
SourceRange AngleBrackets;
SourceLoc FirstTypeLoc;
SourceRange CompositionRange;
public:
ProtocolCompositionTypeRepr(ArrayRef<IdentTypeRepr *> Protocols,
SourceLoc ProtocolLoc,
SourceRange AngleBrackets)
SourceLoc FirstTypeLoc,
SourceRange CompositionRange)
: TypeRepr(TypeReprKind::ProtocolComposition), Protocols(Protocols),
ProtocolLoc(ProtocolLoc), AngleBrackets(AngleBrackets) {
FirstTypeLoc(FirstTypeLoc), CompositionRange(CompositionRange) {
}
ArrayRef<IdentTypeRepr *> getProtocols() const { return Protocols; }
SourceLoc getProtocolLoc() const { return ProtocolLoc; }
SourceRange getAngleBrackets() const { return AngleBrackets; }
SourceLoc getStartLoc() const { return FirstTypeLoc; }
SourceRange getCompositionRange() const { return CompositionRange; }
static ProtocolCompositionTypeRepr *create(ASTContext &C,
ArrayRef<IdentTypeRepr*> Protocols,
SourceLoc ProtocolLoc,
SourceRange AngleBrackets);
SourceLoc FirstTypeLoc,
SourceRange CompositionRange);
static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::ProtocolComposition;
}
static bool classof(const ProtocolCompositionTypeRepr *T) { return true; }
private:
SourceLoc getStartLocImpl() const { return ProtocolLoc; }
SourceLoc getEndLocImpl() const { return AngleBrackets.End; }
SourceLoc getStartLocImpl() const { return FirstTypeLoc; }
SourceLoc getEndLocImpl() const { return CompositionRange.End; }
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
friend class TypeRepr;
};
@@ -414,8 +414,7 @@ class Parser {
}
SourceLoc consumeIdentifier(Identifier *Result = nullptr) {
assert(Tok.is(tok::identifier) || Tok.is(tok::kw_self) ||
Tok.is(tok::kw_Self) || Tok.is(tok::kw_throws));
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self, tok::kw_throws));
if (Result)
*Result = Context.getIdentifier(Tok.getText());
return consumeToken();
@@ -877,9 +876,10 @@ class Parser {
bool parseGenericArguments(SmallVectorImpl<TypeRepr*> &Args,
SourceLoc &LAngleLoc,
SourceLoc &RAngleLoc);
ParserResult<IdentTypeRepr> parseTypeIdentifier();
ParserResult<TypeRepr> parseTypeIdentifierOrTypeComposition();
ParserResult<ProtocolCompositionTypeRepr> parseTypeComposition();
ParserResult<TupleTypeRepr> parseTypeTupleBody();
ParserResult<TypeRepr> parseTypeArray(TypeRepr *Base);
@@ -1082,6 +1082,7 @@ class Parser {
bool canParseType();
bool canParseTypeIdentifier();
bool canParseTypeIdentifierOrTypeComposition();
bool canParseTypeComposition();
bool canParseTypeTupleBody();
bool canParseTypeAttribute();
View
@@ -423,6 +423,7 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts,
TheUnresolvedType(new (*this, AllocationArena::Permanent)
UnresolvedType(*this)),
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
TheAnyType(ProtocolCompositionType::get(*this, ArrayRef<Type>())),
TheNativeObjectType(new (*this, AllocationArena::Permanent)
BuiltinNativeObjectType(*this)),
TheBridgeObjectType(new (*this, AllocationArena::Permanent)
@@ -801,26 +802,24 @@ TypeAliasDecl *ASTContext::getVoidDecl() const {
return Impl.VoidDecl;
}
TypeAliasDecl *ASTContext::getAnyDecl() const {
if (Impl.AnyDecl) {
return Impl.AnyDecl;
if (Impl.VoidDecl) {
return Impl.VoidDecl;
}
// Go find 'Any' in the Swift module.
// Go find 'Void' in the Swift module.
SmallVector<ValueDecl *, 1> results;
lookupInSwiftModule("Any", results);
for (auto result : results) {
if (auto typeAlias = dyn_cast<TypeAliasDecl>(result)) {
Impl.AnyDecl = typeAlias;
break;
Impl.VoidDecl = typeAlias;
return typeAlias;
}
}
return Impl.AnyDecl;
return Impl.VoidDecl;
}
StructDecl *ASTContext::getObjCBoolDecl() {
if (!Impl.ObjCBoolDecl) {
SmallVector<ValueDecl *, 1> results;
View
@@ -210,8 +210,8 @@ TypeRepr *CloneVisitor::visitProtocolCompositionTypeRepr(
}
return new (Ctx) ProtocolCompositionTypeRepr(protocols,
T->getProtocolLoc(),
T->getAngleBrackets());
T->getStartLoc(),
T->getCompositionRange());
}
TypeRepr *CloneVisitor::visitMetatypeTypeRepr(MetatypeTypeRepr *T) {
@@ -426,10 +426,10 @@ void NamedTypeRepr::printImpl(ASTPrinter &Printer,
ProtocolCompositionTypeRepr *
ProtocolCompositionTypeRepr::create(ASTContext &C,
ArrayRef<IdentTypeRepr *> Protocols,
SourceLoc ProtocolLoc,
SourceRange AngleBrackets) {
SourceLoc FirstTypeLoc,
SourceRange CompositionRange) {
return new (C) ProtocolCompositionTypeRepr(C.AllocateCopy(Protocols),
ProtocolLoc, AngleBrackets);
FirstTypeLoc, CompositionRange);
}
void ProtocolCompositionTypeRepr::printImpl(ASTPrinter &Printer,
@@ -1599,7 +1599,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
if (isVariadic) {
auto paramTy =
BoundGenericType::get(SwiftContext.getArrayDecl(), Type(),
{SwiftContext.getAnyDecl()->getDeclaredType()});
{SwiftContext.TheAnyType});
auto name = SwiftContext.getIdentifier("varargs");
auto param = new (SwiftContext)
ParamDecl(true, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
View
@@ -92,7 +92,7 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
LiteralStartLoc = Optional<SourceLoc>();
continue;
}
switch(Tok.getKind()) {
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
#include "swift/Parse/Tokens.def"
View
@@ -2433,35 +2433,42 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
continue;
}
// Provide a nice error if protocol composition is used.
if (Tok.is(tok::kw_protocol) && startsWithLess(peekToken())) {
auto compositionResult = parseTypeComposition();
Status |= compositionResult;
if (auto composition = compositionResult.getPtrOrNull()) {
// Record the protocols inside the composition.
Inherited.append(composition->getProtocols().begin(),
composition->getProtocols().end());
auto usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
auto compositionResult = parseTypeIdentifierOrTypeComposition();
Status |= compositionResult;
if (auto composition = dyn_cast_or_null<ProtocolCompositionTypeRepr>(compositionResult.getPtrOrNull())) {
// Record the protocols inside the composition.
Inherited.append(composition->getProtocols().begin(),
composition->getProtocols().end());
if (usesDeprecatedCompositionSyntax) {
// Provide fixits to remove the composition, leaving the types intact.
auto angleRange = composition->getAngleBrackets();
diagnose(composition->getProtocolLoc(),
auto compositionRange = composition->getCompositionRange();
diagnose(composition->getStartLoc(),
diag::disallowed_protocol_composition)
.highlight({composition->getStartLoc(), compositionRange.End})
.fixItRemove({composition->getStartLoc(), compositionRange.Start})
.fixItRemove(startsWithGreater(L->getTokenAt(compositionRange.End))
? compositionRange.End
: SourceLoc());
} else {
diagnose(composition->getStartLoc(),
diag::disallowed_protocol_composition)
.fixItRemove({composition->getProtocolLoc(), angleRange.Start})
.fixItRemove(startsWithGreater(L->getTokenAt(angleRange.End))
? angleRange.End
: SourceLoc());
.highlight(composition->getCompositionRange());
// TODO: Decompose 'A & B & C' list to 'A, B, C'
}
continue;
} else {
// Parse the inherited type (which must be a protocol).
ParserResult<TypeRepr> Ty = compositionResult;
Status |= Ty;
// Record the type.
if (Ty.isNonNull())
Inherited.push_back(Ty.get());
}
// Parse the inherited type (which must be a protocol).
ParserResult<TypeRepr> Ty = parseTypeIdentifier();
Status |= Ty;
// Record the type.
if (Ty.isNonNull())
Inherited.push_back(Ty.get());
// Check for a ',', which indicates that there are more protocols coming.
} while (consumeIf(tok::comma, prevComma));
View
@@ -1752,8 +1752,7 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
// Consume the base name.
Identifier baseName = Context.getIdentifier(Tok.getText());
SourceLoc baseNameLoc;
if (Tok.is(tok::identifier) || Tok.is(tok::kw_Self) ||
Tok.is(tok::kw_self)) {
if (Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_self)) {
baseNameLoc = consumeIdentifier(&baseName);
} else if (afterDot && Tok.isKeyword()) {
baseNameLoc = consumeToken();
@@ -1851,9 +1850,7 @@ static bool shouldAddSelfFixit(DeclContext* Current, DeclName Name,
/// expr-identifier:
/// unqualified-decl-name generic-args?
Expr *Parser::parseExprIdentifier() {
assert(Tok.is(tok::identifier) || Tok.is(tok::kw_self) ||
Tok.is(tok::kw_Self));
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self));
Token IdentTok = Tok;
// Parse the unqualified-decl-name.
View
@@ -69,12 +69,10 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
if (Tok.is(tok::colon)) {
(void)consumeToken();
ParserResult<TypeRepr> Ty;
if (Tok.getKind() == tok::identifier ||
Tok.getKind() == tok::code_complete) {
Ty = parseTypeIdentifier();
} else if (Tok.getKind() == tok::kw_protocol) {
Ty = parseTypeComposition();
} else if (Tok.getKind() == tok::kw_class) {
if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol)) {
Ty = parseTypeIdentifierOrTypeComposition();
} else if (Tok.is(tok::kw_class)) {
diagnose(Tok, diag::unexpected_class_constraint);
diagnose(Tok, diag::suggest_anyobject, Name)
.fixItReplace(Tok.getLoc(), "AnyObject");
@@ -212,12 +210,8 @@ ParserStatus Parser::parseGenericWhereClause(
SourceLoc ColonLoc = consumeToken();
// Parse the protocol or composition.
ParserResult<TypeRepr> Protocol;
if (Tok.is(tok::kw_protocol)) {
Protocol = parseTypeComposition();
} else {
Protocol = parseTypeIdentifier();
}
ParserResult<TypeRepr> Protocol = parseTypeIdentifierOrTypeComposition();
if (Protocol.isNull()) {
Status.setIsParseError();
if (Protocol.hasCodeCompletion())
Oops, something went wrong.

0 comments on commit a6dad00

Please sign in to comment.