Merge pull request #23685 from DougGregor/custom-attributes-parse
diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def
new file mode 100644
index 0000000..3a19b31
--- /dev/null
+++ b/include/swift/AST/ASTTypeIDZone.def
@@ -0,0 +1,19 @@
+//===--- ASTTypeIDZone.def - Define the AST TypeID Zone ---------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This definition file describes the types in the "AST" TypeID zone,
+// for use with the TypeID template.
+//
+//===----------------------------------------------------------------------===//
+SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl)
+SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
+SWIFT_TYPEID(PropertyBehaviorTypeInfo)
diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h
new file mode 100644
index 0000000..e13342c
--- /dev/null
+++ b/include/swift/AST/ASTTypeIDs.h
@@ -0,0 +1,36 @@
+//===--- ASTTypeIDs.h - AST Type Ids ----------------------------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2019 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines TypeID support for AST types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_AST_ASTTYPEIDS_H
+#define SWIFT_AST_ASTTYPEIDS_H
+
+#include "swift/Basic/TypeID.h"
+namespace swift {
+
+class NominalTypeDecl;
+struct PropertyBehaviorTypeInfo;
+class VarDecl;
+
+#define SWIFT_AST_TYPEID_ZONE 1
+
+// Define the AST type zone (zone 1)
+#define SWIFT_TYPEID_ZONE SWIFT_AST_TYPEID_ZONE
+#define SWIFT_TYPEID_HEADER "swift/AST/ASTTypeIDZone.def"
+#include "swift/Basic/DefineTypeIDZone.h"
+
+} // end namespace swift
+
+#endif /* SWIFT_AST_ASTTYPEIDS_H */
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index 28aef75..f9f0be8 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -393,6 +393,9 @@
SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly,
OnImport | UserInaccessible,
84)
+DECL_ATTR(_custom, Custom,
+ OnAnyDecl | UserInaccessible,
+ 85)
#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h
index d6b3598..c9e5324 100644
--- a/include/swift/AST/Attr.h
+++ b/include/swift/AST/Attr.h
@@ -32,6 +32,7 @@
#include "swift/AST/Ownership.h"
#include "swift/AST/PlatformKind.h"
#include "swift/AST/Requirement.h"
+#include "swift/AST/TrailingCallArguments.h"
#include "swift/AST/TypeLoc.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -49,6 +50,7 @@
class ClassDecl;
class GenericFunctionType;
class LazyConformanceLoader;
+class PatternBindingInitializer;
class TrailingWhereClause;
/// TypeAttributes - These are attributes that may be applied to types.
@@ -1408,6 +1410,54 @@
}
};
+/// Defines a custom attribute.
+class CustomAttr final : public DeclAttribute,
+ public TrailingCallArguments<CustomAttr> {
+ TypeLoc type;
+ Expr *arg;
+ PatternBindingInitializer *initContext;
+
+ unsigned hasArgLabelLocs : 1;
+ unsigned numArgLabels : 16;
+
+ CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type,
+ PatternBindingInitializer *initContext, Expr *arg,
+ ArrayRef<Identifier> argLabels, ArrayRef<SourceLoc> argLabelLocs,
+ bool implicit);
+
+public:
+ static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
+ bool implicit = false) {
+ return create(ctx, atLoc, type, false, nullptr, SourceLoc(), { }, { }, { },
+ SourceLoc(), implicit);
+ }
+
+ static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
+ bool hasInitializer,
+ PatternBindingInitializer *initContext,
+ SourceLoc lParenLoc,
+ ArrayRef<Expr *> args,
+ ArrayRef<Identifier> argLabels,
+ ArrayRef<SourceLoc> argLabelLocs,
+ SourceLoc rParenLoc,
+ bool implicit = false);
+
+ unsigned getNumArguments() const { return numArgLabels; }
+ bool hasArgumentLabelLocs() const { return hasArgLabelLocs; }
+
+ TypeLoc &getTypeLoc() { return type; }
+ const TypeLoc &getTypeLoc() const { return type; }
+
+ Expr *getArg() const { return arg; }
+ void setArg(Expr *newArg) { arg = newArg; }
+
+ PatternBindingInitializer *getInitContext() const { return initContext; }
+
+ static bool classof(const DeclAttribute *DA) {
+ return DA->getKind() == DAK_Custom;
+ }
+};
+
/// Attributes that may be applied to declarations.
class DeclAttributes {
/// Linked list of declaration attributes.
@@ -1584,6 +1634,8 @@
SourceLoc getStartLoc(bool forModifiers = false) const;
};
+void simple_display(llvm::raw_ostream &out, const DeclAttribute *attr);
+
} // end namespace swift
#endif
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 87ea871..69815cb 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1104,6 +1104,9 @@
ERROR(attribute_requires_single_argument,none,
"'%0' requires a function with one argument", (StringRef))
+ERROR(nominal_type_not_attribute,none,
+ "%0 %1 cannot be used as an attribute", (DescriptiveDeclKind, DeclName))
+
ERROR(mutating_invalid_global_scope,none, "%0 is only valid on methods",
(SelfAccessKind))
ERROR(mutating_invalid_classes,none, "%0 isn't valid on methods in "
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index c9804f2..ec3935a 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -22,6 +22,7 @@
#include "swift/AST/DeclNameLoc.h"
#include "swift/AST/FunctionRefKind.h"
#include "swift/AST/ProtocolConformanceRef.h"
+#include "swift/AST/TrailingCallArguments.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeRepr.h"
@@ -570,105 +571,6 @@
}
};
-/// Helper class to capture trailing call argument labels and related
-/// information, for expression nodes that involve argument labels, trailing
-/// closures, etc.
-template<typename Derived>
-class TrailingCallArguments
- : private llvm::TrailingObjects<Derived, Identifier, SourceLoc> {
- // We need to friend TrailingObjects twice here to work around an MSVC bug.
- // If we have two functions of the same name with the parameter
- // typename TrailingObjectsIdentifier::template OverloadToken<T> where T is
- // different for each function, then MSVC reports a "member function already
- // defined or declared" error, which is incorrect.
- using TrailingObjectsIdentifier = llvm::TrailingObjects<Derived, Identifier>;
- friend TrailingObjectsIdentifier;
-
- using TrailingObjects = llvm::TrailingObjects<Derived, Identifier, SourceLoc>;
- friend TrailingObjects;
-
- Derived &asDerived() {
- return *static_cast<Derived *>(this);
- }
-
- const Derived &asDerived() const {
- return *static_cast<const Derived *>(this);
- }
-
- size_t numTrailingObjects(
- typename TrailingObjectsIdentifier::template OverloadToken<Identifier>)
- const {
- return asDerived().getNumArguments();
- }
-
- size_t numTrailingObjects(
- typename TrailingObjectsIdentifier::template OverloadToken<SourceLoc>)
- const {
- return asDerived().hasArgumentLabelLocs() ? asDerived().getNumArguments()
- : 0;
- }
-
- /// Retrieve the buffer containing the argument labels.
- MutableArrayRef<Identifier> getArgumentLabelsBuffer() {
- return { this->template getTrailingObjects<Identifier>(),
- asDerived().getNumArguments() };
- }
-
- /// Retrieve the buffer containing the argument label locations.
- MutableArrayRef<SourceLoc> getArgumentLabelLocsBuffer() {
- if (!asDerived().hasArgumentLabelLocs())
- return { };
-
- return { this->template getTrailingObjects<SourceLoc>(),
- asDerived().getNumArguments() };
- }
-
-protected:
- /// Determine the total size to allocate.
- static size_t totalSizeToAlloc(ArrayRef<Identifier> argLabels,
- ArrayRef<SourceLoc> argLabelLocs,
- bool hasTrailingClosure) {
- return TrailingObjects::template totalSizeToAlloc<Identifier, SourceLoc>(
- argLabels.size(), argLabelLocs.size());
- }
-
- /// Initialize the actual call arguments.
- void initializeCallArguments(ArrayRef<Identifier> argLabels,
- ArrayRef<SourceLoc> argLabelLocs,
- bool hasTrailingClosure) {
- if (!argLabels.empty()) {
- std::uninitialized_copy(argLabels.begin(), argLabels.end(),
- this->template getTrailingObjects<Identifier>());
- }
-
- if (!argLabelLocs.empty())
- std::uninitialized_copy(argLabelLocs.begin(), argLabelLocs.end(),
- this->template getTrailingObjects<SourceLoc>());
- }
-
-public:
- /// Retrieve the argument labels provided at the call site.
- ArrayRef<Identifier> getArgumentLabels() const {
- return { this->template getTrailingObjects<Identifier>(),
- asDerived().getNumArguments() };
- }
-
- /// Retrieve the buffer containing the argument label locations.
- ArrayRef<SourceLoc> getArgumentLabelLocs() const {
- if (!asDerived().hasArgumentLabelLocs())
- return { };
-
- return { this->template getTrailingObjects<SourceLoc>(),
- asDerived().getNumArguments() };
- }
-
- /// Retrieve the location of the ith argument label.
- SourceLoc getArgumentLabelLoc(unsigned i) const {
- auto locs = getArgumentLabelLocs();
- return i < locs.size() ? locs[i] : SourceLoc();
- }
-};
-
/// ErrorExpr - Represents a semantically erroneous subexpression in the AST,
/// typically this will have an ErrorType.
class ErrorExpr : public Expr {
@@ -5448,7 +5350,27 @@
}
#undef SWIFT_FORWARD_SOURCE_LOCS_TO
-
+
+/// Pack the argument information into a single argument, to match the
+/// representation expected by the AST.
+///
+/// \param argLabels The argument labels, which might be updated by this
+/// function.
+///
+/// \param argLabelLocs The argument label locations, which might be updated by
+/// this function.
+Expr *packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc,
+ ArrayRef<Expr *> args,
+ ArrayRef<Identifier> &argLabels,
+ ArrayRef<SourceLoc> &argLabelLocs,
+ SourceLoc rParenLoc,
+ Expr *trailingClosure, bool implicit,
+ SmallVectorImpl<Identifier> &argLabelsScratch,
+ SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
+ llvm::function_ref<Type(const Expr *)> getType =
+ [](const Expr *E) -> Type {
+ return E->getType();
+ });
} // end namespace swift
#endif
diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h
index 5f7177a..1c68cbd 100644
--- a/include/swift/AST/NameLookupRequests.h
+++ b/include/swift/AST/NameLookupRequests.h
@@ -17,6 +17,7 @@
#define SWIFT_NAME_LOOKUP_REQUESTS_H
#include "swift/AST/SimpleRequest.h"
+#include "swift/AST/ASTTypeIDs.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/TinyPtrVector.h"
@@ -238,6 +239,33 @@
void noteCycleStep(DiagnosticEngine &diags) const;
};
+/// Request the nominal type declaration to which the given custom attribute
+/// refers.
+class CustomAttrNominalRequest :
+ public SimpleRequest<CustomAttrNominalRequest,
+ CacheKind::Cached,
+ NominalTypeDecl *,
+ CustomAttr *,
+ DeclContext *> {
+public:
+ using SimpleRequest::SimpleRequest;
+
+private:
+ friend SimpleRequest;
+
+ // Evaluation.
+ llvm::Expected<NominalTypeDecl *>
+ evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const;
+
+public:
+ // Caching
+ bool isCached() const { return true; }
+
+ // Cycle handling
+ void diagnoseCycle(DiagnosticEngine &diags) const;
+ void noteCycleStep(DiagnosticEngine &diags) const;
+};
+
/// The zone number for name-lookup requests.
#define SWIFT_NAME_LOOKUP_REQUESTS_TYPEID_ZONE 9
diff --git a/include/swift/AST/NameLookupTypeIDZone.def b/include/swift/AST/NameLookupTypeIDZone.def
index d00cfbc..1d380d2 100644
--- a/include/swift/AST/NameLookupTypeIDZone.def
+++ b/include/swift/AST/NameLookupTypeIDZone.def
@@ -20,3 +20,4 @@
SWIFT_TYPEID(ExtendedNominalRequest)
SWIFT_TYPEID(SelfBoundsFromWhereClauseRequest)
SWIFT_TYPEID(TypeDeclsFromWhereClauseRequest)
+SWIFT_TYPEID(CustomAttrNominalRequest)
diff --git a/include/swift/AST/TrailingCallArguments.h b/include/swift/AST/TrailingCallArguments.h
new file mode 100644
index 0000000..5279421
--- /dev/null
+++ b/include/swift/AST/TrailingCallArguments.h
@@ -0,0 +1,130 @@
+//===--- TrailingCallArguments.h - Trailing Call Arguments ------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TrailingCallArguments template, which is used
+// to tail-allocate the names and source locations of argument labels in a
+// call.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_AST_TRAILINGCALLARGUMENTS_H
+#define SWIFT_AST_TRAILINGCALLARGUMENTS_H
+
+#include "swift/AST/Identifier.h"
+#include "swift/Basic/SourceLoc.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/TrailingObjects.h"
+
+namespace swift {
+
+/// Helper class to capture trailing call argument labels and related
+/// information, for expression nodes that involve argument labels, trailing
+/// closures, etc.
+template<typename Derived>
+class TrailingCallArguments
+ : private llvm::TrailingObjects<Derived, Identifier, SourceLoc> {
+ // We need to friend TrailingObjects twice here to work around an MSVC bug.
+ // If we have two functions of the same name with the parameter
+ // typename TrailingObjectsIdentifier::template OverloadToken<T> where T is
+ // different for each function, then MSVC reports a "member function already
+ // defined or declared" error, which is incorrect.
+ using TrailingObjectsIdentifier = llvm::TrailingObjects<Derived, Identifier>;
+ friend TrailingObjectsIdentifier;
+
+ using TrailingObjects = llvm::TrailingObjects<Derived, Identifier, SourceLoc>;
+ friend TrailingObjects;
+
+ Derived &asDerived() {
+ return *static_cast<Derived *>(this);
+ }
+
+ const Derived &asDerived() const {
+ return *static_cast<const Derived *>(this);
+ }
+
+ size_t numTrailingObjects(
+ typename TrailingObjectsIdentifier::template OverloadToken<Identifier>)
+ const {
+ return asDerived().getNumArguments();
+ }
+
+ size_t numTrailingObjects(
+ typename TrailingObjectsIdentifier::template OverloadToken<SourceLoc>)
+ const {
+ return asDerived().hasArgumentLabelLocs() ? asDerived().getNumArguments()
+ : 0;
+ }
+
+ /// Retrieve the buffer containing the argument labels.
+ MutableArrayRef<Identifier> getArgumentLabelsBuffer() {
+ return { this->template getTrailingObjects<Identifier>(),
+ asDerived().getNumArguments() };
+ }
+
+ /// Retrieve the buffer containing the argument label locations.
+ MutableArrayRef<SourceLoc> getArgumentLabelLocsBuffer() {
+ if (!asDerived().hasArgumentLabelLocs())
+ return { };
+
+ return { this->template getTrailingObjects<SourceLoc>(),
+ asDerived().getNumArguments() };
+ }
+
+protected:
+ /// Determine the total size to allocate.
+ static size_t totalSizeToAlloc(ArrayRef<Identifier> argLabels,
+ ArrayRef<SourceLoc> argLabelLocs,
+ bool hasTrailingClosure) {
+ return TrailingObjects::template totalSizeToAlloc<Identifier, SourceLoc>(
+ argLabels.size(), argLabelLocs.size());
+ }
+
+ /// Initialize the actual call arguments.
+ void initializeCallArguments(ArrayRef<Identifier> argLabels,
+ ArrayRef<SourceLoc> argLabelLocs,
+ bool hasTrailingClosure) {
+ if (!argLabels.empty()) {
+ std::uninitialized_copy(argLabels.begin(), argLabels.end(),
+ this->template getTrailingObjects<Identifier>());
+ }
+
+ if (!argLabelLocs.empty())
+ std::uninitialized_copy(argLabelLocs.begin(), argLabelLocs.end(),
+ this->template getTrailingObjects<SourceLoc>());
+ }
+
+public:
+ /// Retrieve the argument labels provided at the call site.
+ ArrayRef<Identifier> getArgumentLabels() const {
+ return { this->template getTrailingObjects<Identifier>(),
+ asDerived().getNumArguments() };
+ }
+
+ /// Retrieve the buffer containing the argument label locations.
+ ArrayRef<SourceLoc> getArgumentLabelLocs() const {
+ if (!asDerived().hasArgumentLabelLocs())
+ return { };
+
+ return { this->template getTrailingObjects<SourceLoc>(),
+ asDerived().getNumArguments() };
+ }
+
+ /// Retrieve the location of the ith argument label.
+ SourceLoc getArgumentLabelLoc(unsigned i) const {
+ auto locs = getArgumentLabelLocs();
+ return i < locs.size() ? locs[i] : SourceLoc();
+ }
+};
+
+} // end namespace swift
+
+#endif /* SWIFT_AST_TRAILINGCALLARGUMENTS_H */
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index d8d04cc..9eee6c0 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -52,7 +52,7 @@
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t SWIFTMODULE_VERSION_MINOR = 480; // Last change: import control
+const uint16_t SWIFTMODULE_VERSION_MINOR = 481; // Last change: custom attrs
using DeclIDField = BCFixed<31>;
@@ -1610,6 +1610,12 @@
BCArray<IdentifierIDField>
>;
+ using CustomDeclAttrLayout = BCRecordLayout<
+ Custom_DECL_ATTR,
+ BCFixed<1>, // implicit flag
+ TypeIDField // type referenced by this custom attribute
+ >;
+
}
/// Returns the encoding kind for the given decl.
diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp
index a8751e9..4541b48 100644
--- a/lib/AST/Attr.cpp
+++ b/lib/AST/Attr.cpp
@@ -18,6 +18,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/Decl.h"
+#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Module.h"
#include "swift/AST/Types.h"
@@ -618,6 +619,16 @@
break;
}
+ case DAK_Custom: {
+ Printer.printAttrName("@");
+ const TypeLoc &typeLoc = cast<CustomAttr>(this)->getTypeLoc();
+ if (auto type = typeLoc.getType())
+ type->print(Printer, Options);
+ else
+ typeLoc.getTypeRepr()->print(Printer, Options);
+ break;
+ }
+
case DAK_Count:
llvm_unreachable("exceed declaration attribute kinds");
@@ -744,6 +755,8 @@
return "_implements";
case DAK_ClangImporterSynthesizedType:
return "_clangImporterSynthesizedType";
+ case DAK_Custom:
+ return "<<custom>>";
}
llvm_unreachable("bad DeclAttrKind");
}
@@ -1134,3 +1147,51 @@
TypeLoc &ImplementsAttr::getProtocolType() {
return ProtocolType;
}
+
+CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type,
+ PatternBindingInitializer *initContext, Expr *arg,
+ ArrayRef<Identifier> argLabels,
+ ArrayRef<SourceLoc> argLabelLocs, bool implicit)
+ : DeclAttribute(DAK_Custom, atLoc, range, implicit),
+ type(type),
+ arg(arg),
+ initContext(initContext) {
+ hasArgLabelLocs = !argLabelLocs.empty();
+ numArgLabels = argLabels.size();
+ initializeCallArguments(argLabels, argLabelLocs,
+ /*hasTrailingClosure=*/false);
+}
+
+CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
+ bool hasInitializer,
+ PatternBindingInitializer *initContext,
+ SourceLoc lParenLoc,
+ ArrayRef<Expr *> args,
+ ArrayRef<Identifier> argLabels,
+ ArrayRef<SourceLoc> argLabelLocs,
+ SourceLoc rParenLoc,
+ bool implicit) {
+ SmallVector<Identifier, 2> argLabelsScratch;
+ SmallVector<SourceLoc, 2> argLabelLocsScratch;
+ Expr *arg = nullptr;
+ if (hasInitializer) {
+ arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs,
+ rParenLoc, nullptr, implicit, argLabelsScratch,
+ argLabelLocsScratch);
+ }
+
+ SourceRange range(atLoc, type.getSourceRange().End);
+ if (arg)
+ range.End = arg->getEndLoc();
+
+ size_t size = totalSizeToAlloc(argLabels, argLabelLocs,
+ /*hasTrailingClosure=*/false);
+ void *mem = ctx.Allocate(size, alignof(CustomAttr));
+ return new (mem) CustomAttr(atLoc, range, type, initContext, arg, argLabels,
+ argLabelLocs, implicit);
+}
+
+void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
+ if (attr)
+ attr->print(out);
+}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 98db5ba..3f9b3b0 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1089,23 +1089,16 @@
arg->setType(TupleType::get(typeElements, ctx));
}
-/// Pack the argument information into a single argument, to match the
-/// representation expected by the AST.
-///
-/// \param argLabels The argument labels, which might be updated by this
-/// function.
-///
-/// \param argLabelLocs The argument label locations, which might be updated by
-/// this function.
-static Expr *
-packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef<Expr *> args,
- ArrayRef<Identifier> &argLabels,
- ArrayRef<SourceLoc> &argLabelLocs, SourceLoc rParenLoc,
- Expr *trailingClosure, bool implicit,
- SmallVectorImpl<Identifier> &argLabelsScratch,
- SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
- llvm::function_ref<Type(const Expr *)> getType =
- [](const Expr *E) -> Type { return E->getType(); }) {
+Expr *
+swift::packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc,
+ ArrayRef<Expr *> args,
+ ArrayRef<Identifier> &argLabels,
+ ArrayRef<SourceLoc> &argLabelLocs,
+ SourceLoc rParenLoc,
+ Expr *trailingClosure, bool implicit,
+ SmallVectorImpl<Identifier> &argLabelsScratch,
+ SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
+ llvm::function_ref<Type(const Expr *)> getType) {
// Clear out our scratch space.
argLabelsScratch.clear();
argLabelLocsScratch.clear();
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index 9180840..a11c888 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -2093,6 +2093,31 @@
return nominalTypes.empty() ? nullptr : nominalTypes.front();
}
+llvm::Expected<NominalTypeDecl *>
+CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
+ CustomAttr *attr, DeclContext *dc) const {
+ // Find the types referenced by the custom attribute.
+ auto &ctx = dc->getASTContext();
+ TypeLoc &typeLoc = attr->getTypeLoc();
+ DirectlyReferencedTypeDecls decls;
+ if (auto typeRepr = typeLoc.getTypeRepr()) {
+ decls = directReferencesForTypeRepr(
+ evaluator, ctx, typeRepr, dc);
+ } else if (Type type = typeLoc.getType()) {
+ decls = directReferencesForType(type);
+ }
+
+ // Dig out the nominal type declarations.
+ SmallVector<ModuleDecl *, 2> modulesFound;
+ bool anyObject = false;
+ auto nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls,
+ modulesFound, anyObject);
+ if (nominals.size() == 1 && !isa<ProtocolDecl>(nominals.front()))
+ return nominals.front();
+
+ return nullptr;
+}
+
void swift::getDirectlyInheritedNominalTypeDecls(
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
unsigned i,
diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp
index 0a82db6..3016b75 100644
--- a/lib/AST/NameLookupRequests.cpp
+++ b/lib/AST/NameLookupRequests.cpp
@@ -12,6 +12,7 @@
#include "swift/AST/NameLookupRequests.h"
#include "swift/Subsystems.h"
+#include "swift/AST/ASTContext.h"
#include "swift/AST/Evaluator.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
@@ -176,6 +177,20 @@
diags.diagnose(ext, diag::circular_reference_through);
}
+void CustomAttrNominalRequest::diagnoseCycle(
+ DiagnosticEngine &diags) const {
+ auto attr = std::get<0>(getStorage());
+ ASTContext &ctx = std::get<1>(getStorage())->getASTContext();
+ ctx.Diags.diagnose(attr->getLocation(), diag::circular_reference);
+}
+
+void CustomAttrNominalRequest::noteCycleStep(
+ DiagnosticEngine &diags) const {
+ auto attr = std::get<0>(getStorage());
+ ASTContext &ctx = std::get<1>(getStorage())->getASTContext();
+ ctx.Diags.diagnose(attr->getLocation(), diag::circular_reference_through);
+}
+
// Define request evaluation functions for each of the name lookup requests.
static AbstractRequestFunction *nameLookupRequestFunctions[] = {
#define SWIFT_TYPEID(Name) \
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 7ac1dc4..6a3eb23 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -929,6 +929,7 @@
case DAK_RestatedObjCConformance:
case DAK_SynthesizedProtocol:
case DAK_ClangImporterSynthesizedType:
+ case DAK_Custom:
llvm_unreachable("virtual attributes should not be parsed "
"by attribute parsing code");
case DAK_SetterAccess:
@@ -1852,8 +1853,66 @@
if (TypeAttributes::getAttrKindFromString(Tok.getText()) != TAK_Count)
diagnose(Tok, diag::type_attribute_applied_to_decl);
- else
- diagnose(Tok, diag::unknown_attribute, Tok.getText());
+ else if (Tok.isContextualKeyword("unknown")) {
+ diagnose(Tok, diag::unknown_attribute, "unknown");
+ } else {
+ // Parse a custom attribute.
+ auto type = parseType(diag::expected_type);
+ if (type.hasCodeCompletion() || type.isNull()) {
+ if (Tok.is(tok::l_paren))
+ skipSingle();
+
+ return true;
+ }
+
+ // Parse the optional arguments.
+ SourceLoc lParenLoc, rParenLoc;
+ SmallVector<Expr *, 2> args;
+ SmallVector<Identifier, 2> argLabels;
+ SmallVector<SourceLoc, 2> argLabelLocs;
+ Expr *trailingClosure = nullptr;
+ bool hasInitializer = false;
+
+ // If we're not in a local context, we'll need a context to parse
+ // initializers into (should we have one). This happens for properties
+ // and global variables in libraries.
+ PatternBindingInitializer *initContext = nullptr;
+
+ if (Tok.isFollowingLParen()) {
+ SyntaxParsingContext InitCtx(SyntaxContext,
+ SyntaxKind::InitializerClause);
+
+ // If we have no local context to parse the initial value into, create one
+ // for the PBD we'll eventually create. This allows us to have reasonable
+ // DeclContexts for any closures that may live inside of initializers.
+ Optional<ParseFunctionBody> initParser;
+ if (!CurDeclContext->isLocalContext()) {
+ initContext = new (Context) PatternBindingInitializer(CurDeclContext);
+ initParser.emplace(*this, initContext);
+ }
+
+ ParserStatus status = parseExprList(tok::l_paren, tok::r_paren,
+ /*isPostfix=*/false,
+ /*isExprBasic=*/true,
+ lParenLoc, args, argLabels,
+ argLabelLocs,
+ rParenLoc,
+ trailingClosure,
+ SyntaxKind::FunctionCallArgumentList);
+ if (status.hasCodeCompletion())
+ return true;
+
+ assert(!trailingClosure && "Cannot parse a trailing closure here");
+ hasInitializer = true;
+ }
+
+ // Form the attribute.
+ auto attr = CustomAttr::create(Context, AtLoc, type.get(), hasInitializer,
+ initContext, lParenLoc, args, argLabels,
+ argLabelLocs, rParenLoc);
+ Attributes.add(attr);
+ return false;
+ }
// Recover by eating @foo(...) when foo is not known.
consumeToken();
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index be95d33..cd3a18c 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -20,8 +20,10 @@
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ClangModuleLoader.h"
+#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/NameLookup.h"
+#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/Types.h"
@@ -123,6 +125,7 @@
IGNORED_ATTR(WeakLinked)
IGNORED_ATTR(DynamicReplacement)
IGNORED_ATTR(PrivateImport)
+ IGNORED_ATTR(Custom)
#undef IGNORED_ATTR
void visitAlignmentAttr(AlignmentAttr *attr) {
@@ -835,6 +838,7 @@
void visitFrozenAttr(FrozenAttr *attr);
void visitNonOverrideAttr(NonOverrideAttr *attr);
+ void visitCustomAttr(CustomAttr *attr);
};
} // end anonymous namespace
@@ -2399,6 +2403,36 @@
}
}
+void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
+ auto dc = D->getInnermostDeclContext();
+
+ // Figure out which nominal declaration this custom attribute refers to.
+ auto nominal = evaluateOrDefault(
+ TC.Context.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
+
+ // If there is no nominal type with this name, complain about this being
+ // an unknown attribute.
+ if (!nominal) {
+ std::string typeName;
+ if (auto typeRepr = attr->getTypeLoc().getTypeRepr()) {
+ llvm::raw_string_ostream out(typeName);
+ typeRepr->print(out);
+ } else {
+ typeName = attr->getTypeLoc().getType().getString();
+ }
+
+ TC.diagnose(attr->getLocation(), diag::unknown_attribute,
+ typeName);
+ attr->setInvalid();
+ return;
+ }
+
+ TC.diagnose(attr->getLocation(), diag::nominal_type_not_attribute,
+ nominal->getDescriptiveKind(), nominal->getFullName());
+ nominal->diagnose(diag::decl_declared_here, nominal->getFullName());
+ attr->setInvalid();
+}
+
void TypeChecker::checkDeclAttributes(Decl *D) {
AttributeChecker Checker(*this, D);
diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp
index 1542858..7b4f386 100644
--- a/lib/Sema/TypeCheckDeclOverride.cpp
+++ b/lib/Sema/TypeCheckDeclOverride.cpp
@@ -1321,6 +1321,7 @@
UNINTERESTING_ATTR(Frozen)
UNINTERESTING_ATTR(HasInitialValue)
UNINTERESTING_ATTR(ImplementationOnly)
+ UNINTERESTING_ATTR(Custom)
#undef UNINTERESTING_ATTR
void visitAvailableAttr(AvailableAttr *attr) {
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 0fc9e64..92f360a 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -4011,6 +4011,24 @@
break;
}
+ case decls_block::Custom_DECL_ATTR: {
+ bool isImplicit;
+ TypeID typeID;
+ serialization::decls_block::CustomDeclAttrLayout::readRecord(
+ scratch, isImplicit, typeID);
+
+ Expected<Type> deserialized = MF.getTypeChecked(typeID);
+ if (!deserialized) {
+ MF.fatal(deserialized.takeError());
+ break;
+ }
+
+ Attr = CustomAttr::create(ctx, SourceLoc(),
+ TypeLoc::withoutLoc(deserialized.get()),
+ isImplicit);
+ break;
+ }
+
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
case decls_block::CLASS##_DECL_ATTR: { \
bool isImplicit; \
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index bbca78a..b987866 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -2407,6 +2407,15 @@
addDeclRef(theAttr->getReplacedFunction()), pieces.size(), pieces);
return;
}
+
+ case DAK_Custom: {
+ auto abbrCode = DeclTypeAbbrCodes[CustomDeclAttrLayout::Code];
+ auto theAttr = cast<CustomAttr>(DA);
+ CustomDeclAttrLayout::emitRecord(
+ Out, ScratchRecord, abbrCode, theAttr->isImplicit(),
+ addTypeRef(theAttr->getTypeLoc().getType()));
+ return;
+ }
}
}