Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,44 @@ class TypeDeclsFromWhereClauseRequest :
ExtensionDecl *ext) const;
};

/// The owning decl for a given custom attribute, or a DeclContext for a
/// custom attribute in e.g a closure or inheritance clause.
class CustomAttrOwner final {
llvm::PointerUnion<const Decl *, DeclContext *> Owner;

public:
CustomAttrOwner() : Owner(nullptr) {}
CustomAttrOwner(const Decl *D) : Owner(D) {}
CustomAttrOwner(DeclContext *DC) : Owner(DC) {}

const Decl *getAsDecl() const {
return Owner.dyn_cast<const Decl *>();
}

DeclContext *getDeclContext() const;

friend bool operator==(const CustomAttrOwner &lhs,
const CustomAttrOwner &rhs) {
return lhs.Owner == rhs.Owner;
}

friend bool operator!=(const CustomAttrOwner &lhs,
const CustomAttrOwner &rhs) {
return !(lhs == rhs);
}

friend hash_code hash_value(const CustomAttrOwner &owner) {
return llvm::hash_value(owner.Owner);
}
};

void simple_display(llvm::raw_ostream &out, const CustomAttrOwner &owner);

/// Request the nominal type declaration to which the given custom
/// attribute refers.
class CustomAttrNominalRequest :
public SimpleRequest<CustomAttrNominalRequest,
NominalTypeDecl *(CustomAttr *, DeclContext *),
NominalTypeDecl *(CustomAttr *, CustomAttrOwner),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -362,7 +395,7 @@ class CustomAttrNominalRequest :

// Evaluation.
NominalTypeDecl *
evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const;
evaluate(Evaluator &evaluator, CustomAttr *attr, CustomAttrOwner owner) const;

public:
// Caching
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,10 @@ EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false)
/// Enable @_lifetime attribute
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)

/// Excludes 'private' properties with initial values from the memberwise
/// initializer.
EXPERIMENTAL_FEATURE(ExcludePrivateFromMemberwiseInit, false)

/// Allow macro based aliases to be imported into Swift
EXPERIMENTAL_FEATURE(ImportMacroAliases, true)

Expand Down
25 changes: 18 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ Type Decl::getResolvedCustomAttrType(CustomAttr *attr) const {

auto dc = getDeclContext();
auto *nominal = evaluateOrDefault(
getASTContext().evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
getASTContext().evaluator, CustomAttrNominalRequest{attr, this}, nullptr);
if (!nominal)
return Type();

Expand Down Expand Up @@ -8431,10 +8431,22 @@ bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const {
// If this is a stored property, and not a backing property in a case where
// we only want to see the declared properties, it can be memberwise
// initialized.
if (hasStorage() && preferDeclaredProperties &&
isBackingStorageForDeclaredProperty(this))
return false;

if (hasStorage()) {
if (isBackingStorageForDeclaredProperty(this)) {
if (preferDeclaredProperties)
return false;
} else if (getASTContext().LangOpts.hasFeature(Feature::ExcludePrivateFromMemberwiseInit)) {
// Private variables with initial values are never memberwise initialized.
if (getFormalAccess() == AccessLevel::Private) {
if (hasInitialValue())
return false;
if (auto *PBD = getParentPatternBinding()) {
if (PBD->isDefaultInitializable())
return false;
}
}
}
}
// If this is a computed property with `init` accessor, it's
// memberwise initializable when it could be used to initialize
// other stored properties.
Expand Down Expand Up @@ -8696,10 +8708,9 @@ VarDecl::getAttachedPropertyWrapperTypeInfo(unsigned i) const {
return PropertyWrapperTypeInfo();

auto attr = attrs[i];
auto dc = getDeclContext();
ASTContext &ctx = getASTContext();
nominal = evaluateOrDefault(
ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
ctx.evaluator, CustomAttrNominalRequest{attr, this}, nullptr);
}

if (!nominal)
Expand Down
1 change: 1 addition & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ UNINTERESTING_FEATURE(NonisolatedNonsendingByDefault)
UNINTERESTING_FEATURE(KeyPathWithMethodMembers)
UNINTERESTING_FEATURE(ImportMacroAliases)
UNINTERESTING_FEATURE(NoExplicitNonIsolated)
UNINTERESTING_FEATURE(ExcludePrivateFromMemberwiseInit)

// TODO: Return true for inlinable function bodies with module selectors in them
UNINTERESTING_FEATURE(ModuleSelector)
Expand Down
29 changes: 27 additions & 2 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3961,9 +3961,24 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
parsedGenericParams->getRAngleLoc());
}

static bool shouldPreferPropertyWrapperOverMacro(CustomAttrOwner owner) {
// If we have a VarDecl in a local context, prefer to look for a property
// wrapper if one exists. This is necessary since we don' properly support
// peer declarations in local contexts, so want to use a property wrapper if
// one exists.
if (auto *D = dyn_cast_or_null<VarDecl>(owner.getAsDecl())) {
if (!isa<ParamDecl>(D) && D->getDeclContext()->isLocalContext())
return true;
}
return false;
}

NominalTypeDecl *
CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
CustomAttr *attr, DeclContext *dc) const {
CustomAttr *attr,
CustomAttrOwner owner) const {
auto *dc = owner.getDeclContext();

// Look for names at module scope, so we don't trigger name lookup for
// nested scopes. At this point, we're looking to see whether there are
// any suitable macros.
Expand All @@ -3972,7 +3987,8 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
auto macroName = (macro) ? macro->getNameRef() : DeclNameRef();
auto macros = namelookup::lookupMacros(dc, moduleName, macroName,
getAttachedMacroRoles());
if (!macros.empty())
auto shouldPreferPropWrapper = shouldPreferPropertyWrapperOverMacro(owner);
if (!macros.empty() && !shouldPreferPropWrapper)
return nullptr;

// Find the types referenced by the custom attribute.
Expand All @@ -3992,6 +4008,15 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
auto nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls.first,
ResolveToNominalOptions(),
modulesFound, anyObject);
if (shouldPreferPropWrapper) {
auto hasPropWrapper = llvm::any_of(nominals, [](NominalTypeDecl *NTD) {
return NTD->getAttrs().hasAttribute<PropertyWrapperAttr>();
});
if (!macros.empty() && !hasPropWrapper)
return nullptr;

ASSERT(macros.empty() && "now preferring property wrapper");
}
if (nominals.size() == 1 && !isa<ProtocolDecl>(nominals.front()))
return nominals.front();

Expand Down
20 changes: 20 additions & 0 deletions lib/AST/NameLookupRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,26 @@ void ExtendedNominalRequest::writeDependencySink(
tracker.addPotentialMember(value);
}

//----------------------------------------------------------------------------//
// CustomAttrOwner
//----------------------------------------------------------------------------//

DeclContext *CustomAttrOwner::getDeclContext() const {
if (auto *D = getAsDecl())
return D->getDeclContext();

return Owner.dyn_cast<DeclContext *>();
}

void swift::simple_display(llvm::raw_ostream &out,
const CustomAttrOwner &owner) {
if (auto *D = owner.getAsDecl()) {
simple_display(out, D);
} else {
simple_display(out, owner.getDeclContext());
}
}

//----------------------------------------------------------------------------//
// Destructor computation.
//----------------------------------------------------------------------------//
Expand Down
2 changes: 2 additions & 0 deletions lib/Basic/LangOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ LangOptions::LangOptions() {
#define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#include "swift/Basic/Features.def"

enableFeature(Feature::ExcludePrivateFromMemberwiseInit);

// Special case: remove macro support if the compiler wasn't built with a
// host Swift.
#if !SWIFT_BUILD_SWIFT_SYNTAX
Expand Down
5 changes: 2 additions & 3 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4588,7 +4588,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {

// Figure out which nominal declaration this custom attribute refers to.
auto *nominal = evaluateOrDefault(
Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
Ctx.evaluator, CustomAttrNominalRequest{attr, D}, nullptr);

if (!nominal) {
if (attr->isInvalid())
Expand Down Expand Up @@ -8742,8 +8742,7 @@ static void forEachCustomAttribute(
auto *mutableAttr = const_cast<CustomAttr *>(attr);

auto *nominal = evaluateOrDefault(
ctx.evaluator,
CustomAttrNominalRequest{mutableAttr, decl->getDeclContext()}, nullptr);
ctx.evaluator, CustomAttrNominalRequest{mutableAttr, decl}, nullptr);
if (!nominal)
continue;

Expand Down
14 changes: 7 additions & 7 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,16 +311,16 @@ VarDecl *GlobalActorInstanceRequest::evaluate(
}

std::optional<std::pair<CustomAttr *, NominalTypeDecl *>>
swift::checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc,
swift::checkGlobalActorAttributes(SourceLoc loc, CustomAttrOwner owner,
ArrayRef<CustomAttr *> attrs) {
ASTContext &ctx = dc->getASTContext();
ASTContext &ctx = owner.getDeclContext()->getASTContext();

CustomAttr *globalActorAttr = nullptr;
NominalTypeDecl *globalActorNominal = nullptr;
for (auto attr : attrs) {
// Figure out which nominal declaration this custom attribute refers to.
auto *nominal = evaluateOrDefault(ctx.evaluator,
CustomAttrNominalRequest{attr, dc},
CustomAttrNominalRequest{attr, owner},
nullptr);

if (!nominal)
Expand Down Expand Up @@ -352,11 +352,11 @@ std::optional<std::pair<CustomAttr *, NominalTypeDecl *>>
GlobalActorAttributeRequest::evaluate(
Evaluator &evaluator,
llvm::PointerUnion<Decl *, ClosureExpr *> subject) const {
DeclContext *dc = nullptr;
CustomAttrOwner owner;
DeclAttributes *declAttrs = nullptr;
SourceLoc loc;
if (auto decl = subject.dyn_cast<Decl *>()) {
dc = decl->getDeclContext();
owner = decl;
declAttrs = &decl->getAttrs();
// HACK: `getLoc`, when querying the attr from a serialized decl,
// depending on deserialization order, may launch into arbitrary
Expand All @@ -372,7 +372,7 @@ GlobalActorAttributeRequest::evaluate(
loc = decl->getLoc(/* SerializedOK */ false);
} else {
auto closure = cast<ClosureExpr *>(subject);
dc = closure;
owner = closure;
declAttrs = &closure->getAttrs();
loc = closure->getLoc();
}
Expand All @@ -385,7 +385,7 @@ GlobalActorAttributeRequest::evaluate(
}

// Look for a global actor attribute.
auto result = checkGlobalActorAttributes(loc, dc, attrs);
auto result = checkGlobalActorAttributes(loc, owner, attrs);
if (!result)
return std::nullopt;

Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/TypeCheckConcurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace swift {

class AbstractFunctionDecl;
class ConstructorDecl;
class CustomAttrOwner;
class ActorIsolation;
class AnyFunctionType;
class ASTContext;
Expand Down Expand Up @@ -609,7 +610,7 @@ bool diagnoseSendabilityErrorBasedOn(
/// and perform any necessary resolution and diagnostics, returning the
/// global actor attribute and type it refers to (or \c std::nullopt).
std::optional<std::pair<CustomAttr *, NominalTypeDecl *>>
checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc,
checkGlobalActorAttributes(SourceLoc loc, CustomAttrOwner owner,
ArrayRef<CustomAttr *> attrs);

/// Get the explicit global actor specified for a closure.
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckPropertyWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
auto mutableAttr = const_cast<CustomAttr *>(attr);
// Figure out which nominal declaration this custom attribute refers to.
auto *nominal = evaluateOrDefault(
ctx.evaluator, CustomAttrNominalRequest{mutableAttr, dc}, nullptr);
ctx.evaluator, CustomAttrNominalRequest{mutableAttr, var}, nullptr);

// If we didn't find a nominal type with a @propertyWrapper attribute,
// skip this custom attribute.
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckRequestFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ AttachedResultBuilderRequest::evaluate(Evaluator &evaluator,
auto mutableAttr = const_cast<CustomAttr *>(attr);
// Figure out which nominal declaration this custom attribute refers to.
auto *nominal = evaluateOrDefault(ctx.evaluator,
CustomAttrNominalRequest{mutableAttr, dc},
CustomAttrNominalRequest{mutableAttr, decl},
nullptr);

if (!nominal)
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/PackExpansionMatcher.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
Expand Down
1 change: 0 additions & 1 deletion test/attr/accessibility_print.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public struct BE_PublicStructPrivateMembers {
// CHECK: private{{(\*/)?}} var x
private var x = 0
// CHECK: internal init()
// CHECK: private init(x: Int = 0)
} // CHECK: {{^[}]}}

// CHECK-LABEL: {{^}}fileprivate{{(\*/)?}} struct BF_FilePrivateStruct {
Expand Down