mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
We still only parse transferring... but this sets us up for adding the new 'sending' syntax by first validating that this internal change does not mess up the current transferring impl since we want both to keep working for now. rdar://128216574
855 lines
26 KiB
C++
855 lines
26 KiB
C++
//===--- FeatureSet.cpp - Language feature support --------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2024 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FeatureSet.h"
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/ExistentialLayout.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/Pattern.h"
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
using namespace swift;
|
|
|
|
/// Does the interface of this declaration use a type for which the
|
|
/// given predicate returns true?
|
|
static bool usesTypeMatching(Decl *decl, llvm::function_ref<bool(Type)> fn) {
|
|
if (auto value = dyn_cast<ValueDecl>(decl)) {
|
|
if (Type type = value->getInterfaceType()) {
|
|
return type.findIf(fn);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MARK: - Standard Features
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/// Functions to determine which features a particular declaration uses. The
|
|
/// usesFeatureNNN functions correspond to the features in Features.def.
|
|
|
|
#define BASELINE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
|
|
static bool usesFeature##FeatureName(Decl *decl) { return false; }
|
|
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
|
|
#include "swift/Basic/Features.def"
|
|
|
|
#define UNINTERESTING_FEATURE(FeatureName) \
|
|
static bool usesFeature##FeatureName(Decl *decl) { return false; }
|
|
|
|
static bool usesFeatureRethrowsProtocol(Decl *decl,
|
|
SmallPtrSet<Decl *, 16> &checked) {
|
|
// Make sure we don't recurse.
|
|
if (!checked.insert(decl).second)
|
|
return false;
|
|
|
|
// Check an inheritance clause for a marker protocol.
|
|
auto checkInherited = [&](InheritedTypes inherited) -> bool {
|
|
for (unsigned i : inherited.getIndices()) {
|
|
if (auto inheritedType = inherited.getResolvedType(i)) {
|
|
if (inheritedType->isExistentialType()) {
|
|
auto layout = inheritedType->getExistentialLayout();
|
|
for (ProtocolDecl *proto : layout.getProtocols()) {
|
|
if (usesFeatureRethrowsProtocol(proto, checked))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
|
|
if (checkInherited(nominal->getInherited()))
|
|
return true;
|
|
}
|
|
|
|
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
|
|
if (proto->getAttrs().hasAttribute<AtRethrowsAttr>())
|
|
return true;
|
|
}
|
|
|
|
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
|
|
if (auto nominal = ext->getSelfNominalTypeDecl())
|
|
if (usesFeatureRethrowsProtocol(nominal, checked))
|
|
return true;
|
|
|
|
if (checkInherited(ext->getInherited()))
|
|
return true;
|
|
}
|
|
|
|
if (auto genericSig =
|
|
decl->getInnermostDeclContext()->getGenericSignatureOfContext()) {
|
|
for (const auto &req : genericSig.getRequirements()) {
|
|
if (req.getKind() == RequirementKind::Conformance &&
|
|
usesFeatureRethrowsProtocol(req.getProtocolDecl(), checked))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (auto value = dyn_cast<ValueDecl>(decl)) {
|
|
if (Type type = value->getInterfaceType()) {
|
|
bool hasRethrowsProtocol = type.findIf([&](Type type) {
|
|
if (auto nominal = type->getAnyNominal()) {
|
|
if (usesFeatureRethrowsProtocol(nominal, checked))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
if (hasRethrowsProtocol)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureRethrowsProtocol(Decl *decl) {
|
|
SmallPtrSet<Decl *, 16> checked;
|
|
return usesFeatureRethrowsProtocol(decl, checked);
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(BuiltinBuildTaskExecutorRef)
|
|
UNINTERESTING_FEATURE(BuiltinBuildComplexEqualityExecutor)
|
|
UNINTERESTING_FEATURE(BuiltinCreateAsyncTaskInGroupWithExecutor)
|
|
UNINTERESTING_FEATURE(BuiltinCreateAsyncDiscardingTaskInGroup)
|
|
UNINTERESTING_FEATURE(BuiltinCreateAsyncDiscardingTaskInGroupWithExecutor)
|
|
UNINTERESTING_FEATURE(BuiltinUnprotectedStackAlloc)
|
|
UNINTERESTING_FEATURE(BuiltinAllocVector)
|
|
UNINTERESTING_FEATURE(BuiltinCreateTask)
|
|
|
|
static bool usesFeatureNewCxxMethodSafetyHeuristics(Decl *decl) {
|
|
return decl->hasClangNode();
|
|
}
|
|
|
|
static bool usesFeatureSpecializeAttributeWithAvailability(Decl *decl) {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
|
|
for (auto specialize : func->getAttrs().getAttributes<SpecializeAttr>()) {
|
|
if (!specialize->getAvailableAttrs().empty())
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeaturePrimaryAssociatedTypes2(Decl *decl) {
|
|
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl)) {
|
|
if (protoDecl->getPrimaryAssociatedTypes().size() > 0)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureAssociatedTypeAvailability(Decl *decl) {
|
|
return isa<AssociatedTypeDecl>(decl) &&
|
|
decl->getAttrs().hasAttribute<AvailableAttr>();
|
|
}
|
|
|
|
static bool isImplicitRethrowsProtocol(const ProtocolDecl *proto) {
|
|
return proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence) ||
|
|
proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol);
|
|
}
|
|
|
|
static bool usesFeatureAsyncSequenceFailure(Decl *decl) {
|
|
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
|
|
return isImplicitRethrowsProtocol(proto);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureMacros(Decl *decl) { return isa<MacroDecl>(decl); }
|
|
|
|
static bool usesFeatureFreestandingExpressionMacros(Decl *decl) {
|
|
auto macro = dyn_cast<MacroDecl>(decl);
|
|
if (!macro)
|
|
return false;
|
|
|
|
return macro->getMacroRoles().contains(MacroRole::Expression);
|
|
}
|
|
|
|
static bool usesFeatureAttachedMacros(Decl *decl) {
|
|
auto macro = dyn_cast<MacroDecl>(decl);
|
|
if (!macro)
|
|
return false;
|
|
|
|
return static_cast<bool>(macro->getMacroRoles() & getAttachedMacroRoles());
|
|
}
|
|
|
|
static bool usesFeatureExtensionMacros(Decl *decl) {
|
|
auto macro = dyn_cast<MacroDecl>(decl);
|
|
if (!macro)
|
|
return false;
|
|
|
|
return macro->getMacroRoles().contains(MacroRole::Extension);
|
|
}
|
|
|
|
static bool usesFeatureMoveOnly(Decl *decl) {
|
|
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
|
|
if (auto *nominal = extension->getExtendedNominal())
|
|
return usesFeatureMoveOnly(nominal);
|
|
return false;
|
|
}
|
|
|
|
auto hasInverseInType = [&](Type type) {
|
|
return type.findIf([&](Type type) -> bool {
|
|
if (auto *NTD = type->getAnyNominal()) {
|
|
if (NTD->getAttrs().hasAttribute<MoveOnlyAttr>())
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
};
|
|
|
|
if (auto *TD = dyn_cast<TypeDecl>(decl)) {
|
|
if (auto *alias = dyn_cast<TypeAliasDecl>(TD))
|
|
return hasInverseInType(alias->getUnderlyingType());
|
|
|
|
if (auto *NTD = dyn_cast<NominalTypeDecl>(TD)) {
|
|
if (NTD->getAttrs().hasAttribute<MoveOnlyAttr>())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
|
|
return hasInverseInType(VD->getInterfaceType());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureMoveOnlyResilientTypes(Decl *decl) {
|
|
if (auto *nomDecl = dyn_cast<NominalTypeDecl>(decl))
|
|
return nomDecl->isResilient() && usesFeatureMoveOnly(decl);
|
|
return false;
|
|
}
|
|
|
|
static bool hasParameterPacks(Decl *decl) {
|
|
if (auto genericContext = decl->getAsGenericContext()) {
|
|
auto sig = genericContext->getGenericSignature();
|
|
if (llvm::any_of(sig.getGenericParams(),
|
|
[&](const GenericTypeParamType *GP) {
|
|
return GP->isParameterPack();
|
|
})) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// A declaration needs the $ParameterPacks feature if it declares a
|
|
/// generic parameter pack, or if its type references a generic nominal
|
|
/// or type alias which declares a generic parameter pack.
|
|
static bool usesFeatureParameterPacks(Decl *decl) {
|
|
if (hasParameterPacks(decl))
|
|
return true;
|
|
|
|
if (auto *valueDecl = dyn_cast<ValueDecl>(decl)) {
|
|
if (valueDecl->getInterfaceType().findIf([&](Type t) {
|
|
if (auto *alias = dyn_cast<TypeAliasType>(t.getPointer()))
|
|
return hasParameterPacks(alias->getDecl());
|
|
if (auto *nominal = t->getAnyNominal())
|
|
return hasParameterPacks(nominal);
|
|
|
|
return false;
|
|
})) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureLexicalLifetimes(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<EagerMoveAttr>() ||
|
|
decl->getAttrs().hasAttribute<NoEagerMoveAttr>() ||
|
|
decl->getAttrs().hasAttribute<LexicalLifetimesAttr>();
|
|
}
|
|
|
|
static bool usesFeatureFreestandingMacros(Decl *decl) {
|
|
auto macro = dyn_cast<MacroDecl>(decl);
|
|
if (!macro)
|
|
return false;
|
|
|
|
return macro->getMacroRoles().contains(MacroRole::Declaration);
|
|
}
|
|
|
|
static bool usesFeatureRetroactiveAttribute(Decl *decl) {
|
|
auto ext = dyn_cast<ExtensionDecl>(decl);
|
|
if (!ext)
|
|
return false;
|
|
|
|
return llvm::any_of(
|
|
ext->getInherited().getEntries(),
|
|
[](const InheritedEntry &entry) { return entry.isRetroactive(); });
|
|
}
|
|
|
|
static bool usesFeatureExtensionMacroAttr(Decl *decl) {
|
|
return usesFeatureExtensionMacros(decl);
|
|
}
|
|
|
|
static bool usesFeatureTypedThrows(Decl *decl) {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
|
|
return usesTypeMatching(decl, [](Type ty) {
|
|
if (auto funcType = ty->getAs<AnyFunctionType>())
|
|
return funcType->hasThrownError();
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureOptionalIsolatedParameters(Decl *decl) {
|
|
auto *value = dyn_cast<ValueDecl>(decl);
|
|
if (!value)
|
|
return false;
|
|
|
|
auto *paramList = getParameterList(value);
|
|
if (!paramList)
|
|
return false;
|
|
|
|
for (auto param : *paramList) {
|
|
if (param->isIsolated()) {
|
|
auto paramType = param->getInterfaceType();
|
|
return !paramType->getOptionalObjectType().isNull();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureExtern(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<ExternAttr>();
|
|
}
|
|
|
|
static bool usesFeatureAssociatedTypeImplements(Decl *decl) {
|
|
return isa<TypeDecl>(decl) && decl->getAttrs().hasAttribute<ImplementsAttr>();
|
|
}
|
|
|
|
static bool usesFeatureExpressionMacroDefaultArguments(Decl *decl) {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
|
|
for (auto param : *func->getParameters()) {
|
|
if (param->getDefaultArgumentKind() ==
|
|
DefaultArgumentKind::ExpressionMacro)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(BuiltinStoreRaw)
|
|
UNINTERESTING_FEATURE(BuiltinAddressOfRawLayout)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MARK: - Upcoming Features
|
|
// ----------------------------------------------------------------------------
|
|
|
|
UNINTERESTING_FEATURE(ConciseMagicFile)
|
|
UNINTERESTING_FEATURE(ForwardTrailingClosures)
|
|
UNINTERESTING_FEATURE(StrictConcurrency)
|
|
UNINTERESTING_FEATURE(BareSlashRegexLiterals)
|
|
UNINTERESTING_FEATURE(DeprecateApplicationMain)
|
|
|
|
static bool usesFeatureImportObjcForwardDeclarations(Decl *decl) {
|
|
ClangNode clangNode = decl->getClangNode();
|
|
if (!clangNode)
|
|
return false;
|
|
|
|
const clang::Decl *clangDecl = clangNode.getAsDecl();
|
|
if (!clangDecl)
|
|
return false;
|
|
|
|
if (auto objCInterfaceDecl = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl))
|
|
return !objCInterfaceDecl->hasDefinition();
|
|
|
|
if (auto objCProtocolDecl = dyn_cast<clang::ObjCProtocolDecl>(clangDecl))
|
|
return !objCProtocolDecl->hasDefinition();
|
|
|
|
return false;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(DisableOutwardActorInference)
|
|
UNINTERESTING_FEATURE(InternalImportsByDefault)
|
|
UNINTERESTING_FEATURE(IsolatedDefaultValues)
|
|
UNINTERESTING_FEATURE(GlobalConcurrency)
|
|
UNINTERESTING_FEATURE(FullTypedThrows)
|
|
UNINTERESTING_FEATURE(ExistentialAny)
|
|
UNINTERESTING_FEATURE(InferSendableFromCaptures)
|
|
UNINTERESTING_FEATURE(ImplicitOpenExistentials)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MARK: - Experimental Features
|
|
// ----------------------------------------------------------------------------
|
|
|
|
UNINTERESTING_FEATURE(StaticAssert)
|
|
UNINTERESTING_FEATURE(NamedOpaqueTypes)
|
|
UNINTERESTING_FEATURE(FlowSensitiveConcurrencyCaptures)
|
|
|
|
static bool usesFeatureCodeItemMacros(Decl *decl) {
|
|
auto macro = dyn_cast<MacroDecl>(decl);
|
|
if (!macro)
|
|
return false;
|
|
|
|
return macro->getMacroRoles().contains(MacroRole::CodeItem);
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(BodyMacros)
|
|
UNINTERESTING_FEATURE(TupleConformances)
|
|
|
|
static bool usesFeatureSymbolLinkageMarkers(Decl *decl) {
|
|
auto &attrs = decl->getAttrs();
|
|
return std::any_of(attrs.begin(), attrs.end(), [](auto *attr) {
|
|
if (isa<UsedAttr>(attr))
|
|
return true;
|
|
if (isa<SectionAttr>(attr))
|
|
return true;
|
|
return false;
|
|
});
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(LazyImmediate)
|
|
|
|
static bool usesFeatureMoveOnlyClasses(Decl *decl) {
|
|
return isa<ClassDecl>(decl) && usesFeatureMoveOnly(decl);
|
|
}
|
|
|
|
static bool usesFeatureNoImplicitCopy(Decl *decl) {
|
|
return decl->isNoImplicitCopy();
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(OldOwnershipOperatorSpellings)
|
|
|
|
static bool usesFeatureMoveOnlyEnumDeinits(Decl *decl) {
|
|
if (auto *ei = dyn_cast<EnumDecl>(decl)) {
|
|
return usesFeatureMoveOnly(ei) && ei->getValueTypeDestructor();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(MoveOnlyTuples)
|
|
|
|
// Partial consumption does not affect declarations directly.
|
|
UNINTERESTING_FEATURE(MoveOnlyPartialConsumption)
|
|
|
|
UNINTERESTING_FEATURE(MoveOnlyPartialReinitialization)
|
|
|
|
UNINTERESTING_FEATURE(OneWayClosureParameters)
|
|
|
|
static bool usesFeatureLayoutPrespecialization(Decl *decl) {
|
|
auto &attrs = decl->getAttrs();
|
|
return std::any_of(attrs.begin(), attrs.end(), [](auto *attr) {
|
|
if (auto *specialize = dyn_cast<SpecializeAttr>(attr)) {
|
|
return !specialize->getTypeErasedParams().empty();
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(AccessLevelOnImport)
|
|
UNINTERESTING_FEATURE(AllowNonResilientAccessInPackage)
|
|
UNINTERESTING_FEATURE(ClientBypassResilientAccessInPackage)
|
|
UNINTERESTING_FEATURE(LayoutStringValueWitnesses)
|
|
UNINTERESTING_FEATURE(LayoutStringValueWitnessesInstantiation)
|
|
UNINTERESTING_FEATURE(DifferentiableProgramming)
|
|
UNINTERESTING_FEATURE(ForwardModeDifferentiation)
|
|
UNINTERESTING_FEATURE(AdditiveArithmeticDerivedConformances)
|
|
UNINTERESTING_FEATURE(SendableCompletionHandlers)
|
|
UNINTERESTING_FEATURE(OpaqueTypeErasure)
|
|
UNINTERESTING_FEATURE(PackageCMO)
|
|
UNINTERESTING_FEATURE(ParserRoundTrip)
|
|
UNINTERESTING_FEATURE(ParserValidation)
|
|
UNINTERESTING_FEATURE(ParserDiagnostics)
|
|
UNINTERESTING_FEATURE(ImplicitSome)
|
|
UNINTERESTING_FEATURE(ParserASTGen)
|
|
UNINTERESTING_FEATURE(BuiltinMacros)
|
|
UNINTERESTING_FEATURE(ImportSymbolicCXXDecls)
|
|
UNINTERESTING_FEATURE(GenerateBindingsForThrowingFunctionsInCXX)
|
|
|
|
static bool usesFeatureReferenceBindings(Decl *decl) {
|
|
auto *vd = dyn_cast<VarDecl>(decl);
|
|
return vd && vd->getIntroducer() == VarDecl::Introducer::InOut;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(BuiltinModule)
|
|
UNINTERESTING_FEATURE(RegionBasedIsolation)
|
|
UNINTERESTING_FEATURE(PlaygroundExtendedCallbacks)
|
|
UNINTERESTING_FEATURE(ThenStatements)
|
|
UNINTERESTING_FEATURE(DoExpressions)
|
|
UNINTERESTING_FEATURE(ImplicitLastExprResults)
|
|
|
|
static bool usesFeatureRawLayout(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<RawLayoutAttr>();
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(Embedded)
|
|
UNINTERESTING_FEATURE(Volatile)
|
|
UNINTERESTING_FEATURE(SuppressedAssociatedTypes)
|
|
|
|
static bool disallowFeatureSuppression(StringRef featureName, Decl *decl);
|
|
|
|
static bool allSubstTypesAreCopyable(Type type, DeclContext *context) {
|
|
assert(type->getAnyNominal());
|
|
auto bgt = type->getAs<BoundGenericType>();
|
|
if (!bgt)
|
|
return false; // nothing is bound.
|
|
|
|
for (auto argInterfaceTy : bgt->getGenericArgs())
|
|
if (context->mapTypeIntoContext(argInterfaceTy)->isNoncopyable())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
|
|
if (decl->getAttrs().hasAttribute<PreInverseGenericsAttr>())
|
|
return true;
|
|
|
|
if (auto *valueDecl = dyn_cast<ValueDecl>(decl)) {
|
|
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
|
|
auto reqSig = proto->getRequirementSignature();
|
|
|
|
SmallVector<Requirement, 2> reqs;
|
|
SmallVector<InverseRequirement, 2> inverses;
|
|
reqSig.getRequirementsWithInverses(proto, reqs, inverses);
|
|
if (!inverses.empty())
|
|
return true;
|
|
}
|
|
|
|
if (isa<AbstractFunctionDecl>(valueDecl) ||
|
|
isa<AbstractStorageDecl>(valueDecl)) {
|
|
auto *context = decl->getInnermostDeclContext();
|
|
auto usesFeature = valueDecl->getInterfaceType().findIf(
|
|
[&](Type type) -> bool {
|
|
auto *nominalDecl = type->getAnyNominal();
|
|
if (!nominalDecl || !isa<StructDecl, EnumDecl, ClassDecl>(nominalDecl))
|
|
return false;
|
|
|
|
if (!usesFeatureNoncopyableGenerics(nominalDecl))
|
|
return false;
|
|
|
|
// If we only _refer_ to a TypeDecl that uses NoncopyableGenerics,
|
|
// and a suppressed version of that decl is in the interface, and
|
|
// if we only substitute Copyable types for the generic parameters,
|
|
// then we can say this decl is not "using" the feature such that
|
|
// a feature guard is required. In other words, this reference to the
|
|
// type will always be valid, regardless of whether the feature is
|
|
// enabled or not. (rdar://127389991)
|
|
if (!disallowFeatureSuppression("NoncopyableGenerics", nominalDecl)
|
|
&& allSubstTypesAreCopyable(type, context)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
if (usesFeature)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (auto *ext = dyn_cast<ExtensionDecl>(decl)) {
|
|
if (auto *nominal = ext->getExtendedNominal())
|
|
if (usesFeatureNoncopyableGenerics(nominal))
|
|
return true;
|
|
}
|
|
|
|
SmallVector<Requirement, 2> reqs;
|
|
SmallVector<InverseRequirement, 2> inverseReqs;
|
|
|
|
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
|
|
|
|
// We have baked-in support for Sendable not needing to state inverses
|
|
// in its inheritance clause within interface files. So, it technically is
|
|
// not using the feature with respect to the concerns of an interface file.
|
|
if (proto->isSpecificProtocol(KnownProtocolKind::Sendable))
|
|
return false;
|
|
|
|
proto->getRequirementSignature().getRequirementsWithInverses(
|
|
proto, reqs, inverseReqs);
|
|
} else if (auto *genCtx = decl->getAsGenericContext()) {
|
|
if (auto genericSig = genCtx->getGenericSignature())
|
|
genericSig->getRequirementsWithInverses(reqs, inverseReqs);
|
|
}
|
|
|
|
return !inverseReqs.empty();
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(NoncopyableGenerics2)
|
|
|
|
static bool usesFeatureStructLetDestructuring(Decl *decl) {
|
|
auto sd = dyn_cast<StructDecl>(decl);
|
|
if (!sd)
|
|
return false;
|
|
|
|
for (auto member : sd->getStoredProperties()) {
|
|
if (!member->isLet())
|
|
continue;
|
|
|
|
auto init = member->getParentPattern();
|
|
if (!init)
|
|
continue;
|
|
|
|
if (!init->getSingleVar())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureNonescapableTypes(Decl *decl) {
|
|
if (decl->getAttrs().hasAttribute<NonEscapableAttr>() ||
|
|
decl->getAttrs().hasAttribute<UnsafeNonEscapableResultAttr>()) {
|
|
return true;
|
|
}
|
|
auto *fd = dyn_cast<FuncDecl>(decl);
|
|
if (fd && fd->getAttrs().getAttribute(DeclAttrKind::ResultDependsOnSelf)) {
|
|
return true;
|
|
}
|
|
auto *pd = dyn_cast<ParamDecl>(decl);
|
|
if (pd && pd->hasResultDependsOn()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureStaticExclusiveOnly(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>();
|
|
}
|
|
|
|
static bool usesFeatureExtractConstantsFromMembers(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<ExtractConstantsFromMembersAttr>();
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(BitwiseCopyable)
|
|
UNINTERESTING_FEATURE(FixedArrays)
|
|
UNINTERESTING_FEATURE(GroupActorErrors)
|
|
|
|
static bool usesFeatureTransferringArgsAndResults(Decl *decl) {
|
|
auto functionTypeUsesTransferring = [](Decl *decl) {
|
|
return usesTypeMatching(decl, [](Type type) {
|
|
auto fnType = type->getAs<AnyFunctionType>();
|
|
if (!fnType)
|
|
return false;
|
|
|
|
if (fnType->hasExtInfo() && fnType->hasSendingResult())
|
|
return true;
|
|
|
|
return llvm::any_of(fnType->getParams(),
|
|
[](AnyFunctionType::Param param) {
|
|
return param.getParameterFlags().isSending();
|
|
});
|
|
});
|
|
};
|
|
|
|
if (auto *pd = dyn_cast<ParamDecl>(decl)) {
|
|
if (pd->isSending()) {
|
|
return true;
|
|
}
|
|
|
|
if (functionTypeUsesTransferring(pd))
|
|
return true;
|
|
}
|
|
|
|
if (auto *fDecl = dyn_cast<FuncDecl>(decl)) {
|
|
// First check for param decl results.
|
|
if (llvm::any_of(fDecl->getParameters()->getArray(), [](ParamDecl *pd) {
|
|
return usesFeatureTransferringArgsAndResults(pd);
|
|
}))
|
|
return true;
|
|
if (functionTypeUsesTransferring(decl))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(DynamicActorIsolation)
|
|
|
|
UNINTERESTING_FEATURE(NonfrozenEnumExhaustivity)
|
|
|
|
UNINTERESTING_FEATURE(BorrowingSwitch)
|
|
|
|
UNINTERESTING_FEATURE(ClosureIsolation)
|
|
|
|
static bool usesFeatureConformanceSuppression(Decl *decl) {
|
|
auto *nominal = dyn_cast<NominalTypeDecl>(decl);
|
|
if (!nominal)
|
|
return false;
|
|
|
|
auto inherited = InheritedTypes(nominal);
|
|
for (auto index : indices(inherited.getEntries())) {
|
|
// Ensure that InheritedTypeRequest has set the isSuppressed bit if
|
|
// appropriate.
|
|
auto resolvedTy = inherited.getResolvedType(index);
|
|
(void)resolvedTy;
|
|
|
|
auto entry = inherited.getEntry(index);
|
|
|
|
if (!entry.isSuppressed())
|
|
continue;
|
|
|
|
auto ty = entry.getType();
|
|
|
|
if (!ty)
|
|
continue;
|
|
|
|
auto kp = ty->getKnownProtocol();
|
|
if (!kp)
|
|
continue;
|
|
|
|
auto rpk = getRepressibleProtocolKind(*kp);
|
|
if (!rpk)
|
|
continue;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureBitwiseCopyable2(Decl *decl) {
|
|
if (!decl->getModuleContext()->isStdlibModule()) {
|
|
return false;
|
|
}
|
|
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
|
|
return proto->getNameStr() == "BitwiseCopyable";
|
|
}
|
|
if (auto *typealias = dyn_cast<TypeAliasDecl>(decl)) {
|
|
return typealias->getNameStr() == "_BitwiseCopyable";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool usesFeatureIsolatedAny(Decl *decl) {
|
|
return usesTypeMatching(decl, [](Type type) {
|
|
if (auto fnType = type->getAs<AnyFunctionType>()) {
|
|
return fnType->getIsolation().isErased();
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(MemberImportVisibility)
|
|
UNINTERESTING_FEATURE(IsolatedAny2)
|
|
|
|
static bool usesFeatureGlobalActorIsolatedTypesUsability(Decl *decl) {
|
|
return false;
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(ObjCImplementation)
|
|
UNINTERESTING_FEATURE(ObjCImplementationWithResilientStorage)
|
|
UNINTERESTING_FEATURE(CImplementation)
|
|
|
|
static bool usesFeatureSensitive(Decl *decl) {
|
|
return decl->getAttrs().hasAttribute<SensitiveAttr>();
|
|
}
|
|
|
|
UNINTERESTING_FEATURE(DebugDescriptionMacro)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MARK: - FeatureSet
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureSet::collectRequiredFeature(Feature feature,
|
|
InsertOrRemove operation) {
|
|
required.insertOrRemove(feature, operation == Insert);
|
|
}
|
|
|
|
void FeatureSet::collectSuppressibleFeature(Feature feature,
|
|
InsertOrRemove operation) {
|
|
suppressible.insertOrRemove(numFeatures() - size_t(feature),
|
|
operation == Insert);
|
|
}
|
|
|
|
static bool hasFeatureSuppressionAttribute(Decl *decl, StringRef featureName,
|
|
bool inverted) {
|
|
auto attr = decl->getAttrs().getAttribute<AllowFeatureSuppressionAttr>();
|
|
if (!attr)
|
|
return false;
|
|
|
|
if (attr->getInverted() != inverted)
|
|
return false;
|
|
|
|
for (auto suppressedFeature : attr->getSuppressedFeatures()) {
|
|
if (suppressedFeature.is(featureName))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool disallowFeatureSuppression(StringRef featureName, Decl *decl) {
|
|
return hasFeatureSuppressionAttribute(decl, featureName, true);
|
|
}
|
|
|
|
static bool allowFeatureSuppression(StringRef featureName, Decl *decl) {
|
|
return hasFeatureSuppressionAttribute(decl, featureName, false);
|
|
}
|
|
|
|
/// Go through all the features used by the given declaration and
|
|
/// either add or remove them to this set.
|
|
void FeatureSet::collectFeaturesUsed(Decl *decl, InsertOrRemove operation) {
|
|
// Go through each of the features, checking whether the
|
|
// declaration uses that feature.
|
|
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
|
|
if (usesFeature##FeatureName(decl)) \
|
|
collectRequiredFeature(Feature::FeatureName, operation);
|
|
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
|
|
if (usesFeature##FeatureName(decl)) { \
|
|
if (disallowFeatureSuppression(#FeatureName, decl)) \
|
|
collectRequiredFeature(Feature::FeatureName, operation); \
|
|
else \
|
|
collectSuppressibleFeature(Feature::FeatureName, operation); \
|
|
}
|
|
#define CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
|
|
if (usesFeature##FeatureName(decl)) { \
|
|
if (allowFeatureSuppression(#FeatureName, decl)) \
|
|
collectSuppressibleFeature(Feature::FeatureName, operation); \
|
|
else \
|
|
collectRequiredFeature(Feature::FeatureName, operation); \
|
|
}
|
|
#include "swift/Basic/Features.def"
|
|
}
|
|
|
|
FeatureSet swift::getUniqueFeaturesUsed(Decl *decl) {
|
|
// Add all the features used by this declaration.
|
|
FeatureSet features;
|
|
features.collectFeaturesUsed(decl, FeatureSet::Insert);
|
|
|
|
// Remove all the features used by all enclosing declarations.
|
|
Decl *enclosingDecl = decl;
|
|
while (!features.empty()) {
|
|
// Find the next outermost enclosing declaration.
|
|
if (auto accessor = dyn_cast<AccessorDecl>(enclosingDecl))
|
|
enclosingDecl = accessor->getStorage();
|
|
else
|
|
enclosingDecl = enclosingDecl->getDeclContext()->getAsDecl();
|
|
if (!enclosingDecl)
|
|
break;
|
|
|
|
features.collectFeaturesUsed(enclosingDecl, FeatureSet::Remove);
|
|
}
|
|
|
|
return features;
|
|
}
|