@@ -3971,20 +3971,34 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
39713971 parsedGenericParams->getRAngleLoc ());
39723972}
39733973
3974+ static bool shouldPreferPropertyWrapperOverMacro (CustomAttrOwner owner) {
3975+ // If we have a VarDecl in a local context, prefer to use a property wrapper
3976+ // if one exists. This is necessary since we don't properly support peer
3977+ // declarations in local contexts, so want to use a property wrapper if one
3978+ // exists.
3979+ if (auto *D = dyn_cast_or_null<VarDecl>(owner.getAsDecl ())) {
3980+ if (D->getDeclContext ()->isLocalContext ())
3981+ return true ;
3982+ }
3983+ return false ;
3984+ }
3985+
39743986NominalTypeDecl *CustomAttrNominalRequest::evaluate (Evaluator &evaluator,
39753987 CustomAttr *attr) const {
39763988 auto owner = attr->getOwner ();
39773989 auto *dc = owner.getDeclContext ();
39783990
39793991 // Look for names at module scope, so we don't trigger name lookup for
39803992 // nested scopes. At this point, we're looking to see whether there are
3981- // any suitable macros.
3993+ // any suitable macros. If we're preferring property wrappers we wait to see
3994+ // if any property wrappers are in scope before returning.
39823995 auto [module , macro] = attr->destructureMacroRef ();
39833996 auto moduleName = (module ) ? module ->getNameRef () : DeclNameRef ();
39843997 auto macroName = (macro) ? macro->getNameRef () : DeclNameRef ();
39853998 auto macros = namelookup::lookupMacros (dc, moduleName, macroName,
39863999 getAttachedMacroRoles ());
3987- if (!macros.empty ())
4000+ auto shouldPreferPropWrapper = shouldPreferPropertyWrapperOverMacro (owner);
4001+ if (!macros.empty () && !shouldPreferPropWrapper)
39884002 return nullptr ;
39894003
39904004 // Find the types referenced by the custom attribute.
@@ -4004,6 +4018,15 @@ NominalTypeDecl *CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
40044018 auto nominals = resolveTypeDeclsToNominal (evaluator, ctx, decls.first ,
40054019 ResolveToNominalOptions (),
40064020 modulesFound, anyObject);
4021+ // If we're preferring property wrappers and found a suitable match, continue.
4022+ // Otherwise we can bail and resolve as a macro.
4023+ if (shouldPreferPropWrapper) {
4024+ auto hasPropWrapper = llvm::any_of (nominals, [](NominalTypeDecl *NTD) {
4025+ return NTD->getAttrs ().hasAttribute <PropertyWrapperAttr>();
4026+ });
4027+ if (!macros.empty () && !hasPropWrapper)
4028+ return nullptr ;
4029+ }
40074030 if (nominals.size () == 1 && !isa<ProtocolDecl>(nominals.front ()))
40084031 return nominals.front ();
40094032
0 commit comments