diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 8b032aae390e0..8163c52f18165 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -852,10 +852,11 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext, BridgedStringRef cName, bool underscored); -SWIFT_NAME( - "BridgedCustomAttr.createParsed(_:atLoc:type:initContext:argumentList:)") +SWIFT_NAME("BridgedCustomAttr.createParsed(atLoc:type:declContext:initContext:" + "argumentList:)") BridgedCustomAttr BridgedCustomAttr_createParsed( - BridgedASTContext cContext, swift::SourceLoc atLoc, BridgedTypeRepr cType, + swift::SourceLoc atLoc, BridgedTypeRepr cType, + BridgedDeclContext cDeclContext, BridgedNullableCustomAttributeInitializer cInitContext, BridgedNullableArgumentList cArgumentList); diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 5bf4de457bab6..944111a3be6d3 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -68,6 +68,7 @@ class GenericFunctionType; class LazyConformanceLoader; class LazyMemberLoader; class ModuleDecl; +class NominalTypeDecl; class PatternBindingInitializer; class TrailingWhereClause; class TypeExpr; @@ -2272,27 +2273,46 @@ class ClangImporterSynthesizedTypeAttr : public DeclAttribute { } }; +/// 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 Owner; + +public: + CustomAttrOwner() : Owner(nullptr) {} + CustomAttrOwner(Decl *D) : Owner(D) {} + CustomAttrOwner(DeclContext *DC) : Owner(DC) {} + + /// If the owner is a declaration, returns it, \c nullptr otherwise. + Decl *getAsDecl() const { return Owner.dyn_cast(); } + + /// Retrieve the DeclContext for the CustomAttr. + DeclContext *getDeclContext() const; +}; + /// Defines a custom attribute. class CustomAttr final : public DeclAttribute { TypeExpr *typeExpr; ArgumentList *argList; + CustomAttrOwner owner; CustomAttributeInitializer *initContext; Expr *semanticInit = nullptr; mutable unsigned isArgUnsafeBit : 1; CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type, - CustomAttributeInitializer *initContext, ArgumentList *argList, - bool implicit); + CustomAttrOwner owner, CustomAttributeInitializer *initContext, + ArgumentList *argList, bool implicit); public: static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, - bool implicit = false) { - return create(ctx, atLoc, type, /*initContext*/ nullptr, + CustomAttrOwner owner, bool implicit = false) { + return create(ctx, atLoc, type, owner, /*initContext*/ nullptr, /*argList*/ nullptr, implicit); } static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, + CustomAttrOwner owner, CustomAttributeInitializer *initContext, ArgumentList *argList, bool implicit = false); @@ -2300,6 +2320,16 @@ class CustomAttr final : public DeclAttribute { TypeRepr *getTypeRepr() const; Type getType() const; + /// Retrieve the Decl or DeclContext owner for the attribute. + CustomAttrOwner getOwner() const { return owner; } + void setOwner(CustomAttrOwner newOwner) { owner = newOwner; } + + ASTContext &getASTContext() const; + + /// Retrieve the NominalTypeDecl the CustomAttr refers to, or \c nullptr if + /// it doesn't refer to one (which can be the case for e.g macro attrs). + NominalTypeDecl *getNominalDecl() const; + /// Destructure an attribute's type repr for a macro reference. /// /// For a 1-level member type repr whose base and member are both identifier @@ -2336,7 +2366,8 @@ class CustomAttr final : public DeclAttribute { CustomAttr *clone(ASTContext &ctx) const { assert(argList == nullptr && "Cannot clone custom attribute with an argument list"); - return create(ctx, AtLoc, getTypeExpr(), initContext, argList, isImplicit()); + return create(ctx, AtLoc, getTypeExpr(), owner, initContext, argList, + isImplicit()); } bool canClone() const { return argList == nullptr; } diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 0ce342507dfc7..061355b4f6eb7 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -350,10 +350,10 @@ class TypeDeclsFromWhereClauseRequest : /// Request the nominal type declaration to which the given custom /// attribute refers. -class CustomAttrNominalRequest : - public SimpleRequest { +class CustomAttrNominalRequest + : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -361,8 +361,7 @@ class CustomAttrNominalRequest : friend SimpleRequest; // Evaluation. - NominalTypeDecl * - evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const; + NominalTypeDecl *evaluate(Evaluator &evaluator, CustomAttr *attr) const; public: // Caching diff --git a/include/swift/AST/NameLookupTypeIDZone.def b/include/swift/AST/NameLookupTypeIDZone.def index 584e39f862771..dd302064e1f3a 100644 --- a/include/swift/AST/NameLookupTypeIDZone.def +++ b/include/swift/AST/NameLookupTypeIDZone.def @@ -19,8 +19,7 @@ SWIFT_REQUEST(NameLookup, AnyObjectLookupRequest, QualifiedLookupResult(const DeclContext *, DeclName, NLOptions), Uncached, NoLocationInfo) SWIFT_REQUEST(NameLookup, CustomAttrNominalRequest, - NominalTypeDecl *(CustomAttr *, DeclContext *), Cached, - NoLocationInfo) + NominalTypeDecl *(CustomAttr *), Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, DirectLookupRequest, TinyPtrVector(DirectLookupDescriptor), Uncached, NoLocationInfo) diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index ece312e6fa699..52d6373eca575 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -3053,16 +3053,26 @@ bool ImplementsAttr::isEquivalent(const ImplementsAttr *other, && getProtocol(DC) == other->getProtocol(DC); } +DeclContext *CustomAttrOwner::getDeclContext() const { + ASSERT(!Owner.isNull()); + if (auto *D = getAsDecl()) + return D->getDeclContext(); + + return Owner.dyn_cast(); +} + CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type, + CustomAttrOwner owner, CustomAttributeInitializer *initContext, ArgumentList *argList, bool implicit) : DeclAttribute(DeclAttrKind::Custom, atLoc, range, implicit), - typeExpr(type), argList(argList), initContext(initContext) { + typeExpr(type), argList(argList), owner(owner), initContext(initContext) { assert(type); isArgUnsafeBit = false; } CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, + CustomAttrOwner owner, CustomAttributeInitializer *initContext, ArgumentList *argList, bool implicit) { assert(type); @@ -3071,7 +3081,7 @@ CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, range.End = argList->getEndLoc(); return new (ctx) - CustomAttr(atLoc, range, type, initContext, argList, implicit); + CustomAttr(atLoc, range, type, owner, initContext, argList, implicit); } std::pair @@ -3091,6 +3101,16 @@ CustomAttr::destructureMacroRef() { return {nullptr, nullptr}; } +ASTContext &CustomAttr::getASTContext() const { + return getOwner().getDeclContext()->getASTContext(); +} + +NominalTypeDecl *CustomAttr::getNominalDecl() const { + auto &eval = getASTContext().evaluator; + auto *mutThis = const_cast(this); + return evaluateOrDefault(eval, CustomAttrNominalRequest{mutThis}, nullptr); +} + TypeRepr *CustomAttr::getTypeRepr() const { return typeExpr->getTypeRepr(); } Type CustomAttr::getType() const { return typeExpr->getInstanceType(); } diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 0803748c5d9e2..1656275b6d158 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -197,12 +197,15 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext, } BridgedCustomAttr BridgedCustomAttr_createParsed( - BridgedASTContext cContext, SourceLoc atLoc, BridgedTypeRepr cType, + SourceLoc atLoc, BridgedTypeRepr cType, BridgedDeclContext cDeclContext, BridgedNullableCustomAttributeInitializer cInitContext, BridgedNullableArgumentList cArgumentList) { - ASTContext &context = cContext.unbridged(); + DeclContext *DC = cDeclContext.unbridged(); + ASTContext &context = DC->getASTContext(); + // Note we set a DeclContext as the owner, which we'll change to the attached + // Decl if necessary when attaching the attributes. return CustomAttr::create( - context, atLoc, new (context) TypeExpr(cType.unbridged()), + context, atLoc, new (context) TypeExpr(cType.unbridged()), /*owner*/ DC, cInitContext.unbridged(), cArgumentList.unbridged()); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3a92a94226690..261cc3f0d49a4 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -442,6 +442,8 @@ void Decl::attachParsedAttrs(DeclAttributes attrs) { attr->setOriginalDeclaration(this); for (auto attr : attrs.getAttributes()) recordABIAttr(attr); + for (auto *attr : attrs.getAttributes()) + attr->setOwner(this); // @implementation requires an explicit @objc attribute, but // @_objcImplementation didn't. Insert one if necessary. @@ -573,8 +575,7 @@ Type Decl::getResolvedCustomAttrType(CustomAttr *attr) const { return ty; auto dc = getDeclContext(); - auto *nominal = evaluateOrDefault( - getASTContext().evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); + auto *nominal = attr->getNominalDecl(); if (!nominal) return Type(); @@ -8703,11 +8704,7 @@ VarDecl::getAttachedPropertyWrapperTypeInfo(unsigned i) const { if (i >= attrs.size()) return PropertyWrapperTypeInfo(); - auto attr = attrs[i]; - auto dc = getDeclContext(); - ASTContext &ctx = getASTContext(); - nominal = evaluateOrDefault( - ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); + nominal = attrs[i]->getNominalDecl(); } if (!nominal) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 99a0310aa1c58..393e056d207df 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -3971,18 +3971,34 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c parsedGenericParams->getRAngleLoc()); } -NominalTypeDecl * -CustomAttrNominalRequest::evaluate(Evaluator &evaluator, - CustomAttr *attr, DeclContext *dc) const { +static bool shouldPreferPropertyWrapperOverMacro(CustomAttrOwner owner) { + // If we have a VarDecl in a local context, prefer to use a property wrapper + // if one exists. This is necessary since we don't properly support peer + // declarations in local contexts, so want to use a property wrapper if one + // exists. + if (auto *D = dyn_cast_or_null(owner.getAsDecl())) { + if (D->getDeclContext()->isLocalContext()) + return true; + } + return false; +} + +NominalTypeDecl *CustomAttrNominalRequest::evaluate(Evaluator &evaluator, + CustomAttr *attr) const { + auto owner = attr->getOwner(); + 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. + // any suitable macros. If we're preferring property wrappers we wait to see + // if any property wrappers are in scope before returning. auto [module, macro] = attr->destructureMacroRef(); auto moduleName = (module) ? module->getNameRef() : DeclNameRef(); 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. @@ -4002,6 +4018,15 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, auto nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls.first, ResolveToNominalOptions(), modulesFound, anyObject); + // If we're preferring property wrappers and found a suitable match, continue. + // Otherwise we can bail and resolve as a macro. + if (shouldPreferPropWrapper) { + auto hasPropWrapper = llvm::any_of(nominals, [](NominalTypeDecl *NTD) { + return NTD->getAttrs().hasAttribute(); + }); + if (!macros.empty() && !hasPropWrapper) + return nullptr; + } if (nominals.size() == 1 && !isa(nominals.front())) return nominals.front(); diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index e77859ba11836..8316eb5cb0f4c 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -2285,9 +2285,9 @@ extension ASTGenVisitor { } return .createParsed( - self.ctx, atLoc: self.generateSourceLoc(node.atSign), type: type, + declContext: declContext, initContext: initContext.asNullable, argumentList: argList.asNullable ) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 60cc7c87fbd32..9b07bc613b5c2 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -6262,8 +6262,8 @@ void cloneImportedAttributes(ValueDecl *fromDecl, ValueDecl* toDecl) { case DeclAttrKind::Custom: { CustomAttr *cAttr = cast(attr); attrs.add(CustomAttr::create(context, SourceLoc(), cAttr->getTypeExpr(), - cAttr->getInitContext(), cAttr->getArgs(), - true)); + /*owner*/ toDecl, cAttr->getInitContext(), + cAttr->getArgs(), /*implicit*/ true)); break; } case DeclAttrKind::DiscardableResult: { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index f2db92c2f1100..cea5f5aa1d73d 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -8885,7 +8885,10 @@ void ClangImporter::Implementation::importNontrivialAttribute( SmallVector attrs(decl->getAttrs().begin(), decl->getAttrs().end()); for (auto attr : attrs) { - MappedDecl->getAttrs().add(cached ? attr->clone(SwiftContext) : attr); + auto *newAttr = cached ? attr->clone(SwiftContext) : attr; + if (auto *CA = dyn_cast(newAttr)) + CA->setOwner(MappedDecl); + MappedDecl->getAttrs().add(newAttr); } } break; @@ -8933,7 +8936,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) { if (Type mainActorType = SwiftContext.getMainActorType()) { auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext); - auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr); + auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr, + /*owner*/ MappedDecl); MappedDecl->getAttrs().add(attr); seenMainActorAttr = swiftAttr; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index bc964de53936e..c34d34f025dac 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4215,10 +4215,12 @@ ParserResult Parser::parseCustomAttribute(SourceLoc atLoc) { "Cannot parse a trailing closure here"); } - // Form the attribute. + // Form the attribute. We set a DeclContext as the owner, which we'll change + // to the attached Decl if necessary when attaching the attributes. auto *TE = new (Context) TypeExpr(type.get()); - auto *customAttr = CustomAttr::create(Context, atLoc, TE, initContext, - argList); + auto *customAttr = + CustomAttr::create(Context, atLoc, TE, + /*owner*/ CurDeclContext, initContext, argList); if (status.hasCodeCompletion() && CodeCompletionCallbacks) { CodeCompletionCallbacks->setCompletingInAttribute(customAttr); } diff --git a/lib/Sema/CSSyntacticElement.cpp b/lib/Sema/CSSyntacticElement.cpp index 9ee3f0eb62702..cb03a1ca2629a 100644 --- a/lib/Sema/CSSyntacticElement.cpp +++ b/lib/Sema/CSSyntacticElement.cpp @@ -2595,7 +2595,8 @@ static void applySolutionToClosurePropertyWrappers(ClosureExpr *closure, auto &context = wrappedValueVar->getASTContext(); auto *typeExpr = TypeExpr::createImplicit(backingType, context); auto *attr = - CustomAttr::create(context, SourceLoc(), typeExpr, /*implicit=*/true); + CustomAttr::create(context, SourceLoc(), typeExpr, + /*owner*/ wrappedValueVar, /*implicit=*/true); wrappedValueVar->getAttrs().add(attr); } } diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index cdffea876a224..0b692ec313099 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -268,8 +268,8 @@ static ParamDecl *createMemberwiseInitParameter(DeclContext *DC, // Attach a result builder attribute if needed. if (resultBuilderType) { auto typeExpr = TypeExpr::createImplicit(resultBuilderType, ctx); - auto attr = - CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true); + auto attr = CustomAttr::create(ctx, SourceLoc(), typeExpr, /*owner*/ arg, + /*implicit=*/true); arg->getAttrs().add(attr); } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index b005626ffe527..89e1eaa0d0ba5 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -4619,9 +4619,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { auto dc = D->getDeclContext(); // Figure out which nominal declaration this custom attribute refers to. - auto *nominal = evaluateOrDefault( - Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); - + auto *nominal = attr->getNominalDecl(); if (!nominal) { if (attr->isInvalid()) return; @@ -8780,19 +8778,10 @@ template static void forEachCustomAttribute( Decl *decl, llvm::function_ref fn) { - auto &ctx = decl->getASTContext(); - for (auto *attr : decl->getAttrs().getAttributes()) { - auto *mutableAttr = const_cast(attr); - - auto *nominal = evaluateOrDefault( - ctx.evaluator, - CustomAttrNominalRequest{mutableAttr, decl->getDeclContext()}, nullptr); - if (!nominal) - continue; - - if (nominal->getAttrs().hasAttribute()) - fn(mutableAttr, nominal); + auto *nominal = attr->getNominalDecl(); + if (nominal && nominal->getAttrs().hasAttribute()) + fn(attr, nominal); } } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 95b3cdbb6f1bb..0b6a6054e45db 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -311,18 +311,17 @@ VarDecl *GlobalActorInstanceRequest::evaluate( } std::optional> -swift::checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc, - ArrayRef attrs) { - ASTContext &ctx = dc->getASTContext(); +swift::checkGlobalActorAttributes(SourceLoc loc, ArrayRef attrs) { + if (attrs.empty()) + return std::nullopt; + + auto &ctx = attrs[0]->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}, - nullptr); - + auto *nominal = attr->getNominalDecl(); if (!nominal) continue; @@ -352,11 +351,9 @@ std::optional> GlobalActorAttributeRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion subject) const { - DeclContext *dc = nullptr; DeclAttributes *declAttrs = nullptr; SourceLoc loc; if (auto decl = subject.dyn_cast()) { - dc = decl->getDeclContext(); declAttrs = &decl->getAttrs(); // HACK: `getLoc`, when querying the attr from a serialized decl, // depending on deserialization order, may launch into arbitrary @@ -372,7 +369,6 @@ GlobalActorAttributeRequest::evaluate( loc = decl->getLoc(/* SerializedOK */ false); } else { auto closure = cast(subject); - dc = closure; declAttrs = &closure->getAttrs(); loc = closure->getLoc(); } @@ -385,7 +381,7 @@ GlobalActorAttributeRequest::evaluate( } // Look for a global actor attribute. - auto result = checkGlobalActorAttributes(loc, dc, attrs); + auto result = checkGlobalActorAttributes(loc, attrs); if (!result) return std::nullopt; @@ -6088,8 +6084,8 @@ static void addAttributesForActorIsolation(ValueDecl *value, } case ActorIsolation::GlobalActor: { auto typeExpr = TypeExpr::createImplicit(isolation.getGlobalActor(), ctx); - auto attr = - CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true); + auto attr = CustomAttr::create(ctx, SourceLoc(), typeExpr, /*owner*/ value, + /*implicit=*/true); value->getAttrs().add(attr); if (isolation.preconcurrency() && diff --git a/lib/Sema/TypeCheckConcurrency.h b/lib/Sema/TypeCheckConcurrency.h index 50b01165ba306..6c858727488d8 100644 --- a/lib/Sema/TypeCheckConcurrency.h +++ b/lib/Sema/TypeCheckConcurrency.h @@ -609,8 +609,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> -checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc, - ArrayRef attrs); +checkGlobalActorAttributes(SourceLoc loc, ArrayRef attrs); /// Get the explicit global actor specified for a closure. Type getExplicitGlobalActor(ClosureExpr *closure); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index d15c34929807b..12de0968b180e 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -2241,7 +2241,12 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, // When a macro is not found for a custom attribute, it may be a non-macro. // So bail out to prevent diagnostics from the contraint system. - if (macroRef.getAttr()) { + if (auto *attr = macroRef.getAttr()) { + // If we already resolved this CustomAttr to a nominal, this isn't for a + // macro. + if (attr->getNominalDecl()) + return ConcreteDeclRef(); + auto foundMacros = namelookup::lookupMacros(dc, macroRef.getModuleName(), macroRef.getMacroName(), roles); if (foundMacros.empty()) diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index ed8dbea775570..fe5ada5078472 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -440,13 +440,9 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, llvm::TinyPtrVector result; for (auto attr : var->getExpandedAttrs().getAttributes()) { - auto mutableAttr = const_cast(attr); - // Figure out which nominal declaration this custom attribute refers to. - auto *nominal = evaluateOrDefault( - ctx.evaluator, CustomAttrNominalRequest{mutableAttr, dc}, nullptr); - // If we didn't find a nominal type with a @propertyWrapper attribute, // skip this custom attribute. + auto *nominal = attr->getNominalDecl(); if (!nominal || !nominal->getAttrs().hasAttribute()) continue; @@ -454,7 +450,7 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, // the semantic checking required. auto sourceFile = dc->getParentSourceFile(); if (!sourceFile) { - result.push_back(mutableAttr); + result.push_back(attr); continue; } @@ -545,7 +541,7 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, } } - result.push_back(mutableAttr); + result.push_back(attr); } // Attributes are stored in reverse order in the AST, but we want them in diff --git a/lib/Sema/TypeCheckRequestFunctions.cpp b/lib/Sema/TypeCheckRequestFunctions.cpp index ec0ecf94003c2..9d24c72b25441 100644 --- a/lib/Sema/TypeCheckRequestFunctions.cpp +++ b/lib/Sema/TypeCheckRequestFunctions.cpp @@ -175,24 +175,13 @@ bool SuppressesConformanceRequest::evaluate(Evaluator &evaluator, return false; } -CustomAttr * -AttachedResultBuilderRequest::evaluate(Evaluator &evaluator, - ValueDecl *decl) const { - ASTContext &ctx = decl->getASTContext(); - auto dc = decl->getDeclContext(); +CustomAttr *AttachedResultBuilderRequest::evaluate(Evaluator &evaluator, + ValueDecl *decl) const { for (auto attr : decl->getAttrs().getAttributes()) { - auto mutableAttr = const_cast(attr); - // Figure out which nominal declaration this custom attribute refers to. - auto *nominal = evaluateOrDefault(ctx.evaluator, - CustomAttrNominalRequest{mutableAttr, dc}, - nullptr); - - if (!nominal) - continue; - // Return the first custom attribute that is a result builder type. - if (nominal->getAttrs().hasAttribute()) - return mutableAttr; + auto *nominal = attr->getNominalDecl(); + if (nominal && nominal->getAttrs().hasAttribute()) + return attr; } return nullptr; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index e9fcf14459e9e..bc30b57b620d0 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3419,8 +3419,8 @@ void TypeAttrSet::diagnoseUnclaimed(TypeAttribute *attr, Type TypeResolver::resolveGlobalActor(SourceLoc loc, TypeResolutionOptions options, CustomAttr *&attr, TypeAttrSet &attrs) { - auto foundGlobalActor = checkGlobalActorAttributes( - loc, getDeclContext(), attrs.getCustomAttrs()); + auto foundGlobalActor = + checkGlobalActorAttributes(loc, attrs.getCustomAttrs()); if (!foundGlobalActor) return Type(); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8869182e094d7..4eb8d9e12905c 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3474,8 +3474,12 @@ class DeclDeserializer { ctx.Diags.diagnose(SourceLoc(), diagId, decl, MF.getAssociatedModule()); } - if (DAttrs) + if (DAttrs) { decl->getAttrs().setRawAttributeChain(DAttrs); + // Wire up the correct owner for any CustomAttrs we deserialized. + for (auto *CA : decl->getAttrs().getAttributes()) + CA->setOwner(decl); + } if (auto value = dyn_cast(decl)) { if (!privateDiscriminator.empty()) @@ -5965,8 +5969,10 @@ llvm::Error DeclDeserializer::deserializeCustomAttrs() { } else if (!deserialized.get() && MF.allowCompilerErrors()) { // Serialized an invalid attribute, just skip it when allowing errors } else { + // Note that the owner will be set in DeclDeserializer's destructor. auto *TE = TypeExpr::createImplicit(deserialized.get(), ctx); - auto custom = CustomAttr::create(ctx, SourceLoc(), TE, isImplicit); + auto custom = CustomAttr::create(ctx, SourceLoc(), TE, CustomAttrOwner(), + isImplicit); custom->setArgIsUnsafe(isArgUnsafe); AddAttribute(custom); } diff --git a/test/NameLookup/property_wrapper_and_macro.swift b/test/NameLookup/property_wrapper_and_macro.swift new file mode 100644 index 0000000000000..cc7c6bc53381f --- /dev/null +++ b/test/NameLookup/property_wrapper_and_macro.swift @@ -0,0 +1,89 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend -emit-ir -primary-file %t/valid.swift %t/definitions.swift +// RUN: %target-swift-frontend -typecheck -verify -verify-additional-prefix main- -primary-file %t/main.swift %t/definitions.swift +// RUN: %target-swift-frontend -typecheck -verify -verify-additional-prefix other- -parse-as-library -primary-file %t/other.swift %t/definitions.swift + +//--- definitions.swift +@attached(peer) +macro SomeAttr() = #externalMacro(module: "", type: "") // expected-note {{declared here}} +// expected-main-note@-1 2{{declared here}} + +@propertyWrapper +struct SomeAttr { + var wrappedValue: T + init(wrappedValue: T) { self.wrappedValue = wrappedValue } + init(projectedValue: Self) { self = projectedValue} + var projectedValue: Self { self } +} + +struct Err: Error {} + +//--- valid.swift +func foo() throws { + // Make sure we prefer the property wrapper over the macro here. + @SomeAttr var x = 0 + let _: Int = x + let _: SomeAttr = _x + let _: SomeAttr = $x + + _ = { + @SomeAttr var y = 0 + let _: Int = y + let _: SomeAttr = _y + let _: SomeAttr = $y + } + + func bar(@SomeAttr x: Int) { + let _: Int = x + let _: SomeAttr = _x + let _: SomeAttr = $x + } + + bar($x: SomeAttr(wrappedValue: 0)) + + func baz(_ fn: (SomeAttr) -> Void) {} + baz { x in } + baz { $x in } + + _ = if .random() { + @SomeAttr var z = 0 + let _: SomeAttr = _z + let _: SomeAttr = $z + throw Err() + } else { + 0 + } +} + +//--- main.swift +struct S1 { + var x = if .random() { + @SomeAttr var y = 0 + let _: SomeAttr = _y + let _: SomeAttr = $y + throw Err() // expected-error {{errors cannot be thrown out of a property initializer}} + } else { + 0 + } +} + +// Here we prefer the macro. +struct S2 { + @SomeAttr var x = 0 // expected-error {{could not be found for macro}} +} + +func bar() { + @SomeAttr func baz() {} // expected-error {{could not be found for macro}} +} + +@SomeAttr var x = 0 // expected-error {{could not be found for macro}} + +_ = { @SomeAttr in } +// expected-error@-1 {{attribute @SomeAttr is not supported on a closure}} +// expected-warning@-2 {{cannot specialize a non-generic external macro 'SomeAttr()'}} + +//--- other.swift + +// Also check for a library file +@SomeAttr var x = 0 // expected-error {{could not be found for macro}}