| //===--- Attr.cpp - Swift Language Attr ASTs ------------------------------===// |
| // |
| // 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 implements routines relating to declaration attributes. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/Attr.h" |
| #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/IndexSubset.h" |
| #include "swift/AST/LazyResolver.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/AST/TypeCheckRequests.h" |
| #include "swift/AST/TypeRepr.h" |
| #include "swift/AST/Types.h" |
| #include "swift/Basic/Defer.h" |
| #include "swift/Basic/QuotedString.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| using namespace swift; |
| |
| #define DECL_ATTR(_, Id, ...) \ |
| static_assert(IsTriviallyDestructible<Id##Attr>::value, \ |
| "Attrs are BumpPtrAllocated; the destructor is never called"); |
| #include "swift/AST/Attr.def" |
| static_assert(IsTriviallyDestructible<DeclAttributes>::value, |
| "DeclAttributes are BumpPtrAllocated; the d'tor is never called"); |
| static_assert(IsTriviallyDestructible<TypeAttributes>::value, |
| "TypeAttributes are BumpPtrAllocated; the d'tor is never called"); |
| |
| #define DECL_ATTR(Name, Id, ...) \ |
| static_assert(DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::ABIBreakingToAdd) != \ |
| DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::ABIStableToAdd), \ |
| #Name " needs to specify either ABIBreakingToAdd or ABIStableToAdd"); |
| #include "swift/AST/Attr.def" |
| |
| #define DECL_ATTR(Name, Id, ...) \ |
| static_assert(DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::ABIBreakingToRemove) != \ |
| DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::ABIStableToRemove), \ |
| #Name " needs to specify either ABIBreakingToRemove or ABIStableToRemove"); |
| #include "swift/AST/Attr.def" |
| |
| #define DECL_ATTR(Name, Id, ...) \ |
| static_assert(DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::APIBreakingToAdd) != \ |
| DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::APIStableToAdd), \ |
| #Name " needs to specify either APIBreakingToAdd or APIStableToAdd"); |
| #include "swift/AST/Attr.def" |
| |
| #define DECL_ATTR(Name, Id, ...) \ |
| static_assert(DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::APIBreakingToRemove) != \ |
| DeclAttribute::isOptionSetFor##Id(DeclAttribute::DeclAttrOptions::APIStableToRemove), \ |
| #Name " needs to specify either APIBreakingToRemove or APIStableToRemove"); |
| #include "swift/AST/Attr.def" |
| |
| // Only allow allocation of attributes using the allocator in ASTContext. |
| void *AttributeBase::operator new(size_t Bytes, ASTContext &C, |
| unsigned Alignment) { |
| return C.Allocate(Bytes, Alignment); |
| } |
| |
| StringRef swift::getAccessLevelSpelling(AccessLevel value) { |
| switch (value) { |
| case AccessLevel::Private: return "private"; |
| case AccessLevel::FilePrivate: return "fileprivate"; |
| case AccessLevel::Internal: return "internal"; |
| case AccessLevel::Public: return "public"; |
| case AccessLevel::Open: return "open"; |
| } |
| |
| llvm_unreachable("Unhandled AccessLevel in switch."); |
| } |
| |
| void TypeAttributes::getConventionArguments(SmallVectorImpl<char> &buf) const { |
| llvm::raw_svector_ostream stream(buf); |
| auto &convention = ConventionArguments.getValue(); |
| stream << convention.Name; |
| if (convention.WitnessMethodProtocol) { |
| stream << ": " << convention.WitnessMethodProtocol; |
| return; |
| } |
| if (!convention.ClangType.Item.empty()) |
| stream << ", cType: " << QuotedString(convention.ClangType.Item); |
| } |
| |
| /// Given a name like "autoclosure", return the type attribute ID that |
| /// corresponds to it. This returns TAK_Count on failure. |
| /// |
| TypeAttrKind TypeAttributes::getAttrKindFromString(StringRef Str) { |
| return llvm::StringSwitch<TypeAttrKind>(Str) |
| #define TYPE_ATTR(X) .Case(#X, TAK_##X) |
| #include "swift/AST/Attr.def" |
| .Default(TAK_Count); |
| } |
| |
| /// Return the name (like "autoclosure") for an attribute ID. |
| const char *TypeAttributes::getAttrName(TypeAttrKind kind) { |
| switch (kind) { |
| default: llvm_unreachable("Invalid attribute ID"); |
| #define TYPE_ATTR(X) case TAK_##X: return #X; |
| #include "swift/AST/Attr.def" |
| } |
| } |
| |
| |
| |
| /// Given a name like "inline", return the decl attribute ID that corresponds |
| /// to it. Note that this is a many-to-one mapping, and that the identifier |
| /// passed in may only be the first portion of the attribute (e.g. in the case |
| /// of the 'unowned(unsafe)' attribute, the string passed in is 'unowned'. |
| /// |
| /// Also note that this recognizes both attributes like '@inline' (with no @) |
| /// and decl modifiers like 'final'. This returns DAK_Count on failure. |
| /// |
| DeclAttrKind DeclAttribute::getAttrKindFromString(StringRef Str) { |
| return llvm::StringSwitch<DeclAttrKind>(Str) |
| #define DECL_ATTR(X, CLASS, ...) .Case(#X, DAK_##CLASS) |
| #define DECL_ATTR_ALIAS(X, CLASS) .Case(#X, DAK_##CLASS) |
| #include "swift/AST/Attr.def" |
| .Default(DAK_Count); |
| } |
| |
| /// Returns true if this attribute can appear on the specified decl. |
| bool DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind DK, const Decl *D) { |
| return canAttributeAppearOnDeclKind(DK, D->getKind()); |
| } |
| |
| bool DeclAttribute::canAttributeAppearOnDeclKind(DeclAttrKind DAK, DeclKind DK) { |
| auto Options = getOptions(DAK); |
| switch (DK) { |
| #define DECL(Id, Parent) case DeclKind::Id: return (Options & On##Id) != 0; |
| #include "swift/AST/DeclNodes.def" |
| } |
| llvm_unreachable("bad DeclKind"); |
| } |
| |
| bool |
| DeclAttributes::isUnavailableInSwiftVersion( |
| const version::Version &effectiveVersion) const { |
| llvm::VersionTuple vers = effectiveVersion; |
| for (auto attr : *this) { |
| if (auto available = dyn_cast<AvailableAttr>(attr)) { |
| if (available->isInvalid()) |
| continue; |
| |
| if (available->getPlatformAgnosticAvailability() == |
| PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) { |
| if (available->Introduced.hasValue() && |
| available->Introduced.getValue() > vers) |
| return true; |
| if (available->Obsoleted.hasValue() && |
| available->Obsoleted.getValue() <= vers) |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| const AvailableAttr * |
| DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx) const{ |
| const AvailableAttr *bestAttr = nullptr; |
| |
| for (auto attr : *this) { |
| auto *avAttr = dyn_cast<AvailableAttr>(attr); |
| if (!avAttr) |
| continue; |
| |
| if (avAttr->isInvalid()) |
| continue; |
| |
| if (!avAttr->hasPlatform()) |
| continue; |
| |
| if (!avAttr->isActivePlatform(ctx)) |
| continue; |
| |
| // We have an attribute that is active for the platform, but |
| // is it more specific than our curent best? |
| if (!bestAttr || inheritsAvailabilityFromPlatform(avAttr->Platform, |
| bestAttr->Platform)) { |
| bestAttr = avAttr; |
| } |
| } |
| |
| return bestAttr; |
| } |
| |
| const AvailableAttr * |
| DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const { |
| const AvailableAttr *potential = nullptr; |
| const AvailableAttr *conditional = nullptr; |
| |
| for (auto Attr : *this) |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Definitely not available. |
| if (AvAttr->isUnconditionallyUnavailable()) |
| return AvAttr; |
| |
| switch (AvAttr->getVersionAvailability(ctx)) { |
| case AvailableVersionComparison::Available: |
| // Doesn't limit the introduced version. |
| break; |
| |
| case AvailableVersionComparison::PotentiallyUnavailable: |
| // We'll return this if we don't see something that proves it's |
| // not available in this version. |
| potential = AvAttr; |
| break; |
| |
| case AvailableVersionComparison::Unavailable: |
| case AvailableVersionComparison::Obsoleted: |
| conditional = AvAttr; |
| break; |
| } |
| } |
| |
| if (conditional) |
| return conditional; |
| return potential; |
| } |
| |
| const AvailableAttr *DeclAttributes::getUnavailable( |
| const ASTContext &ctx) const { |
| const AvailableAttr *conditional = nullptr; |
| const AvailableAttr *bestActive = findMostSpecificActivePlatform(ctx); |
| |
| for (auto Attr : *this) |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| // If this is a platform-specific attribute and it isn't the most |
| // specific attribute for the current platform, we're done. |
| if (AvAttr->hasPlatform() && |
| (!bestActive || AvAttr != bestActive)) |
| continue; |
| |
| // If this attribute doesn't apply to the active platform, we're done. |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Unconditional unavailable. |
| if (AvAttr->isUnconditionallyUnavailable()) |
| return AvAttr; |
| |
| switch (AvAttr->getVersionAvailability(ctx)) { |
| case AvailableVersionComparison::Available: |
| case AvailableVersionComparison::PotentiallyUnavailable: |
| break; |
| |
| case AvailableVersionComparison::Obsoleted: |
| case AvailableVersionComparison::Unavailable: |
| conditional = AvAttr; |
| break; |
| } |
| } |
| return conditional; |
| } |
| |
| const AvailableAttr * |
| DeclAttributes::getDeprecated(const ASTContext &ctx) const { |
| const AvailableAttr *conditional = nullptr; |
| const AvailableAttr *bestActive = findMostSpecificActivePlatform(ctx); |
| for (auto Attr : *this) { |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| if (AvAttr->hasPlatform() && |
| (!bestActive || AvAttr != bestActive)) |
| continue; |
| |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Unconditional deprecated. |
| if (AvAttr->isUnconditionallyDeprecated()) |
| return AvAttr; |
| |
| Optional<llvm::VersionTuple> DeprecatedVersion = AvAttr->Deprecated; |
| if (!DeprecatedVersion.hasValue()) |
| continue; |
| |
| llvm::VersionTuple MinVersion = AvAttr->getActiveVersion(ctx); |
| |
| // We treat the declaration as deprecated if it is deprecated on |
| // all deployment targets. |
| // Once availability checking is enabled by default, we should |
| // query the type refinement context hierarchy to determine |
| // whether a declaration is deprecated on all versions |
| // allowed by the context containing the reference. |
| if (DeprecatedVersion.getValue() <= MinVersion) { |
| conditional = AvAttr; |
| } |
| } |
| } |
| return conditional; |
| } |
| |
| void DeclAttributes::dump(const Decl *D) const { |
| StreamPrinter P(llvm::errs()); |
| PrintOptions PO = PrintOptions::printEverything(); |
| print(P, PO, D); |
| } |
| |
| /// Returns true if the attribute can be presented as a short form available |
| /// attribute (e.g., as @available(iOS 8.0, *). The presentation requires an |
| /// introduction version and does not support deprecation, obsoletion, or |
| /// messages. |
| LLVM_READONLY |
| static bool isShortAvailable(const DeclAttribute *DA) { |
| auto *AvailAttr = dyn_cast<AvailableAttr>(DA); |
| if (!AvailAttr) |
| return false; |
| |
| if (!AvailAttr->Introduced.hasValue()) |
| return false; |
| |
| if (AvailAttr->Deprecated.hasValue()) |
| return false; |
| |
| if (AvailAttr->Obsoleted.hasValue()) |
| return false; |
| |
| if (!AvailAttr->Message.empty()) |
| return false; |
| |
| if (!AvailAttr->Rename.empty()) |
| return false; |
| |
| switch (AvailAttr->PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| return false; |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return true; |
| } |
| |
| return true; |
| } |
| |
| /// Return true when another availability attribute implies the same availability as this |
| /// attribute and so printing the attribute can be skipped to de-clutter the declaration |
| /// when printing the short form. |
| /// For example, iOS availability implies macCatalyst availability so if attributes for |
| /// both are present and they have the same 'introduced' version, we can skip printing an |
| /// explicit availability for macCatalyst. |
| static bool isShortFormAvailabilityImpliedByOther(const AvailableAttr *Attr, |
| ArrayRef<const DeclAttribute *> Others) { |
| assert(isShortAvailable(Attr)); |
| |
| for (auto *DA : Others) { |
| auto *Other = cast<AvailableAttr>(DA); |
| if (Attr->Platform == Other->Platform) |
| continue; |
| |
| if (!inheritsAvailabilityFromPlatform(Attr->Platform, Other->Platform)) |
| continue; |
| |
| if (Attr->Introduced == Other->Introduced) |
| return true; |
| } |
| return false; |
| } |
| |
| /// Print the short-form @available() attribute for an array of long-form |
| /// AvailableAttrs that can be represented in the short form. |
| /// For example, for: |
| /// @available(OSX, introduced: 10.10) |
| /// @available(iOS, introduced: 8.0) |
| /// this will print: |
| /// @available(OSX 10.10, iOS 8.0, *) |
| static void printShortFormAvailable(ArrayRef<const DeclAttribute *> Attrs, |
| ASTPrinter &Printer, |
| const PrintOptions &Options) { |
| assert(!Attrs.empty()); |
| |
| Printer << "@available("; |
| auto FirstAvail = cast<AvailableAttr>(Attrs.front()); |
| if (Attrs.size() == 1 && |
| FirstAvail->getPlatformAgnosticAvailability() != |
| PlatformAgnosticAvailabilityKind::None) { |
| assert(FirstAvail->Introduced.hasValue()); |
| if (FirstAvail->isLanguageVersionSpecific()) { |
| Printer << "swift "; |
| } else { |
| assert(FirstAvail->isPackageDescriptionVersionSpecific()); |
| Printer << "_PackageDescription "; |
| } |
| Printer << FirstAvail->Introduced.getValue().getAsString() |
| << ")"; |
| } else { |
| for (auto *DA : Attrs) { |
| auto *AvailAttr = cast<AvailableAttr>(DA); |
| assert(AvailAttr->Introduced.hasValue()); |
| if (isShortFormAvailabilityImpliedByOther(AvailAttr, Attrs)) |
| continue; |
| Printer << platformString(AvailAttr->Platform) << " " |
| << AvailAttr->Introduced.getValue().getAsString() << ", "; |
| } |
| Printer << "*)"; |
| } |
| Printer.printNewline(); |
| } |
| |
| /// The kind of a parameter in a `wrt:` differentiation parameters clause: |
| /// either a differentiability parameter or a linearity parameter. Used for |
| /// printing `@differentiable`, `@derivative`, and `@transpose` attributes. |
| enum class DifferentiationParameterKind { |
| /// A differentiability parameter, printed by name. |
| /// Used for `@differentiable` and `@derivative` attribute. |
| Differentiability, |
| /// A linearity parameter, printed by index. |
| /// Used for `@transpose` attribute. |
| Linearity |
| }; |
| |
| /// Returns the differentiation parameters clause string for the given function, |
| /// parameter indices, parsed parameters, and differentiation parameter kind. |
| /// Use the parameter indices if specified; otherwise, use the parsed |
| /// parameters. |
| static std::string getDifferentiationParametersClauseString( |
| const AbstractFunctionDecl *function, IndexSubset *parameterIndices, |
| ArrayRef<ParsedAutoDiffParameter> parsedParams, |
| DifferentiationParameterKind parameterKind) { |
| assert(function); |
| bool isInstanceMethod = function->isInstanceMember(); |
| bool isStaticMethod = function->isStatic(); |
| std::string result; |
| llvm::raw_string_ostream printer(result); |
| |
| // Use the parameter indices, if specified. |
| if (parameterIndices) { |
| auto parameters = parameterIndices->getBitVector(); |
| auto parameterCount = parameters.count(); |
| printer << "wrt: "; |
| if (parameterCount > 1) |
| printer << '('; |
| // Check if differentiating wrt `self`. If so, manually print it first. |
| bool isWrtSelf = |
| (isInstanceMethod || |
| (isStaticMethod && |
| parameterKind == DifferentiationParameterKind::Linearity)) && |
| parameters.test(parameters.size() - 1); |
| if (isWrtSelf) { |
| parameters.reset(parameters.size() - 1); |
| printer << "self"; |
| if (parameters.any()) |
| printer << ", "; |
| } |
| // Print remaining differentiation parameters. |
| interleave(parameters.set_bits(), [&](unsigned index) { |
| switch (parameterKind) { |
| // Print differentiability parameters by name. |
| case DifferentiationParameterKind::Differentiability: |
| printer << function->getParameters()->get(index)->getName().str(); |
| break; |
| // Print linearity parameters by index. |
| case DifferentiationParameterKind::Linearity: |
| printer << index; |
| break; |
| } |
| }, [&] { printer << ", "; }); |
| if (parameterCount > 1) |
| printer << ')'; |
| } |
| // Otherwise, use the parsed parameters. |
| else if (!parsedParams.empty()) { |
| printer << "wrt: "; |
| if (parsedParams.size() > 1) |
| printer << '('; |
| interleave(parsedParams, [&](const ParsedAutoDiffParameter ¶m) { |
| switch (param.getKind()) { |
| case ParsedAutoDiffParameter::Kind::Named: |
| printer << param.getName(); |
| break; |
| case ParsedAutoDiffParameter::Kind::Self: |
| printer << "self"; |
| break; |
| case ParsedAutoDiffParameter::Kind::Ordered: |
| auto *paramList = function->getParameters(); |
| assert(param.getIndex() <= paramList->size() && |
| "wrt parameter is out of range"); |
| auto *funcParam = paramList->get(param.getIndex()); |
| printer << funcParam->getNameStr(); |
| break; |
| } |
| }, [&] { printer << ", "; }); |
| if (parsedParams.size() > 1) |
| printer << ')'; |
| } |
| return printer.str(); |
| } |
| |
| /// Print the arguments of the given `@differentiable` attribute. |
| /// - If `omitWrtClause` is true, omit printing the `wrt:` differentiation |
| /// parameters clause. |
| static void printDifferentiableAttrArguments( |
| const DifferentiableAttr *attr, ASTPrinter &printer, |
| const PrintOptions &Options, const Decl *D, bool omitWrtClause = false) { |
| assert(D); |
| // Create a temporary string for the attribute argument text. |
| std::string attrArgText; |
| llvm::raw_string_ostream stream(attrArgText); |
| |
| // Get original function. |
| auto *original = dyn_cast<AbstractFunctionDecl>(D); |
| // Handle stored/computed properties and subscript methods. |
| if (auto *asd = dyn_cast<AbstractStorageDecl>(D)) |
| original = asd->getAccessor(AccessorKind::Get); |
| assert(original && "Must resolve original declaration"); |
| |
| // Print comma if not leading clause. |
| bool isLeadingClause = true; |
| auto printCommaIfNecessary = [&] { |
| if (isLeadingClause) { |
| isLeadingClause = false; |
| return; |
| } |
| stream << ", "; |
| }; |
| |
| // Print if the function is marked as linear. |
| if (attr->isLinear()) { |
| isLeadingClause = false; |
| stream << "linear"; |
| } |
| |
| // Print differentiation parameters clause, unless it is to be omitted. |
| if (!omitWrtClause) { |
| auto diffParamsString = getDifferentiationParametersClauseString( |
| original, attr->getParameterIndices(), attr->getParsedParameters(), |
| DifferentiationParameterKind::Differentiability); |
| // Check whether differentiation parameter clause is empty. |
| // Handles edge case where resolved parameter indices are unset and |
| // parsed parameters are empty. This case should never trigger for |
| // user-visible printing. |
| if (!diffParamsString.empty()) { |
| printCommaIfNecessary(); |
| stream << diffParamsString; |
| } |
| } |
| // Print 'where' clause, if any. |
| // First, filter out requirements satisfied by the original function's |
| // generic signature. They should not be printed. |
| ArrayRef<Requirement> derivativeRequirements; |
| if (auto derivativeGenSig = attr->getDerivativeGenericSignature()) |
| derivativeRequirements = derivativeGenSig->getRequirements(); |
| auto requirementsToPrint = |
| llvm::make_filter_range(derivativeRequirements, [&](Requirement req) { |
| if (const auto &originalGenSig = original->getGenericSignature()) |
| if (originalGenSig->isRequirementSatisfied(req)) |
| return false; |
| return true; |
| }); |
| if (!llvm::empty(requirementsToPrint)) { |
| if (!isLeadingClause) |
| stream << ' '; |
| stream << "where "; |
| interleave(requirementsToPrint, [&](Requirement req) { |
| if (const auto &originalGenSig = original->getGenericSignature()) |
| if (originalGenSig->isRequirementSatisfied(req)) |
| return; |
| req.print(stream, Options); |
| }, [&] { |
| stream << ", "; |
| }); |
| } |
| |
| // If the attribute argument text is empty, return. Do not print parentheses. |
| if (stream.str().empty()) |
| return; |
| |
| // Otherwise, print the attribute argument text enclosed in parentheses. |
| printer << '('; |
| printer << stream.str(); |
| printer << ')'; |
| } |
| |
| void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| if (!DeclAttrs) |
| return; |
| |
| SmallVector<const DeclAttribute *, 8> orderedAttributes(begin(), end()); |
| print(Printer, Options, orderedAttributes, D); |
| } |
| |
| void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options, |
| ArrayRef<const DeclAttribute *> FlattenedAttrs, |
| const Decl *D) { |
| using AttributeVector = SmallVector<const DeclAttribute *, 8>; |
| |
| // Process attributes in passes. |
| AttributeVector shortAvailableAttributes; |
| const DeclAttribute *swiftVersionAvailableAttribute = nullptr; |
| const DeclAttribute *packageDescriptionVersionAvailableAttribute = nullptr; |
| AttributeVector longAttributes; |
| AttributeVector attributes; |
| AttributeVector modifiers; |
| |
| CustomAttr *FuncBuilderAttr = nullptr; |
| if (auto *VD = dyn_cast_or_null<ValueDecl>(D)) { |
| FuncBuilderAttr = VD->getAttachedResultBuilder(); |
| } |
| for (auto DA : llvm::reverse(FlattenedAttrs)) { |
| // Always print result builder attribute. |
| bool isResultBuilderAttr = DA == FuncBuilderAttr; |
| if (!Options.PrintImplicitAttrs && DA->isImplicit()) |
| continue; |
| if (!Options.PrintUserInaccessibleAttrs && |
| !isResultBuilderAttr && |
| DeclAttribute::isUserInaccessible(DA->getKind())) |
| continue; |
| if (Options.excludeAttrKind(DA->getKind())) |
| continue; |
| |
| // Be careful not to coalesce `@available(swift 5)` with other short |
| // `available' attributes. |
| if (auto *availableAttr = dyn_cast<AvailableAttr>(DA)) { |
| if (availableAttr->isLanguageVersionSpecific() && |
| isShortAvailable(availableAttr)) { |
| swiftVersionAvailableAttribute = availableAttr; |
| continue; |
| } |
| if (availableAttr->isPackageDescriptionVersionSpecific() && |
| isShortAvailable(availableAttr)) { |
| packageDescriptionVersionAvailableAttribute = availableAttr; |
| continue; |
| } |
| } |
| |
| AttributeVector &which = DA->isDeclModifier() ? modifiers : |
| isShortAvailable(DA) ? shortAvailableAttributes : |
| DA->isLongAttribute() ? longAttributes : |
| attributes; |
| which.push_back(DA); |
| } |
| |
| if (swiftVersionAvailableAttribute) |
| printShortFormAvailable(swiftVersionAvailableAttribute, Printer, Options); |
| if (packageDescriptionVersionAvailableAttribute) |
| printShortFormAvailable(packageDescriptionVersionAvailableAttribute, Printer, Options); |
| if (!shortAvailableAttributes.empty()) |
| printShortFormAvailable(shortAvailableAttributes, Printer, Options); |
| |
| for (auto DA : longAttributes) |
| DA->print(Printer, Options, D); |
| for (auto DA : attributes) |
| DA->print(Printer, Options, D); |
| for (auto DA : modifiers) |
| DA->print(Printer, Options, D); |
| } |
| |
| SourceLoc DeclAttributes::getStartLoc(bool forModifiers) const { |
| if (isEmpty()) |
| return SourceLoc(); |
| |
| const DeclAttribute *lastAttr = nullptr; |
| for (auto attr : *this) { |
| if (attr->getRangeWithAt().Start.isValid() && |
| (!forModifiers || attr->isDeclModifier())) |
| lastAttr = attr; |
| } |
| |
| return lastAttr ? lastAttr->getRangeWithAt().Start : SourceLoc(); |
| } |
| |
| bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| |
| // Handle any attributes that are not printed at all before we make printer |
| // callbacks. |
| switch (getKind()) { |
| case DAK_ObjC: |
| if (Options.PrintForSIL && isImplicit()) |
| return false; |
| break; |
| case DAK_RawDocComment: |
| case DAK_ObjCBridged: |
| case DAK_SynthesizedProtocol: |
| case DAK_Rethrows: |
| case DAK_Infix: |
| return false; |
| case DAK_Override: { |
| if (!Options.IsForSwiftInterface) |
| break; |
| // When we are printing Swift interface, we have to skip the override keyword |
| // if the overriden decl is invisible from the interface. Otherwise, an error |
| // will occur while building the Swift module because the overriding decl |
| // doesn't override anything. |
| // We couldn't skip every `override` keywords becuase they change the |
| // ABI if the overriden decl is also publically visible. |
| // For public-override-internal case, having `override` doesn't have ABI |
| // implication. Thus we can skip them. |
| if (auto *VD = dyn_cast<ValueDecl>(D)) { |
| if (auto *BD = VD->getOverriddenDecl()) { |
| if (!BD->hasClangNode() && |
| !BD->getFormalAccessScope(VD->getDeclContext(), |
| /*treatUsableFromInlineAsPublic*/ true) |
| .isPublic()) { |
| return false; |
| } |
| } |
| } |
| break; |
| } |
| case DAK_Custom: { |
| if (!Options.IsForSwiftInterface) |
| break; |
| // For Swift interface, we should print result builder attributes |
| // on parameter decls and on protocol requirements. |
| // Printing the attribute elsewhere isn't ABI relevant. |
| if (auto *VD = dyn_cast<ValueDecl>(D)) { |
| if (VD->getAttachedResultBuilder() == this) { |
| if (!isa<ParamDecl>(D) && |
| !((isa<VarDecl>(D) || isa<FuncDecl>(D)) && |
| isa<ProtocolDecl>(D->getDeclContext()))) |
| return false; |
| } |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| |
| // Handle any decl-modifiers. |
| // FIXME: Ideally we would handle decl modifiers as a special kind of |
| // attribute, but for now it's simpler to treat them as a keyword in the |
| // printer. |
| switch (getKind()) { |
| // Handle all of the SIMPLE_DECL_ATTRs. |
| #define SIMPLE_DECL_ATTR(X, CLASS, ...) case DAK_##CLASS: |
| #include "swift/AST/Attr.def" |
| case DAK_Inline: |
| case DAK_AccessControl: |
| case DAK_ReferenceOwnership: |
| case DAK_Effects: |
| case DAK_Optimize: |
| case DAK_ActorIndependent: |
| if (DeclAttribute::isDeclModifier(getKind())) { |
| Printer.printKeyword(getAttrName(), Options); |
| } else if (Options.IsForSwiftInterface && getKind() == DAK_ResultBuilder) { |
| // Use @_functionBuilder in Swift interfaces to maintain backward |
| // compatibility. |
| Printer.printSimpleAttr("_functionBuilder", /*needAt=*/true); |
| } else { |
| Printer.printSimpleAttr(getAttrName(), /*needAt=*/true); |
| } |
| return true; |
| |
| case DAK_SetterAccess: |
| Printer.printKeyword(getAttrName(), Options, "(set)"); |
| return true; |
| |
| case DAK_SPIAccessControl: { |
| if (!Options.PrintSPIs) return false; |
| |
| auto spiAttr = static_cast<const SPIAccessControlAttr*>(this); |
| interleave(spiAttr->getSPIGroups(), |
| [&](Identifier spiName) { |
| Printer.printAttrName(getAttrName(), true); |
| Printer << "(" << spiName << ")"; |
| }, |
| [&] { Printer << " "; }); |
| return true; |
| } |
| |
| default: |
| break; |
| } |
| |
| Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); |
| SWIFT_DEFER { |
| Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); |
| }; |
| |
| switch (getKind()) { |
| case DAK_Semantics: |
| Printer.printAttrName("@_semantics"); |
| Printer << "(\"" << cast<SemanticsAttr>(this)->Value << "\")"; |
| break; |
| |
| case DAK_Alignment: |
| Printer.printAttrName("@_alignment"); |
| Printer << "(" << cast<AlignmentAttr>(this)->getValue() << ")"; |
| break; |
| |
| case DAK_SILGenName: |
| Printer.printAttrName("@_silgen_name"); |
| Printer << "(\"" << cast<SILGenNameAttr>(this)->Name << "\")"; |
| break; |
| |
| case DAK_OriginallyDefinedIn: { |
| Printer.printAttrName("@_originallyDefinedIn"); |
| Printer << "(module: "; |
| auto Attr = cast<OriginallyDefinedInAttr>(this); |
| Printer << "\"" << Attr->OriginalModuleName << "\", "; |
| Printer << platformString(Attr->Platform) << " " << |
| Attr->MovedVersion.getAsString(); |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_Available: { |
| Printer.printAttrName("@available"); |
| Printer << "("; |
| auto Attr = cast<AvailableAttr>(this); |
| if (Attr->isLanguageVersionSpecific()) |
| Printer << "swift"; |
| else if (Attr->isPackageDescriptionVersionSpecific()) |
| Printer << "_PackageDescription"; |
| else |
| Printer << Attr->platformString(); |
| |
| if (Attr->isUnconditionallyUnavailable()) |
| Printer << ", unavailable"; |
| else if (Attr->isUnconditionallyDeprecated()) |
| Printer << ", deprecated"; |
| |
| if (Attr->Introduced) |
| Printer << ", introduced: " << Attr->Introduced.getValue().getAsString(); |
| if (Attr->Deprecated) |
| Printer << ", deprecated: " << Attr->Deprecated.getValue().getAsString(); |
| if (Attr->Obsoleted) |
| Printer << ", obsoleted: " << Attr->Obsoleted.getValue().getAsString(); |
| |
| if (!Attr->Rename.empty()) |
| Printer << ", renamed: \"" << Attr->Rename << "\""; |
| |
| // If there's no message, but this is specifically an imported |
| // "unavailable in Swift" attribute, synthesize a message to look good in |
| // the generated interface. |
| if (!Attr->Message.empty()) { |
| Printer << ", message: "; |
| Printer.printEscapedStringLiteral(Attr->Message); |
| } |
| else if (Attr->getPlatformAgnosticAvailability() |
| == PlatformAgnosticAvailabilityKind::UnavailableInSwift) |
| Printer << ", message: \"Not available in Swift\""; |
| |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_CDecl: |
| Printer << "@_cdecl(\"" << cast<CDeclAttr>(this)->Name << "\")"; |
| break; |
| |
| case DAK_ObjC: { |
| Printer.printAttrName("@objc"); |
| llvm::SmallString<32> scratch; |
| if (auto Name = cast<ObjCAttr>(this)->getName()) { |
| if (!cast<ObjCAttr>(this)->isNameImplicit()) |
| Printer << "(" << Name->getString(scratch) << ")"; |
| } |
| break; |
| } |
| |
| case DAK_PrivateImport: { |
| Printer.printAttrName("@_private(sourceFile: \""); |
| Printer << cast<PrivateImportAttr>(this)->getSourceFile() << "\")"; |
| break; |
| } |
| |
| case DAK_SwiftNativeObjCRuntimeBase: { |
| auto *attr = cast<SwiftNativeObjCRuntimeBaseAttr>(this); |
| Printer.printAttrName("@_swift_native_objc_runtime_base"); |
| Printer << "(" << attr->BaseClassName.str() << ")"; |
| break; |
| } |
| |
| case DAK_Specialize: { |
| auto *attr = cast<SpecializeAttr>(this); |
| // Don't print the _specialize attribute if it is marked spi and we are |
| // asked to skip SPI. |
| if (!Options.PrintSPIs && !attr->getSPIGroups().empty()) |
| return false; |
| |
| Printer << "@" << getAttrName() << "("; |
| auto exported = attr->isExported() ? "true" : "false"; |
| auto kind = attr->isPartialSpecialization() ? "partial" : "full"; |
| auto target = attr->getTargetFunctionName(); |
| Printer << "exported: "<< exported << ", "; |
| for (auto id : attr->getSPIGroups()) { |
| Printer << "spi: " << id << ", "; |
| } |
| Printer << "kind: " << kind << ", "; |
| if (target) |
| Printer << "target: " << target << ", "; |
| SmallVector<Requirement, 4> requirementsScratch; |
| ArrayRef<Requirement> requirements; |
| if (auto sig = attr->getSpecializedSignature()) |
| requirements = sig->getRequirements(); |
| |
| auto *FnDecl = dyn_cast_or_null<AbstractFunctionDecl>(D); |
| if (FnDecl && FnDecl->getGenericSignature()) { |
| auto genericSig = FnDecl->getGenericSignature(); |
| |
| if (auto sig = attr->getSpecializedSignature()) { |
| requirementsScratch = sig->requirementsNotSatisfiedBy( |
| genericSig); |
| requirements = requirementsScratch; |
| } |
| } |
| |
| if (!requirements.empty()) { |
| Printer << "where "; |
| } |
| |
| interleave(requirements, |
| [&](Requirement req) { |
| req.print(Printer, Options); |
| }, |
| [&] { Printer << ", "; }); |
| |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_Implements: { |
| Printer.printAttrName("@_implements"); |
| Printer << "("; |
| auto *attr = cast<ImplementsAttr>(this); |
| attr->getProtocolType().print(Printer, Options); |
| Printer << ", " << attr->getMemberName() << ")"; |
| break; |
| } |
| |
| case DAK_ObjCRuntimeName: { |
| Printer.printAttrName("@_objcRuntimeName"); |
| Printer << "("; |
| auto *attr = cast<ObjCRuntimeNameAttr>(this); |
| Printer << attr->Name; |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_ClangImporterSynthesizedType: { |
| Printer.printAttrName("@_clangImporterSynthesizedType"); |
| auto *attr = cast<ClangImporterSynthesizedTypeAttr>(this); |
| Printer << "(originalTypeName: \"" << attr->originalTypeName |
| << "\", manglingForKind: \"" << attr->getManglingName() << "\")"; |
| break; |
| } |
| |
| case DAK_DynamicReplacement: { |
| Printer.printAttrName("@_dynamicReplacement"); |
| Printer << "(for: \""; |
| auto *attr = cast<DynamicReplacementAttr>(this); |
| Printer << attr->getReplacedFunctionName() << "\")"; |
| break; |
| } |
| |
| case DAK_TypeEraser: { |
| Printer.printAttrName("@_typeEraser"); |
| Printer << "("; |
| Printer.callPrintNamePre(PrintNameContext::Attribute); |
| auto *attr = cast<TypeEraserAttr>(this); |
| if (auto *repr = attr->getParsedTypeEraserTypeRepr()) |
| repr->print(Printer, Options); |
| else if (auto proto = dyn_cast<ProtocolDecl>(D)) |
| attr->getResolvedType(proto)->print(Printer, Options); |
| Printer.printNamePost(PrintNameContext::Attribute); |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_Custom: { |
| Printer.callPrintNamePre(PrintNameContext::Attribute); |
| Printer << "@"; |
| auto *attr = cast<CustomAttr>(this); |
| if (auto type = attr->getType()) |
| type.print(Printer, Options); |
| else |
| attr->getTypeRepr()->print(Printer, Options); |
| Printer.printNamePost(PrintNameContext::Attribute); |
| break; |
| } |
| |
| case DAK_ProjectedValueProperty: |
| Printer.printAttrName("@_projectedValueProperty"); |
| Printer << "("; |
| Printer << cast<ProjectedValuePropertyAttr>(this)->ProjectionPropertyName; |
| Printer << ")"; |
| break; |
| |
| case DAK_Differentiable: { |
| Printer.printAttrName("@differentiable"); |
| auto *attr = cast<DifferentiableAttr>(this); |
| printDifferentiableAttrArguments(attr, Printer, Options, D); |
| break; |
| } |
| |
| case DAK_Derivative: { |
| Printer.printAttrName("@derivative"); |
| Printer << "(of: "; |
| auto *attr = cast<DerivativeAttr>(this); |
| if (auto *baseType = attr->getBaseTypeRepr()) |
| baseType->print(Printer, Options); |
| attr->getOriginalFunctionName().print(Printer); |
| auto *derivative = cast<AbstractFunctionDecl>(D); |
| auto diffParamsString = getDifferentiationParametersClauseString( |
| derivative, attr->getParameterIndices(), attr->getParsedParameters(), |
| DifferentiationParameterKind::Differentiability); |
| if (!diffParamsString.empty()) |
| Printer << ", " << diffParamsString; |
| Printer << ')'; |
| break; |
| } |
| |
| case DAK_Transpose: { |
| Printer.printAttrName("@transpose"); |
| Printer << "(of: "; |
| auto *attr = cast<TransposeAttr>(this); |
| if (auto *baseType = attr->getBaseTypeRepr()) |
| baseType->print(Printer, Options); |
| attr->getOriginalFunctionName().print(Printer); |
| auto *transpose = cast<AbstractFunctionDecl>(D); |
| auto transParamsString = getDifferentiationParametersClauseString( |
| transpose, attr->getParameterIndices(), attr->getParsedParameters(), |
| DifferentiationParameterKind::Linearity); |
| if (!transParamsString.empty()) |
| Printer << ", " << transParamsString; |
| Printer << ')'; |
| break; |
| } |
| |
| case DAK_Count: |
| llvm_unreachable("exceed declaration attribute kinds"); |
| |
| #define SIMPLE_DECL_ATTR(X, CLASS, ...) case DAK_##CLASS: |
| #include "swift/AST/Attr.def" |
| llvm_unreachable("handled above"); |
| |
| default: |
| assert(DeclAttribute::isDeclModifier(getKind()) && |
| "handled above"); |
| } |
| |
| return true; |
| } |
| |
| void DeclAttribute::print(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| |
| if (!printImpl(Printer, Options, D)) |
| return; // Nothing printed. |
| |
| if (isLongAttribute() && Options.PrintLongAttrsOnSeparateLines) |
| Printer.printNewline(); |
| else |
| Printer << " "; |
| } |
| |
| void DeclAttribute::print(llvm::raw_ostream &OS, const Decl *D) const { |
| StreamPrinter P(OS); |
| print(P, PrintOptions(), D); |
| } |
| |
| uint64_t DeclAttribute::getOptions(DeclAttrKind DK) { |
| switch (DK) { |
| case DAK_Count: |
| llvm_unreachable("getOptions needs a valid attribute"); |
| #define DECL_ATTR(_, CLASS, OPTIONS, ...)\ |
| case DAK_##CLASS: return OPTIONS; |
| #include "swift/AST/Attr.def" |
| } |
| llvm_unreachable("bad DeclAttrKind"); |
| } |
| |
| StringRef DeclAttribute::getAttrName() const { |
| switch (getKind()) { |
| case DAK_Count: |
| llvm_unreachable("getAttrName needs a valid attribute"); |
| #define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \ |
| case DAK_##CLASS: \ |
| return #NAME; |
| #include "swift/AST/Attr.def" |
| case DAK_SILGenName: |
| return "_silgen_name"; |
| case DAK_Alignment: |
| return "_alignment"; |
| case DAK_CDecl: |
| return "_cdecl"; |
| case DAK_SwiftNativeObjCRuntimeBase: |
| return "_swift_native_objc_runtime_base"; |
| case DAK_Semantics: |
| return "_semantics"; |
| case DAK_Available: |
| return "available"; |
| case DAK_ObjC: |
| case DAK_ObjCRuntimeName: |
| return "objc"; |
| case DAK_DynamicReplacement: |
| return "_dynamicReplacement"; |
| case DAK_TypeEraser: |
| return "_typeEraser"; |
| case DAK_PrivateImport: |
| return "_private"; |
| case DAK_RestatedObjCConformance: |
| return "_restatedObjCConformance"; |
| case DAK_Inline: { |
| switch (cast<InlineAttr>(this)->getKind()) { |
| case InlineKind::Never: |
| return "inline(never)"; |
| case InlineKind::Always: |
| return "inline(__always)"; |
| } |
| llvm_unreachable("Invalid inline kind"); |
| } |
| case DAK_ActorIndependent: { |
| switch (cast<ActorIndependentAttr>(this)->getKind()) { |
| case ActorIndependentKind::Safe: |
| return "actorIndependent"; |
| case ActorIndependentKind::Unsafe: |
| return "actorIndependent(unsafe)"; |
| } |
| llvm_unreachable("Invalid actorIndependent kind"); |
| } |
| case DAK_Optimize: { |
| switch (cast<OptimizeAttr>(this)->getMode()) { |
| case OptimizationMode::NoOptimization: |
| return "_optimize(none)"; |
| case OptimizationMode::ForSpeed: |
| return "_optimize(speed)"; |
| case OptimizationMode::ForSize: |
| return "_optimize(size)"; |
| default: |
| llvm_unreachable("Invalid optimization kind"); |
| } |
| } |
| case DAK_Effects: |
| switch (cast<EffectsAttr>(this)->getKind()) { |
| case EffectsKind::ReadNone: |
| return "_effects(readnone)"; |
| case EffectsKind::ReadOnly: |
| return "_effects(readonly)"; |
| case EffectsKind::ReleaseNone: |
| return "_effects(releasenone)"; |
| case EffectsKind::ReadWrite: |
| return "_effects(readwrite)"; |
| case EffectsKind::Unspecified: |
| return "_effects(unspecified)"; |
| } |
| case DAK_AccessControl: |
| case DAK_SetterAccess: { |
| AccessLevel access = cast<AbstractAccessControlAttr>(this)->getAccess(); |
| return getAccessLevelSpelling(access); |
| } |
| |
| case DAK_SPIAccessControl: |
| return "_spi"; |
| case DAK_ReferenceOwnership: |
| return keywordOf(cast<ReferenceOwnershipAttr>(this)->get()); |
| case DAK_RawDocComment: |
| return "<<raw doc comment>>"; |
| case DAK_ObjCBridged: |
| return "<<ObjC bridged>>"; |
| case DAK_SynthesizedProtocol: |
| return "<<synthesized protocol>>"; |
| case DAK_Specialize: |
| return "_specialize"; |
| case DAK_Implements: |
| return "_implements"; |
| case DAK_ClangImporterSynthesizedType: |
| return "_clangImporterSynthesizedType"; |
| case DAK_Custom: |
| return "<<custom>>"; |
| case DAK_ProjectedValueProperty: |
| return "_projectedValueProperty"; |
| case DAK_OriginallyDefinedIn: |
| return "_originallyDefinedIn"; |
| case DAK_Differentiable: |
| return "differentiable"; |
| case DAK_Derivative: |
| return "derivative"; |
| case DAK_Transpose: |
| return "transpose"; |
| } |
| llvm_unreachable("bad DeclAttrKind"); |
| } |
| |
| ObjCAttr::ObjCAttr(SourceLoc atLoc, SourceRange baseRange, |
| Optional<ObjCSelector> name, SourceRange parenRange, |
| ArrayRef<SourceLoc> nameLocs) |
| : DeclAttribute(DAK_ObjC, atLoc, baseRange, /*Implicit=*/false), |
| NameData(nullptr) |
| { |
| if (name) { |
| // Store the name. |
| assert(name->getNumSelectorPieces() == nameLocs.size()); |
| NameData = name->getOpaqueValue(); |
| |
| // Store location information. |
| Bits.ObjCAttr.HasTrailingLocationInfo = true; |
| getTrailingLocations()[0] = parenRange.Start; |
| getTrailingLocations()[1] = parenRange.End; |
| std::memcpy(getTrailingLocations().slice(2).data(), nameLocs.data(), |
| nameLocs.size() * sizeof(SourceLoc)); |
| } else { |
| Bits.ObjCAttr.HasTrailingLocationInfo = false; |
| } |
| |
| Bits.ObjCAttr.ImplicitName = false; |
| Bits.ObjCAttr.Swift3Inferred = false; |
| } |
| |
| ObjCAttr *ObjCAttr::create(ASTContext &Ctx, Optional<ObjCSelector> name, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(name, isNameImplicit); |
| } |
| |
| ObjCAttr *ObjCAttr::createUnnamed(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc) { |
| return new (Ctx) ObjCAttr(AtLoc, SourceRange(ObjCLoc), None, |
| SourceRange(), { }); |
| } |
| |
| ObjCAttr *ObjCAttr::createUnnamedImplicit(ASTContext &Ctx) { |
| return new (Ctx) ObjCAttr(None, false); |
| } |
| |
| ObjCAttr *ObjCAttr::createNullary(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc, SourceLoc LParenLoc, |
| SourceLoc NameLoc, Identifier Name, |
| SourceLoc RParenLoc) { |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(3), alignof(ObjCAttr)); |
| return new (mem) ObjCAttr(AtLoc, SourceRange(ObjCLoc, RParenLoc), |
| ObjCSelector(Ctx, 0, Name), |
| SourceRange(LParenLoc, RParenLoc), |
| NameLoc); |
| } |
| |
| ObjCAttr *ObjCAttr::createNullary(ASTContext &Ctx, Identifier Name, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(ObjCSelector(Ctx, 0, Name), isNameImplicit); |
| } |
| |
| ObjCAttr *ObjCAttr::createSelector(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc, SourceLoc LParenLoc, |
| ArrayRef<SourceLoc> NameLocs, |
| ArrayRef<Identifier> Names, |
| SourceLoc RParenLoc) { |
| assert(NameLocs.size() == Names.size()); |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(NameLocs.size() + 2), |
| alignof(ObjCAttr)); |
| return new (mem) ObjCAttr(AtLoc, SourceRange(ObjCLoc, RParenLoc), |
| ObjCSelector(Ctx, Names.size(), Names), |
| SourceRange(LParenLoc, RParenLoc), |
| NameLocs); |
| } |
| |
| ObjCAttr *ObjCAttr::createSelector(ASTContext &Ctx, |
| ArrayRef<Identifier> Names, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(ObjCSelector(Ctx, Names.size(), Names), |
| isNameImplicit); |
| } |
| |
| ArrayRef<SourceLoc> ObjCAttr::getNameLocs() const { |
| if (!hasTrailingLocationInfo()) |
| return { }; |
| |
| return getTrailingLocations().slice(2); |
| } |
| |
| SourceLoc ObjCAttr::getLParenLoc() const { |
| if (!hasTrailingLocationInfo()) |
| return SourceLoc(); |
| |
| return getTrailingLocations()[0]; |
| } |
| |
| SourceLoc ObjCAttr::getRParenLoc() const { |
| if (!hasTrailingLocationInfo()) |
| return SourceLoc(); |
| |
| return getTrailingLocations()[1]; |
| } |
| |
| ObjCAttr *ObjCAttr::clone(ASTContext &context) const { |
| auto attr = new (context) ObjCAttr(getName(), isNameImplicit()); |
| attr->setSwift3Inferred(isSwift3Inferred()); |
| return attr; |
| } |
| |
| PrivateImportAttr::PrivateImportAttr(SourceLoc atLoc, SourceRange baseRange, |
| StringRef sourceFile, |
| SourceRange parenRange) |
| : DeclAttribute(DAK_PrivateImport, atLoc, baseRange, /*Implicit=*/false), |
| SourceFile(sourceFile) {} |
| |
| PrivateImportAttr *PrivateImportAttr::create(ASTContext &Ctxt, SourceLoc AtLoc, |
| SourceLoc PrivateLoc, |
| SourceLoc LParenLoc, |
| StringRef sourceFile, |
| SourceLoc RParenLoc) { |
| return new (Ctxt) |
| PrivateImportAttr(AtLoc, SourceRange(PrivateLoc, RParenLoc), sourceFile, |
| SourceRange(LParenLoc, RParenLoc)); |
| } |
| |
| DynamicReplacementAttr::DynamicReplacementAttr(SourceLoc atLoc, |
| SourceRange baseRange, |
| DeclNameRef name, |
| SourceRange parenRange) |
| : DeclAttribute(DAK_DynamicReplacement, atLoc, baseRange, |
| /*Implicit=*/false), |
| ReplacedFunctionName(name) { |
| Bits.DynamicReplacementAttr.HasTrailingLocationInfo = true; |
| getTrailingLocations()[0] = parenRange.Start; |
| getTrailingLocations()[1] = parenRange.End; |
| } |
| |
| DynamicReplacementAttr * |
| DynamicReplacementAttr::create(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc DynReplLoc, SourceLoc LParenLoc, |
| DeclNameRef ReplacedFunction, SourceLoc RParenLoc) { |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(2), |
| alignof(DynamicReplacementAttr)); |
| return new (mem) DynamicReplacementAttr( |
| AtLoc, SourceRange(DynReplLoc, RParenLoc), ReplacedFunction, |
| SourceRange(LParenLoc, RParenLoc)); |
| } |
| |
| DynamicReplacementAttr * |
| DynamicReplacementAttr::create(ASTContext &Ctx, DeclNameRef name, |
| AbstractFunctionDecl *f) { |
| return new (Ctx) DynamicReplacementAttr(name, f); |
| } |
| |
| DynamicReplacementAttr * |
| DynamicReplacementAttr::create(ASTContext &Ctx, DeclNameRef name, |
| LazyMemberLoader *Resolver, uint64_t Data) { |
| return new (Ctx) DynamicReplacementAttr(name, Resolver, Data); |
| } |
| |
| SourceLoc DynamicReplacementAttr::getLParenLoc() const { |
| return getTrailingLocations()[0]; |
| } |
| |
| SourceLoc DynamicReplacementAttr::getRParenLoc() const { |
| return getTrailingLocations()[1]; |
| } |
| |
| TypeEraserAttr *TypeEraserAttr::create(ASTContext &ctx, |
| SourceLoc atLoc, SourceRange range, |
| TypeExpr *typeEraserExpr) { |
| return new (ctx) TypeEraserAttr(atLoc, range, typeEraserExpr, nullptr, 0); |
| } |
| |
| TypeEraserAttr *TypeEraserAttr::create(ASTContext &ctx, |
| LazyMemberLoader *Resolver, |
| uint64_t Data) { |
| return new (ctx) TypeEraserAttr(SourceLoc(), SourceRange(), |
| nullptr, Resolver, Data); |
| } |
| |
| bool TypeEraserAttr::hasViableTypeEraserInit(ProtocolDecl *protocol) const { |
| return evaluateOrDefault(protocol->getASTContext().evaluator, |
| TypeEraserHasViableInitRequest{ |
| const_cast<TypeEraserAttr *>(this), protocol}, |
| false); |
| } |
| |
| TypeRepr *TypeEraserAttr::getParsedTypeEraserTypeRepr() const { |
| return TypeEraserExpr ? TypeEraserExpr->getTypeRepr() : nullptr; |
| } |
| |
| SourceLoc TypeEraserAttr::getLoc() const { |
| return TypeEraserExpr ? TypeEraserExpr->getLoc() : SourceLoc(); |
| } |
| |
| Type TypeEraserAttr::getTypeWithoutResolving() const { |
| return TypeEraserExpr ? TypeEraserExpr->getInstanceType() : Type(); |
| } |
| |
| Type TypeEraserAttr::getResolvedType(const ProtocolDecl *PD) const { |
| auto &ctx = PD->getASTContext(); |
| return evaluateOrDefault(ctx.evaluator, |
| ResolveTypeEraserTypeRequest{ |
| const_cast<ProtocolDecl *>(PD), |
| const_cast<TypeEraserAttr *>(this)}, |
| ErrorType::get(ctx)); |
| } |
| |
| AvailableAttr * |
| AvailableAttr::createPlatformAgnostic(ASTContext &C, |
| StringRef Message, |
| StringRef Rename, |
| PlatformAgnosticAvailabilityKind Kind, |
| llvm::VersionTuple Obsoleted) { |
| assert(Kind != PlatformAgnosticAvailabilityKind::None); |
| llvm::VersionTuple NoVersion; |
| if (Kind == PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) { |
| assert(!Obsoleted.empty()); |
| } |
| return new (C) AvailableAttr( |
| SourceLoc(), SourceRange(), PlatformKind::none, Message, Rename, |
| NoVersion, SourceRange(), |
| NoVersion, SourceRange(), |
| Obsoleted, SourceRange(), |
| Kind, /* isImplicit */ false); |
| } |
| |
| bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const { |
| return isPlatformActive(Platform, ctx.LangOpts); |
| } |
| |
| Optional<OriginallyDefinedInAttr::ActiveVersion> |
| OriginallyDefinedInAttr::isActivePlatform(const ASTContext &ctx) const { |
| OriginallyDefinedInAttr::ActiveVersion Result; |
| Result.Platform = Platform; |
| Result.Version = MovedVersion; |
| Result.ModuleName = OriginalModuleName; |
| if (isPlatformActive(Platform, ctx.LangOpts, /*TargetVariant*/false)) { |
| Result.IsSimulator = ctx.LangOpts.Target.isSimulatorEnvironment(); |
| return Result; |
| } |
| |
| // Also check if the platform is active by using target variant. This ensures |
| // we emit linker directives for multiple platforms when building zippered |
| // libraries. |
| if (ctx.LangOpts.TargetVariant.hasValue() && |
| isPlatformActive(Platform, ctx.LangOpts, /*TargetVariant*/true)) { |
| Result.IsSimulator = ctx.LangOpts.TargetVariant->isSimulatorEnvironment(); |
| return Result; |
| } |
| return None; |
| } |
| |
| bool AvailableAttr::isLanguageVersionSpecific() const { |
| if (PlatformAgnostic == |
| PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) |
| { |
| assert(Platform == PlatformKind::none && |
| (Introduced.hasValue() || |
| Deprecated.hasValue() || |
| Obsoleted.hasValue())); |
| return true; |
| } |
| return false; |
| } |
| |
| bool AvailableAttr::isPackageDescriptionVersionSpecific() const { |
| if (PlatformAgnostic == |
| PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific) |
| { |
| assert(Platform == PlatformKind::none && |
| (Introduced.hasValue() || |
| Deprecated.hasValue() || |
| Obsoleted.hasValue())); |
| return true; |
| } |
| return false; |
| } |
| |
| bool AvailableAttr::isUnconditionallyUnavailable() const { |
| switch (PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return false; |
| |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled PlatformAgnosticAvailabilityKind in switch."); |
| } |
| |
| bool AvailableAttr::isUnconditionallyDeprecated() const { |
| switch (PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return false; |
| |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled PlatformAgnosticAvailabilityKind in switch."); |
| } |
| |
| llvm::VersionTuple AvailableAttr::getActiveVersion(const ASTContext &ctx) const { |
| if (isLanguageVersionSpecific()) { |
| return ctx.LangOpts.EffectiveLanguageVersion; |
| } else if (isPackageDescriptionVersionSpecific()) { |
| return ctx.LangOpts.PackageDescriptionVersion; |
| } else { |
| return ctx.LangOpts.getMinPlatformVersion(); |
| } |
| } |
| |
| AvailableVersionComparison AvailableAttr::getVersionAvailability( |
| const ASTContext &ctx) const { |
| |
| // Unconditional unavailability. |
| if (isUnconditionallyUnavailable()) |
| return AvailableVersionComparison::Unavailable; |
| |
| llvm::VersionTuple queryVersion = getActiveVersion(ctx); |
| |
| // If this entity was obsoleted before or at the query platform version, |
| // consider it obsolete. |
| if (Obsoleted && *Obsoleted <= queryVersion) |
| return AvailableVersionComparison::Obsoleted; |
| |
| // If this entity was introduced after the query version and we're doing a |
| // platform comparison, true availability can only be determined dynamically; |
| // if we're doing a _language_ version check, the query version is a |
| // static requirement, so we treat "introduced later" as just plain |
| // unavailable. |
| if (Introduced && *Introduced > queryVersion) { |
| if (isLanguageVersionSpecific() || isPackageDescriptionVersionSpecific()) |
| return AvailableVersionComparison::Unavailable; |
| else |
| return AvailableVersionComparison::PotentiallyUnavailable; |
| } |
| |
| // The entity is available. |
| return AvailableVersionComparison::Available; |
| } |
| |
| const AvailableAttr *AvailableAttr::isUnavailable(const Decl *D) { |
| ASTContext &ctx = D->getASTContext(); |
| if (auto attr = D->getAttrs().getUnavailable(ctx)) |
| return attr; |
| |
| // If D is an extension member, check if the extension is unavailable. |
| // |
| // Skip decls imported from Clang, they could be associated to the wrong |
| // extension and inherit undesired unavailability. The ClangImporter |
| // associates Objective-C protocol members to the first category where the |
| // protocol is directly or indirectly adopted, no matter its availability |
| // and the availability of other categories. rdar://problem/53956555 |
| if (!D->getClangNode()) |
| if (auto ext = dyn_cast<ExtensionDecl>(D->getDeclContext())) |
| return AvailableAttr::isUnavailable(ext); |
| |
| return nullptr; |
| } |
| |
| SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range, |
| TrailingWhereClause *clause, bool exported, |
| SpecializationKind kind, |
| GenericSignature specializedSignature, |
| DeclNameRef targetFunctionName, |
| ArrayRef<Identifier> spiGroups) |
| : DeclAttribute(DAK_Specialize, atLoc, range, |
| /*Implicit=*/clause == nullptr), |
| trailingWhereClause(clause), specializedSignature(specializedSignature), |
| targetFunctionName(targetFunctionName), numSPIGroups(spiGroups.size()) { |
| std::uninitialized_copy(spiGroups.begin(), spiGroups.end(), |
| getTrailingObjects<Identifier>()); |
| Bits.SpecializeAttr.exported = exported; |
| Bits.SpecializeAttr.kind = unsigned(kind); |
| } |
| |
| TrailingWhereClause *SpecializeAttr::getTrailingWhereClause() const { |
| return trailingWhereClause; |
| } |
| |
| SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, |
| SourceRange range, |
| TrailingWhereClause *clause, |
| bool exported, SpecializationKind kind, |
| DeclNameRef targetFunctionName, |
| ArrayRef<Identifier> spiGroups, |
| GenericSignature specializedSignature) { |
| unsigned size = totalSizeToAlloc<Identifier>(spiGroups.size()); |
| void *mem = Ctx.Allocate(size, alignof(SpecializeAttr)); |
| return new (mem) |
| SpecializeAttr(atLoc, range, clause, exported, kind, specializedSignature, |
| targetFunctionName, spiGroups); |
| } |
| |
| SpecializeAttr *SpecializeAttr::create(ASTContext &ctx, bool exported, |
| SpecializationKind kind, |
| ArrayRef<Identifier> spiGroups, |
| GenericSignature specializedSignature, |
| DeclNameRef targetFunctionName) { |
| unsigned size = totalSizeToAlloc<Identifier>(spiGroups.size()); |
| void *mem = ctx.Allocate(size, alignof(SpecializeAttr)); |
| return new (mem) |
| SpecializeAttr(SourceLoc(), SourceRange(), nullptr, exported, kind, |
| specializedSignature, targetFunctionName, spiGroups); |
| } |
| |
| SpecializeAttr *SpecializeAttr::create( |
| ASTContext &ctx, bool exported, SpecializationKind kind, |
| ArrayRef<Identifier> spiGroups, GenericSignature specializedSignature, |
| DeclNameRef targetFunctionName, LazyMemberLoader *resolver, uint64_t data) { |
| unsigned size = totalSizeToAlloc<Identifier>(spiGroups.size()); |
| void *mem = ctx.Allocate(size, alignof(SpecializeAttr)); |
| auto *attr = new (mem) |
| SpecializeAttr(SourceLoc(), SourceRange(), nullptr, exported, kind, |
| specializedSignature, targetFunctionName, spiGroups); |
| attr->resolver = resolver; |
| attr->resolverContextData = data; |
| return attr; |
| } |
| |
| ValueDecl * SpecializeAttr::getTargetFunctionDecl(const ValueDecl *onDecl) const { |
| return evaluateOrDefault(onDecl->getASTContext().evaluator, |
| SpecializeAttrTargetDeclRequest{ |
| onDecl, const_cast<SpecializeAttr *>(this)}, |
| nullptr); |
| } |
| |
| SPIAccessControlAttr::SPIAccessControlAttr(SourceLoc atLoc, SourceRange range, |
| ArrayRef<Identifier> spiGroups) |
| : DeclAttribute(DAK_SPIAccessControl, atLoc, range, |
| /*Implicit=*/false), |
| numSPIGroups(spiGroups.size()) { |
| std::uninitialized_copy(spiGroups.begin(), spiGroups.end(), |
| getTrailingObjects<Identifier>()); |
| } |
| |
| SPIAccessControlAttr * |
| SPIAccessControlAttr::create(ASTContext &context, |
| SourceLoc atLoc, |
| SourceRange range, |
| ArrayRef<Identifier> spiGroups) { |
| unsigned size = totalSizeToAlloc<Identifier>(spiGroups.size()); |
| void *mem = context.Allocate(size, alignof(SPIAccessControlAttr)); |
| return new (mem) SPIAccessControlAttr(atLoc, range, spiGroups); |
| } |
| |
| DifferentiableAttr::DifferentiableAttr(bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, bool linear, |
| ArrayRef<ParsedAutoDiffParameter> params, |
| TrailingWhereClause *clause) |
| : DeclAttribute(DAK_Differentiable, atLoc, baseRange, implicit), |
| Linear(linear), NumParsedParameters(params.size()), WhereClause(clause) { |
| std::copy(params.begin(), params.end(), |
| getTrailingObjects<ParsedAutoDiffParameter>()); |
| } |
| |
| DifferentiableAttr::DifferentiableAttr(Decl *original, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, |
| bool linear, |
| IndexSubset *parameterIndices, |
| GenericSignature derivativeGenSig) |
| : DeclAttribute(DAK_Differentiable, atLoc, baseRange, implicit), |
| OriginalDeclaration(original), Linear(linear) { |
| setParameterIndices(parameterIndices); |
| setDerivativeGenericSignature(derivativeGenSig); |
| } |
| |
| DifferentiableAttr * |
| DifferentiableAttr::create(ASTContext &context, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, |
| bool linear, |
| ArrayRef<ParsedAutoDiffParameter> parameters, |
| TrailingWhereClause *clause) { |
| unsigned size = totalSizeToAlloc<ParsedAutoDiffParameter>(parameters.size()); |
| void *mem = context.Allocate(size, alignof(DifferentiableAttr)); |
| return new (mem) DifferentiableAttr(implicit, atLoc, baseRange, linear, |
| parameters, clause); |
| } |
| |
| DifferentiableAttr * |
| DifferentiableAttr::create(AbstractFunctionDecl *original, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, bool linear, |
| IndexSubset *parameterIndices, |
| GenericSignature derivativeGenSig) { |
| auto &ctx = original->getASTContext(); |
| |
| size_t size = totalSizeToAlloc<ParsedAutoDiffParameter>(0); |
| void *mem = ctx.Allocate(size, alignof(DifferentiableAttr)); |
| return new (mem) DifferentiableAttr(original, implicit, atLoc, baseRange, |
| linear, parameterIndices, derivativeGenSig); |
| } |
| |
| void DifferentiableAttr::setOriginalDeclaration(Decl *originalDeclaration) { |
| assert(originalDeclaration && "Original declaration must be non-null"); |
| assert(!OriginalDeclaration && |
| "Original declaration cannot have already been set"); |
| OriginalDeclaration = originalDeclaration; |
| } |
| |
| bool DifferentiableAttr::hasBeenTypeChecked() const { |
| return ParameterIndicesAndBit.getInt(); |
| } |
| |
| IndexSubset *DifferentiableAttr::getParameterIndices() const { |
| assert(getOriginalDeclaration() && |
| "Original declaration must have been resolved"); |
| auto &ctx = getOriginalDeclaration()->getASTContext(); |
| return evaluateOrDefault(ctx.evaluator, |
| DifferentiableAttributeTypeCheckRequest{ |
| const_cast<DifferentiableAttr *>(this)}, |
| nullptr); |
| } |
| |
| void DifferentiableAttr::setParameterIndices(IndexSubset *paramIndices) { |
| assert(getOriginalDeclaration() && |
| "Original declaration must have been resolved"); |
| auto &ctx = getOriginalDeclaration()->getASTContext(); |
| ctx.evaluator.cacheOutput( |
| DifferentiableAttributeTypeCheckRequest{ |
| const_cast<DifferentiableAttr *>(this)}, |
| std::move(paramIndices)); |
| } |
| |
| GenericEnvironment *DifferentiableAttr::getDerivativeGenericEnvironment( |
| AbstractFunctionDecl *original) const { |
| if (auto derivativeGenSig = getDerivativeGenericSignature()) |
| return derivativeGenSig->getGenericEnvironment(); |
| return original->getGenericEnvironment(); |
| } |
| |
| void DeclNameRefWithLoc::print(ASTPrinter &Printer) const { |
| Printer << Name; |
| if (AccessorKind) |
| Printer << '.' << getAccessorLabel(*AccessorKind); |
| } |
| |
| void DifferentiableAttr::print(llvm::raw_ostream &OS, const Decl *D, |
| bool omitWrtClause) const { |
| StreamPrinter P(OS); |
| P << "@" << getAttrName(); |
| printDifferentiableAttrArguments(this, P, PrintOptions(), D, omitWrtClause); |
| } |
| |
| DerivativeAttr::DerivativeAttr(bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| ArrayRef<ParsedAutoDiffParameter> params) |
| : DeclAttribute(DAK_Derivative, atLoc, baseRange, implicit), |
| BaseTypeRepr(baseTypeRepr), OriginalFunctionName(std::move(originalName)), |
| NumParsedParameters(params.size()) { |
| std::copy(params.begin(), params.end(), |
| getTrailingObjects<ParsedAutoDiffParameter>()); |
| } |
| |
| DerivativeAttr::DerivativeAttr(bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| IndexSubset *parameterIndices) |
| : DeclAttribute(DAK_Derivative, atLoc, baseRange, implicit), |
| BaseTypeRepr(baseTypeRepr), OriginalFunctionName(std::move(originalName)), |
| ParameterIndices(parameterIndices) {} |
| |
| DerivativeAttr * |
| DerivativeAttr::create(ASTContext &context, bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| ArrayRef<ParsedAutoDiffParameter> params) { |
| unsigned size = totalSizeToAlloc<ParsedAutoDiffParameter>(params.size()); |
| void *mem = context.Allocate(size, alignof(DerivativeAttr)); |
| return new (mem) DerivativeAttr(implicit, atLoc, baseRange, baseTypeRepr, |
| std::move(originalName), params); |
| } |
| |
| DerivativeAttr *DerivativeAttr::create(ASTContext &context, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, |
| TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| IndexSubset *parameterIndices) { |
| void *mem = context.Allocate(sizeof(DerivativeAttr), alignof(DerivativeAttr)); |
| return new (mem) DerivativeAttr(implicit, atLoc, baseRange, baseTypeRepr, |
| std::move(originalName), parameterIndices); |
| } |
| |
| AbstractFunctionDecl * |
| DerivativeAttr::getOriginalFunction(ASTContext &context) const { |
| return evaluateOrDefault( |
| context.evaluator, |
| DerivativeAttrOriginalDeclRequest{const_cast<DerivativeAttr *>(this)}, |
| nullptr); |
| } |
| |
| void DerivativeAttr::setOriginalFunction(AbstractFunctionDecl *decl) { |
| assert(!OriginalFunction && "cannot overwrite original function"); |
| OriginalFunction = decl; |
| } |
| |
| void DerivativeAttr::setOriginalFunctionResolver( |
| LazyMemberLoader *resolver, uint64_t resolverContextData) { |
| assert(!OriginalFunction && "cannot overwrite original function"); |
| OriginalFunction = resolver; |
| ResolverContextData = resolverContextData; |
| } |
| |
| TransposeAttr::TransposeAttr(bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| ArrayRef<ParsedAutoDiffParameter> params) |
| : DeclAttribute(DAK_Transpose, atLoc, baseRange, implicit), |
| BaseTypeRepr(baseTypeRepr), OriginalFunctionName(std::move(originalName)), |
| NumParsedParameters(params.size()) { |
| std::uninitialized_copy(params.begin(), params.end(), |
| getTrailingObjects<ParsedAutoDiffParameter>()); |
| } |
| |
| TransposeAttr::TransposeAttr(bool implicit, SourceLoc atLoc, |
| SourceRange baseRange, TypeRepr *baseTypeRepr, |
| DeclNameRefWithLoc originalName, |
| IndexSubset *parameterIndices) |
| : DeclAttribute(DAK_Transpose, atLoc, baseRange, implicit), |
| BaseTypeRepr(baseTypeRepr), OriginalFunctionName(std::move(originalName)), |
| ParameterIndices(parameterIndices) {} |
| |
| TransposeAttr *TransposeAttr::create(ASTContext &context, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, |
| TypeRepr *baseType, |
| DeclNameRefWithLoc originalName, |
| ArrayRef<ParsedAutoDiffParameter> params) { |
| unsigned size = totalSizeToAlloc<ParsedAutoDiffParameter>(params.size()); |
| void *mem = context.Allocate(size, alignof(TransposeAttr)); |
| return new (mem) TransposeAttr(implicit, atLoc, baseRange, baseType, |
| std::move(originalName), params); |
| } |
| |
| TransposeAttr *TransposeAttr::create(ASTContext &context, bool implicit, |
| SourceLoc atLoc, SourceRange baseRange, |
| TypeRepr *baseType, |
| DeclNameRefWithLoc originalName, |
| IndexSubset *parameterIndices) { |
| void *mem = context.Allocate(sizeof(TransposeAttr), alignof(TransposeAttr)); |
| return new (mem) TransposeAttr(implicit, atLoc, baseRange, baseType, |
| std::move(originalName), parameterIndices); |
| } |
| |
| ImplementsAttr::ImplementsAttr(SourceLoc atLoc, SourceRange range, |
| TypeExpr *ProtocolType, |
| DeclName MemberName, |
| DeclNameLoc MemberNameLoc) |
| : DeclAttribute(DAK_Implements, atLoc, range, /*Implicit=*/false), |
| ProtocolType(ProtocolType), |
| MemberName(MemberName), |
| MemberNameLoc(MemberNameLoc) { |
| } |
| |
| |
| ImplementsAttr *ImplementsAttr::create(ASTContext &Ctx, SourceLoc atLoc, |
| SourceRange range, |
| TypeExpr *ProtocolType, |
| DeclName MemberName, |
| DeclNameLoc MemberNameLoc) { |
| void *mem = Ctx.Allocate(sizeof(ImplementsAttr), alignof(ImplementsAttr)); |
| return new (mem) ImplementsAttr(atLoc, range, ProtocolType, |
| MemberName, MemberNameLoc); |
| } |
| |
| void ImplementsAttr::setProtocolType(Type ty) { |
| assert(ty); |
| ProtocolType->setType(MetatypeType::get(ty)); |
| } |
| |
| Type ImplementsAttr::getProtocolType() const { |
| return ProtocolType->getInstanceType(); |
| } |
| |
| TypeRepr *ImplementsAttr::getProtocolTypeRepr() const { |
| return ProtocolType->getTypeRepr(); |
| } |
| |
| CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type, |
| PatternBindingInitializer *initContext, Expr *arg, |
| ArrayRef<Identifier> argLabels, |
| ArrayRef<SourceLoc> argLabelLocs, bool implicit) |
| : DeclAttribute(DAK_Custom, atLoc, range, implicit), |
| typeExpr(type), |
| arg(arg), |
| initContext(initContext) { |
| assert(type); |
| hasArgLabelLocs = !argLabelLocs.empty(); |
| numArgLabels = argLabels.size(); |
| initializeCallArguments(argLabels, argLabelLocs); |
| } |
| |
| CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, |
| bool hasInitializer, |
| PatternBindingInitializer *initContext, |
| SourceLoc lParenLoc, |
| ArrayRef<Expr *> args, |
| ArrayRef<Identifier> argLabels, |
| ArrayRef<SourceLoc> argLabelLocs, |
| SourceLoc rParenLoc, |
| bool implicit) { |
| assert(type); |
| SmallVector<Identifier, 2> argLabelsScratch; |
| SmallVector<SourceLoc, 2> argLabelLocsScratch; |
| Expr *arg = nullptr; |
| if (hasInitializer) { |
| arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, |
| rParenLoc, /*trailingClosures=*/{}, implicit, |
| argLabelsScratch, argLabelLocsScratch); |
| } |
| |
| SourceRange range(atLoc, type->getSourceRange().End); |
| if (arg) |
| range.End = arg->getEndLoc(); |
| |
| size_t size = totalSizeToAlloc(argLabels, argLabelLocs); |
| void *mem = ctx.Allocate(size, alignof(CustomAttr)); |
| return new (mem) CustomAttr(atLoc, range, type, initContext, arg, argLabels, |
| argLabelLocs, implicit); |
| } |
| |
| TypeRepr *CustomAttr::getTypeRepr() const { return typeExpr->getTypeRepr(); } |
| Type CustomAttr::getType() const { return typeExpr->getInstanceType(); } |
| |
| void CustomAttr::resetTypeInformation(TypeExpr *info) { typeExpr = info; } |
| |
| void CustomAttr::setType(Type ty) { |
| assert(ty); |
| typeExpr->setType(MetatypeType::get(ty)); |
| } |
| |
| void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) { |
| if (attr) |
| attr->print(out); |
| } |