Repository: swiftlang/swift
Pull request #79821: [ASTGen] Adopt AvailabilityDomainOrIdentifier scheme 
Author: login: rintaro
Created: 2025-03-06T19:05:34Z | Merged: 2025-03-07T20:16:12Z

Aligning with `lib/Parse`



Diff:
diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h
index 34ad8a947a174..8eb41f4cf7697 100644
--- a/include/swift/AST/ASTBridging.h
+++ b/include/swift/AST/ASTBridging.h
@@ -34,7 +34,7 @@ template<typename T> class ArrayRef;
 
 namespace swift {
 enum class AccessorKind;
-class AvailabilityDomain;
+class AvailabilityDomainOrIdentifier;
 class Argument;
 class ASTContext;
 struct ASTNode;
@@ -678,6 +678,10 @@ enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedPlatformKind : size_t {
 SWIFT_NAME("BridgedPlatformKind.init(from:)")
 BridgedPlatformKind BridgedPlatformKind_fromString(BridgedStringRef cStr);
 
+SWIFT_NAME("BridgedPlatformKind.init(from:)")
+BridgedPlatformKind
+BridgedPlatformKind_fromIdentifier(BridgedIdentifier cIdent);
+
 swift::PlatformKind unbridge(BridgedPlatformKind cPlatform);
 
 SWIFT_NAME("BridgedAvailabilityMacroMap.has(self:name:)")
@@ -701,19 +705,48 @@ struct BridgedAvailabilityMacroDefinition {
   BridgedArrayRef specs;
 };
 
-struct BridgedAvailabilityDomain;
+struct BridgedAvailabilityDomainOrIdentifier {
+  void *_Nullable opaque;
+
+  BridgedAvailabilityDomainOrIdentifier() : opaque(nullptr) {};
+  BRIDGED_INLINE BridgedAvailabilityDomainOrIdentifier(
+      swift::AvailabilityDomainOrIdentifier domain);
+  BRIDGED_INLINE swift::AvailabilityDomainOrIdentifier unbridged() const;
+};
+
+SWIFT_NAME("getter:BridgedAvailabilityDomainOrIdentifier.isDomain(self:)")
+BRIDGED_INLINE bool BridgedAvailabilityDomainOrIdentifier_isDomain(
+    BridgedAvailabilityDomainOrIdentifier cVal);
+
+SWIFT_NAME("getter:BridgedAvailabilityDomainOrIdentifier.asIdentifier(self:)")
+BRIDGED_INLINE BridgedIdentifier
+BridgedAvailabilityDomainOrIdentifier_getAsIdentifier(
+    BridgedAvailabilityDomainOrIdentifier cVal);
 
 SWIFT_NAME("BridgedAvailabilitySpec.createWildcard(_:loc:)")
 BridgedAvailabilitySpec
 BridgedAvailabilitySpec_createWildcard(BridgedASTContext cContext,
                                        BridgedSourceLoc cLoc);
 
-SWIFT_NAME("BridgedAvailabilitySpec.create(_:domain:nameLoc:version:"
-           "versionRange:)")
-BridgedAvailabilitySpec BridgedAvailabilitySpec_createForDomain(
-    BridgedASTContext cContext, BridgedAvailabilityDomain cDomain,
-    BridgedSourceLoc cLoc, BridgedVersionTuple cVersion,
-    BridgedSourceRange cVersionRange);
+SWIFT_NAME(
+    "BridgedAvailabilitySpec.createForDomainIdentifier(_:name:nameLoc:version:"
+    "versionRange:)")
+BridgedAvailabilitySpec BridgedAvailabilitySpec_createForDomainIdentifier(
+    BridgedASTContext cContext, BridgedIdentifier cName, BridgedSourceLoc cLoc,
+    BridgedVersionTuple cVersion, BridgedSourceRange cVersionRange);
+
+SWIFT_NAME("BridgedAvailabilitySpec.clone(self:_:)")
+BridgedAvailabilitySpec
+BridgedAvailabilitySpec_clone(BridgedAvailabilitySpec spec,
+                              BridgedASTContext cContext);
+
+SWIFT_NAME("BridgedAvailabilitySpec.setMacroLoc(self:_:)")
+void BridgedAvailabilitySpec_setMacroLoc(BridgedAvailabilitySpec spec,
+                                         BridgedSourceLoc cLoc);
+
+SWIFT_NAME("getter:BridgedAvailabilitySpec.domainOrIdentifier(self:)")
+BridgedAvailabilityDomainOrIdentifier
+BridgedAvailabilitySpec_getDomainOrIdentifier(BridgedAvailabilitySpec spec);
 
 SWIFT_NAME("getter:BridgedAvailabilitySpec.sourceRange(self:)")
 BridgedSourceRange
@@ -722,14 +755,6 @@ BridgedAvailabilitySpec_getSourceRange(BridgedAvailabilitySpec spec);
 SWIFT_NAME("getter:BridgedAvailabilitySpec.isWildcard(self:)")
 bool BridgedAvailabilitySpec_isWildcard(BridgedAvailabilitySpec spec);
 
-SWIFT_NAME("getter:BridgedAvailabilitySpec.domain(self:)")
-BridgedAvailabilityDomain
-BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec);
-
-SWIFT_NAME("getter:BridgedAvailabilitySpec.platform(self:)")
-BridgedPlatformKind
-BridgedAvailabilitySpec_getPlatform(BridgedAvailabilitySpec spec);
-
 SWIFT_NAME("getter:BridgedAvailabilitySpec.rawVersion(self:)")
 BridgedVersionTuple
 BridgedAvailabilitySpec_getRawVersion(BridgedAvailabilitySpec spec);
@@ -738,23 +763,6 @@ SWIFT_NAME("getter:BridgedAvailabilitySpec.versionRange(self:)")
 BridgedSourceRange
 BridgedAvailabilitySpec_getVersionRange(BridgedAvailabilitySpec spec);
 
-struct BridgedAvailabilityDomain {
-  void *_Nullable opaque;
-
-  BridgedAvailabilityDomain() : opaque(nullptr) {};
-  BRIDGED_INLINE BridgedAvailabilityDomain(swift::AvailabilityDomain domain);
-  BRIDGED_INLINE swift::AvailabilityDomain unbridged() const;
-
-  BRIDGED_INLINE static BridgedAvailabilityDomain forUniversal();
-  BRIDGED_INLINE static BridgedAvailabilityDomain
-  forPlatform(BridgedPlatformKind platformKind);
-  BRIDGED_INLINE static BridgedAvailabilityDomain forSwiftLanguage();
-  BRIDGED_INLINE static BridgedAvailabilityDomain forPackageDescription();
-  BRIDGED_INLINE static BridgedAvailabilityDomain forEmbedded();
-
-  bool isNull() const { return opaque == nullptr; };
-};
-
 //===----------------------------------------------------------------------===//
 // MARK: AutoDiff
 //===----------------------------------------------------------------------===//
@@ -856,23 +864,10 @@ enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAvailableAttrKind {
   BridgedAvailableAttrKindNoAsync,
 };
 
-SWIFT_NAME(
-    "BridgedAvailableAttr.createParsed(_:atLoc:range:domain:domainLoc:kind:message:"
-    "renamed:introduced:introducedRange:deprecated:deprecatedRange:"
-    "obsoleted:obsoletedRange:)")
-BridgedAvailableAttr BridgedAvailableAttr_createParsed(
-    BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
-    BridgedSourceRange cRange, BridgedAvailabilityDomain cDomain, BridgedSourceLoc cDomainLoc,
-    BridgedAvailableAttrKind cKind, BridgedStringRef cMessage,
-    BridgedStringRef cRenamed, BridgedVersionTuple cIntroduced,
-    BridgedSourceRange cIntroducedRange, BridgedVersionTuple cDeprecated,
-    BridgedSourceRange cDeprecatedRange, BridgedVersionTuple cObsoleted,
-    BridgedSourceRange cObsoletedRange);
-
 SWIFT_NAME("BridgedAvailableAttr.createParsed(_:atLoc:range:domainIdentifier:"
            "domainLoc:kind:message:renamed:introduced:introducedRange:"
            "deprecated:deprecatedRange:obsoleted:obsoletedRange:)")
-BridgedAvailableAttr BridgedAvailableAttr_createParsedIdentifier(
+BridgedAvailableAttr BridgedAvailableAttr_createParsed(
     BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
     BridgedSourceRange cRange, BridgedIdentifier cDomainIdentifier,
     BridgedSourceLoc cDomainLoc, BridgedAvailableAttrKind cKind,
@@ -881,6 +876,19 @@ BridgedAvailableAttr BridgedAvailableAttr_createParsedIdentifier(
     BridgedVersionTuple cDeprecated, BridgedSourceRange cDeprecatedRange,
     BridgedVersionTuple cObsoleted, BridgedSourceRange cObsoletedRange);
 
+SWIFT_NAME("BridgedAvailableAttr.createUnavailableInEmbedded(_:atLoc:range:)")
+BridgedAvailableAttr
+BridgedAvailableAttr_createUnavailableInEmbedded(BridgedASTContext cContext,
+                                                 BridgedSourceLoc cAtLoc,
+                                                 BridgedSourceRange cRange);
+
+SWIFT_NAME("BridgedAvailableAttr.setIsGroupMember(self:)")
+void BridgedAvailableAttr_setIsGroupMember(BridgedAvailableAttr cAttr);
+SWIFT_NAME("BridgedAvailableAttr.setIsGroupedWithWildcard(self:)")
+void BridgedAvailableAttr_setIsGroupedWithWildcard(BridgedAvailableAttr cAttr);
+SWIFT_NAME("BridgedAvailableAttr.setIsGroupTerminator(self:)")
+void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr);
+
 enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind {
   BridgedExecutionKindConcurrent,
   BridgedExecutionKindCaller,
diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h
index a6228428c12fe..aaa07655dbc33 100644
--- a/include/swift/AST/ASTBridgingImpl.h
+++ b/include/swift/AST/ASTBridgingImpl.h
@@ -283,32 +283,28 @@ swift::DeclAttributes BridgedDeclAttributes::unbridged() const {
 }
 
 //===----------------------------------------------------------------------===//
-// MARK: AvailabilityDomain
+// MARK: AvailabilityDomainOrIdentifier
 //===----------------------------------------------------------------------===//
 
-BridgedAvailabilityDomain::BridgedAvailabilityDomain(
-    swift::AvailabilityDomain domain)
-    : opaque(domain.getOpaqueValue()) {}
+BridgedAvailabilityDomainOrIdentifier::BridgedAvailabilityDomainOrIdentifier(
+    swift::AvailabilityDomainOrIdentifier domainOrIdentifier)
+    : opaque(domainOrIdentifier.getOpaqueValue()) {}
 
-swift::AvailabilityDomain BridgedAvailabilityDomain::unbridged() const {
-  return swift::AvailabilityDomain::fromOpaque(opaque);
+swift::AvailabilityDomainOrIdentifier
+BridgedAvailabilityDomainOrIdentifier::unbridged() const {
+  return swift::AvailabilityDomainOrIdentifier::fromOpaque(opaque);
 }
 
-BridgedAvailabilityDomain BridgedAvailabilityDomain::forUniversal() {
-  return swift::AvailabilityDomain::forUniversal();
+bool BridgedAvailabilityDomainOrIdentifier_isDomain(
+    BridgedAvailabilityDomainOrIdentifier cVal) {
+  return cVal.unbridged().isDomain();
 }
-BridgedAvailabilityDomain
-BridgedAvailabilityDomain::forPlatform(BridgedPlatformKind platformKind) {
-  return swift::AvailabilityDomain::forPlatform(unbridge(platformKind));
-}
-BridgedAvailabilityDomain BridgedAvailabilityDomain::forSwiftLanguage() {
-  return swift::AvailabilityDomain::forSwiftLanguage();
-}
-BridgedAvailabilityDomain BridgedAvailabilityDomain::forPackageDescription() {
-  return swift::AvailabilityDomain::forPackageDescription();
-}
-BridgedAvailabilityDomain BridgedAvailabilityDomain::forEmbedded() {
-  return swift::AvailabilityDomain::forEmbedded();
+
+BridgedIdentifier BridgedAvailabilityDomainOrIdentifier_getAsIdentifier(
+    BridgedAvailabilityDomainOrIdentifier cVal) {
+  if (auto ident = cVal.unbridged().getAsIdentifier())
+    return *ident;
+  return swift::Identifier();
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h
index bc7ee6e426f07..37e4fbe7fd64b 100644
--- a/include/swift/AST/Attr.h
+++ b/include/swift/AST/Attr.h
@@ -888,6 +888,11 @@ class AvailableAttr : public DeclAttribute {
       llvm::VersionTuple Introduced, llvm::VersionTuple Deprecated,
       llvm::VersionTuple Obsoleted);
 
+  /// Create an `AvailableAttr` for `@_unavailableInEmbedded`.
+  static AvailableAttr *createUnavailableInEmbedded(ASTContext &ctx,
+                                                    SourceLoc AtLoc,
+                                                    SourceRange Range);
+
   AvailableAttr *clone(ASTContext &C, bool implicit) const;
   AvailableAttr *clone(ASTContext &C) const {
     return clone(C, isImplicit());
diff --git a/include/swift/AST/AvailabilityDomain.h b/include/swift/AST/AvailabilityDomain.h
index a98bccae5c5fe..1d99697f962d7 100644
--- a/include/swift/AST/AvailabilityDomain.h
+++ b/include/swift/AST/AvailabilityDomain.h
@@ -334,10 +334,6 @@ class AvailabilityDomainOrIdentifier {
 
   AvailabilityDomainOrIdentifier(Storage storage) : storage(storage) {}
 
-  static AvailabilityDomainOrIdentifier fromOpaque(void *opaque) {
-    return AvailabilityDomainOrIdentifier(Storage::getFromOpaqueValue(opaque));
-  }
-
   std::optional<AvailabilityDomain>
   lookUpInDeclContext(SourceLoc loc, const DeclContext *declContext) const;
 
@@ -397,6 +393,12 @@ class AvailabilityDomainOrIdentifier {
   /// different than the context that the original was created for.
   AvailabilityDomainOrIdentifier copy(ASTContext &ctx) const;
 
+  static AvailabilityDomainOrIdentifier fromOpaque(void *opaque) {
+    return AvailabilityDomainOrIdentifier(Storage::getFromOpaqueValue(opaque));
+  }
+
+  void *getOpaqueValue() const { return storage.getOpaqueValue(); }
+
   void print(llvm::raw_ostream &os) const;
 };
 
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 2699c4ed85157..366dcf3458683 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -4945,8 +4945,18 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
   void visitAvailableAttr(AvailableAttr *Attr, Label label) {
     printCommon(Attr, "available_attr", label);
 
-    printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
-                  Label::always("domain"));
+    printFlag(Attr->isGroupMember(), "group_member");
+    printFlag(Attr->isGroupedWithWildcard(), "group_with_wildcard");
+    printFlag(Attr->isGroupTerminator(), "group_terminator");
+
+    auto domainOrIdentifier = Attr->getDomainOrIdentifier();
+    if (domainOrIdentifier.isDomain()) {
+      printFieldRaw([&](auto &out) { domainOrIdentifier.getAsDomain()->print(out); },
+                    Label::always("domain"));
+    } else {
+      printFlag(domainOrIdentifier.isResolved(), "resolved");
+      printField(*domainOrIdentifier.getAsIdentifier(), Label::always("domainIdentifier"));
+    }
 
     switch (Attr->getKind()) {
     case swift::AvailableAttr::Kind::Default:
diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp
index 9c4cbbaf6fa8a..a7ad54653aa9a 100644
--- a/lib/AST/Attr.cpp
+++ b/lib/AST/Attr.cpp
@@ -2208,6 +2208,19 @@ AvailableAttr *AvailableAttr::createPlatformVersioned(
       /*SPI=*/false);
 }
 
+AvailableAttr *AvailableAttr::createUnavailableInEmbedded(ASTContext &C,
+                                                          SourceLoc AtLoc,
+                                                          SourceRange Range) {
+  return new (C) AvailableAttr(
+      AtLoc, Range, AvailabilityDomain::forEmbedded(), SourceLoc(),
+      AvailableAttr::Kind::Unavailable, "unavailable in embedded Swift",
+      /*Rename=*/StringRef(),
+      /*Introduced=*/llvm::VersionTuple(), /*IntroducedRange=*/{},
+      /*Deprecated=*/llvm::VersionTuple(), /*DeprecatedRange=*/{},
+      /*Obsoleted=*/llvm::VersionTuple(), /*ObsoletedRange=*/{},
+      /*Implicit=*/false, /*IsSPI=*/false);
+}
+
 bool BackDeployedAttr::isActivePlatform(const ASTContext &ctx,
                                         bool forTargetVariant) const {
   return isPlatformActive(Platform, ctx.LangOpts, forTargetVariant);
diff --git a/lib/AST/Bridging/AvailabilityBridging.cpp b/lib/AST/Bridging/AvailabilityBridging.cpp
index c1a72f54bed02..fce3167dc803d 100644
--- a/lib/AST/Bridging/AvailabilityBridging.cpp
+++ b/lib/AST/Bridging/AvailabilityBridging.cpp
@@ -58,6 +58,11 @@ BridgedPlatformKind BridgedPlatformKind_fromString(BridgedStringRef cStr) {
   }
 }
 
+BridgedPlatformKind
+BridgedPlatformKind_fromIdentifier(BridgedIdentifier cIdent) {
+  return BridgedPlatformKind_fromString(cIdent.unbridged().str());
+}
+
 PlatformKind unbridge(BridgedPlatformKind platform) {
   switch (platform) {
   case BridgedPlatformKind_None:
@@ -70,18 +75,6 @@ PlatformKind unbridge(BridgedPlatformKind platform) {
   llvm_unreachable("unhandled enum value");
 }
 
-static BridgedPlatformKind bridge(PlatformKind platform) {
-  switch (platform) {
-  case PlatformKind::none:
-    return BridgedPlatformKind_None;
-#define AVAILABILITY_PLATFORM(X, PrettyName)                                   \
-  case PlatformKind::X:                                                        \
-    return BridgedPlatformKind_##X;
-#include "swift/AST/PlatformKinds.def"
-  }
-  llvm_unreachable("unhandled enum value");
-}
-
 //===----------------------------------------------------------------------===//
 // MARK: AvailabilitySpec
 //===----------------------------------------------------------------------===//
@@ -93,15 +86,30 @@ BridgedAvailabilitySpec_createWildcard(BridgedASTContext cContext,
                                           cLoc.unbridged());
 }
 
-BridgedAvailabilitySpec BridgedAvailabilitySpec_createForDomain(
-    BridgedASTContext cContext, BridgedAvailabilityDomain cDomain,
-    BridgedSourceLoc cLoc, BridgedVersionTuple cVersion,
-    BridgedSourceRange cVersionRange) {
-  return AvailabilitySpec::createForDomain(
-      cContext.unbridged(), cDomain.unbridged(), cLoc.unbridged(),
+BridgedAvailabilitySpec BridgedAvailabilitySpec_createForDomainIdentifier(
+    BridgedASTContext cContext, BridgedIdentifier cName, BridgedSourceLoc cLoc,
+    BridgedVersionTuple cVersion, BridgedSourceRange cVersionRange) {
+  return AvailabilitySpec::createForDomainIdentifier(
+      cContext.unbridged(), cName.unbridged(), cLoc.unbridged(),
       cVersion.unbridged(), cVersionRange.unbridged());
 }
 
+BridgedAvailabilitySpec
+BridgedAvailabilitySpec_clone(BridgedAvailabilitySpec spec,
+                              BridgedASTContext cContext) {
+  return spec.unbridged()->clone(cContext.unbridged());
+}
+
+void BridgedAvailabilitySpec_setMacroLoc(BridgedAvailabilitySpec spec,
+                                         BridgedSourceLoc cLoc) {
+  spec.unbridged()->setMacroLoc(cLoc.unbridged());
+}
+
+BridgedAvailabilityDomainOrIdentifier
+BridgedAvailabilitySpec_getDomainOrIdentifier(BridgedAvailabilitySpec spec) {
+  return spec.unbridged()->getDomainOrIdentifier();
+}
+
 BridgedSourceRange
 BridgedAvailabilitySpec_getSourceRange(BridgedAvailabilitySpec spec) {
   return spec.unbridged()->getSourceRange();
@@ -111,24 +119,6 @@ bool BridgedAvailabilitySpec_isWildcard(BridgedAvailabilitySpec spec) {
   return spec.unbridged()->isWildcard();
 }
 
-// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
-BridgedAvailabilityDomain
-BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec) {
-  auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
-  if (domain)
-    return *domain;
-  return BridgedAvailabilityDomain();
-}
-
-// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
-BridgedPlatformKind
-BridgedAvailabilitySpec_getPlatform(BridgedAvailabilitySpec spec) {
-  auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
-  if (domain)
-    return bridge(domain->getPlatformKind());
-  return bridge(PlatformKind::none);
-}
-
 BridgedVersionTuple
 BridgedAvailabilitySpec_getRawVersion(BridgedAvailabilitySpec spec) {
   return spec.unbridged()->getRawVersion();
diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp
index bcd97dba526d8..c36c4a0cf5f82 100644
--- a/lib/AST/Bridging/DeclAttributeBridging.cpp
+++ b/lib/AST/Bridging/DeclAttributeBridging.cpp
@@ -130,25 +130,6 @@ static AvailableAttr::Kind unbridge(BridgedAvailableAttrKind value) {
 }
 
 BridgedAvailableAttr BridgedAvailableAttr_createParsed(
-    BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
-    BridgedSourceRange cRange, BridgedAvailabilityDomain cDomain,
-    BridgedSourceLoc cDomainLoc, BridgedAvailableAttrKind cKind,
-    BridgedStringRef cMessage, BridgedStringRef cRenamed,
-    BridgedVersionTuple cIntroduced, BridgedSourceRange cIntroducedRange,
-    BridgedVersionTuple cDeprecated, BridgedSourceRange cDeprecatedRange,
-    BridgedVersionTuple cObsoleted, BridgedSourceRange cObsoletedRange) {
-  return new (cContext.unbridged())
-      AvailableAttr(cAtLoc.unbridged(), cRange.unbridged(), cDomain.unbridged(),
-                    cDomainLoc.unbridged(), unbridge(cKind),
-                    cMessage.unbridged(), cRenamed.unbridged(),
-                    cIntroduced.unbridged(), cIntroducedRange.unbridged(),
-                    cDeprecated.unbridged(), cDeprecatedRange.unbridged(),
-                    cObsoleted.unbridged(), cObsoletedRange.unbridged(),
-                    /*Implicit=*/false,
-                    /*IsSPI=*/false);
-}
-
-BridgedAvailableAttr BridgedAvailableAttr_createParsedIdentifier(
     BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
     BridgedSourceRange cRange, BridgedIdentifier cDomainIdentifier,
     BridgedSourceLoc cDomainLoc, BridgedAvailableAttrKind cKind,
@@ -168,6 +149,24 @@ BridgedAvailableAttr BridgedAvailableAttr_createParsedIdentifier(
                     /*IsSPI=*/false);
 }
 
+BridgedAvailableAttr
+BridgedAvailableAttr_createUnavailableInEmbedded(BridgedASTContext cContext,
+                                                 BridgedSourceLoc cAtLoc,
+                                                 BridgedSourceRange cRange) {
+  return AvailableAttr::createUnavailableInEmbedded(
+      cContext.unbridged(), cAtLoc.unbridged(), cRange.unbridged());
+}
+
+void BridgedAvailableAttr_setIsGroupMember(BridgedAvailableAttr cAttr) {
+  cAttr.unbridged()->setIsGroupMember();
+}
+void BridgedAvailableAttr_setIsGroupedWithWildcard(BridgedAvailableAttr cAttr) {
+  cAttr.unbridged()->setIsGroupedWithWildcard();
+}
+void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr) {
+  cAttr.unbridged()->setIsGroupTerminator();
+}
+
 static std::optional<AccessLevel> unbridge(BridgedAccessLevel level) {
   switch (level) {
   case BridgedAccessLevelPrivate:
diff --git a/lib/ASTGen/Sources/ASTGen/Availability.swift b/lib/ASTGen/Sources/ASTGen/Availability.swift
index 78c1c9f71cb39..e7dae640e303f 100644
--- a/lib/ASTGen/Sources/ASTGen/Availability.swift
+++ b/lib/ASTGen/Sources/ASTGen/Availability.swift
@@ -70,20 +70,27 @@ extension ASTGenVisitor {
   ) -> [BridgedAvailableAttr] {
     let specs = self.generateAvailabilitySpecList(args: args, context: .availableAttr)
 
+    var isFirst = true
     var result: [BridgedAvailableAttr] = []
+    let containsWildCard = specs.contains { $0.isWildcard }
     for spec in specs {
       guard !spec.isWildcard else {
         continue
       }
-      let domain = spec.domain
-      guard !domain.isNull() else {
+
+      let domainOrIdentifier = spec.domainOrIdentifier
+      // The domain should not be resolved during parsing.
+      assert(!domainOrIdentifier.isDomain)
+      if domainOrIdentifier.asIdentifier == nil {
         continue
       }
+
+      // TODO: Assert 'spec' is domain identifier.
       let attr = BridgedAvailableAttr.createParsed(
         self.ctx,
         atLoc: atLoc,
         range: range,
-        domain: domain,
+        domainIdentifier: domainOrIdentifier.asIdentifier,
         domainLoc: spec.sourceRange.start,
         kind: .default,
         message: BridgedStringRef(),
@@ -95,6 +102,15 @@ extension ASTGenVisitor {
         obsoleted: BridgedVersionTuple(),
         obsoletedRange: BridgedSourceRange()
       )
+      attr.setIsGroupMember()
+      if containsWildCard {
+        attr.setIsGroupedWithWildcard()
+      }
+      if isFirst {
+        attr.setIsGroupTerminator()
+        isFirst = false
+      }
+
       result.append(attr)
     }
     return result
@@ -112,8 +128,7 @@ extension ASTGenVisitor {
       // TODO: Diangose
       fatalError("missing first arg")
     }
-    let platformStr = platformToken.rawText
-    let platformLoc = self.generateSourceLoc(platformToken)
+    let domain = self.generateIdentifierAndSourceLoc(platformToken)
 
     // Other arguments can be shuffled.
     enum Argument: UInt8 {
@@ -237,8 +252,8 @@ extension ASTGenVisitor {
       self.ctx,
       atLoc: atLoc,
       range: range,
-      domainIdentifier: self.ctx.getIdentifier(platformStr.bridged),
-      domainLoc: platformLoc,
+      domainIdentifier: domain.identifier,
+      domainLoc: domain.sourceLoc,
       kind: attrKind,
       message: message ?? BridgedStringRef(),
       renamed: renamed ?? BridgedStringRef(),
@@ -284,65 +299,47 @@ extension ASTGenVisitor {
     var result: [BridgedAvailabilitySpec] = []
 
     func handle(domainNode: TokenSyntax, versionNode: VersionTupleSyntax?) {
-      // FIXME: [availability] Add support for custom domains
-      let nameLoc = self.generateSourceLoc(domainNode)
       let version = self.generate(versionTuple: versionNode)
       let versionRange = self.generateSourceRange(versionNode)
 
-      switch domainNode.rawText {
-      case "swift", "_PackageVersion":
-        let domain: BridgedAvailabilityDomain = domainNode.rawText == "swift"
-          ? .forSwiftLanguage()
-          : .forPackageDescription()
-
-        let spec = BridgedAvailabilitySpec.create(
-          self.ctx,
-          domain: domain,
-          nameLoc: nameLoc,
-          version: version?.bridged ?? BridgedVersionTuple(),
-          versionRange: versionRange
+      if context != .macro {
+        // Try expand macro first.
+        let expanded = ctx.availabilityMacroMap.get(
+          name: domainNode.rawText.bridged,
+          version: version?.bridged ?? BridgedVersionTuple()
         )
-        result.append(spec)
-
-      case let name:
-        var macroMatched = false;
-        if context != .macro {
-          // Try expand macro first.
-          let expanded = ctx.availabilityMacroMap.get(
-            name: name.bridged,
-            version: version?.bridged ?? BridgedVersionTuple()
-          )
-          if !expanded.isEmpty {
-            expanded.withElements(ofType: UnsafeRawPointer.self) { buffer in
-              for ptr in buffer {
-                result.append(BridgedAvailabilitySpec(raw: UnsafeMutableRawPointer(mutating: ptr)))
-              }
+        if !expanded.isEmpty {
+          let macroLoc = self.generateSourceLoc(domainNode)
+          expanded.withElements(ofType: UnsafeRawPointer.self) { buffer in
+            for ptr in buffer {
+              // Make a copy of the specs to add the macro source location
+              // for the diagnostic about the use of macros in inlinable code.
+              let spec = BridgedAvailabilitySpec(raw: UnsafeMutableRawPointer(mutating: ptr))
+                .clone(self.ctx)
+              spec.setMacroLoc(macroLoc)
+              result.append(spec)
             }
-            macroMatched = true
           }
+          return
         }
+      }
 
-        // Was not a macro, it should be a valid platform name.
-        if !macroMatched {
-          let platform = BridgedPlatformKind(from: name.bridged)
-          guard platform != .none else {
-            // TODO: Diagnostics.
-            fatalError("invalid platform kind")
-          }
-          guard let version = version else {
-            // TODO: Diagnostics.
-            fatalError("expected version")
-          }
-          let spec = BridgedAvailabilitySpec.create(
-            self.ctx,
-            domain: BridgedAvailabilityDomain.forPlatform(platform),
-            nameLoc: nameLoc,
-            version: version.bridged,
-            versionRange: versionRange
-          )
-          result.append(spec)
-        }
+      // Was not a macro, it should be a valid platform name.
+      let platform = self.generateIdentifierAndSourceLoc(domainNode)
+      guard let version = version else {
+        // TODO: Diagnostics.
+        fatalError("expected version")
       }
+      // FIXME: Wasting ASTContext memory.
+      // 'AvailabilitySpec' is 'ASTAllocated' but created spec is ephemeral in context of `@available` attributes.
+      let spec = BridgedAvailabilitySpec.createForDomainIdentifier(
+        self.ctx,
+        name: platform.identifier,
+        nameLoc: platform.sourceLoc,
+        version: version.bridged,
+        versionRange: versionRange
+      )
+      result.append(spec)
     }
 
     for parsed in node {
@@ -392,7 +389,9 @@ extension ASTGenVisitor {
         expanded.withElements(ofType: UnsafeRawPointer.self) { buffer in
           for ptr in buffer {
             let spec = BridgedAvailabilitySpec(raw: UnsafeMutableRawPointer(mutating: ptr))
-            let platform = spec.platform
+            let domainOrIdentifier = spec.domainOrIdentifier
+            precondition(!domainOrIdentifier.isDomain)
+            let platform = BridgedPlatformKind(from: domainOrIdentifier.asIdentifier)
             guard platform != .none else {
               continue
             }
diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
index 9c449511d95a1..65da0a7d61d53 100644
--- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
+++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
@@ -2120,21 +2120,10 @@ extension ASTGenVisitor {
 
   func generateUnavailableInEmbeddedAttr(attribute node: AttributeSyntax) -> BridgedAvailableAttr? {
     if ctx.langOptsHasFeature(.Embedded) {
-      return BridgedAvailableAttr.createParsed(
+      return BridgedAvailableAttr.createUnavailableInEmbedded(
         self.ctx,
         atLoc: self.generateSourceLoc(node.atSign),
-        range: self.generateAttrSourceRange(node),
-        domain: .forEmbedded(),
-        domainLoc: nil,
-        kind: .unavailable,
-        message: "unavailable in embedded Swift",
-        renamed: "",
-        introduced: BridgedVersionTuple(),
-        introducedRange: BridgedSourceRange(),
-        deprecated: BridgedVersionTuple(),
-        deprecatedRange:  BridgedSourceRange(),
-        obsoleted: BridgedVersionTuple(),
-        obsoletedRange: BridgedSourceRange()
+        range: self.generateAttrSourceRange(node)
       )
     } else {
       // For non-Embedded mode, ignore it.
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index cc793882c6286..d607c2371cbc0 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -4299,13 +4299,8 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
   if (!DK && Tok.getText() == UNAVAILABLE_IN_EMBEDDED_ATTRNAME) {
     SourceLoc attrLoc = consumeToken();
     if (Context.LangOpts.hasFeature(Feature::Embedded)) {
-      StringRef Message = "unavailable in embedded Swift", Renamed;
-      auto attr = new (Context) AvailableAttr(
-          AtLoc, SourceRange(AtLoc, attrLoc), AvailabilityDomain::forEmbedded(),
-          SourceLoc(), AvailableAttr::Kind::Unavailable, Message, Renamed,
-          llvm::VersionTuple(), SourceRange(), llvm::VersionTuple(),
-          SourceRange(), llvm::VersionTuple(), SourceRange(),
-          /*Implicit=*/false, /*IsSPI=*/false);
+      auto attr = AvailableAttr::createUnavailableInEmbedded(
+          Context, AtLoc, SourceRange(AtLoc, attrLoc));
       Attributes.add(attr);
     }
     return makeParserSuccess();


Reviews:
user: login: tshortli
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T19:08:40Z
user: login: tshortli
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T19:33:26Z
user: login: rintaro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T19:39:18Z
user: login: tshortli
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T20:57:47Z
user: login: hamishknight
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T15:59:30Z
user: login: tshortli
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:01:54Z

Review comments:
diff_hunk: @@ -4945,8 +4945,18 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
   void visitAvailableAttr(AvailableAttr *Attr, Label label) {
     printCommon(Attr, "available_attr", label);
 
-    printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
-                  Label::always("domain"));
+    printFlag(Attr->isGroupMember(), "group_member");
+    printFlag(Attr->isGroupedWithWildcard(), "group_with_wildcard");
+    printFlag(Attr->isGroupTerminator(), "group_terminator");
+
+    auto domainOrIdentifier = Attr->getDomainOrIdentifier();
+    printFlag(domainOrIdentifier.isResolved(), "resolved");
path: lib/AST/ASTDumper.cpp
user: login: tshortli
body: The resolved flag seems a bit redundant given that it expresses the same information as `domain` vs `domainIdentifier` below
created_at: 2025-03-06T19:08:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4945,8 +4945,18 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
   void visitAvailableAttr(AvailableAttr *Attr, Label label) {
     printCommon(Attr, "available_attr", label);
 
-    printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
-                  Label::always("domain"));
+    printFlag(Attr->isGroupMember(), "group_member");
+    printFlag(Attr->isGroupedWithWildcard(), "group_with_wildcard");
+    printFlag(Attr->isGroupTerminator(), "group_terminator");
+
+    auto domainOrIdentifier = Attr->getDomainOrIdentifier();
+    printFlag(domainOrIdentifier.isResolved(), "resolved");
path: lib/AST/ASTDumper.cpp
user: login: tshortli
body: I guess it can be "resolved" and still be an identifier if lookup fails. I'm just not sure if we need to reflect that state in this output. Maybe it's useful for debugging though
created_at: 2025-03-06T19:33:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4945,8 +4945,18 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
   void visitAvailableAttr(AvailableAttr *Attr, Label label) {
     printCommon(Attr, "available_attr", label);
 
-    printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
-                  Label::always("domain"));
+    printFlag(Attr->isGroupMember(), "group_member");
+    printFlag(Attr->isGroupedWithWildcard(), "group_with_wildcard");
+    printFlag(Attr->isGroupTerminator(), "group_terminator");
+
+    auto domainOrIdentifier = Attr->getDomainOrIdentifier();
+    printFlag(domainOrIdentifier.isResolved(), "resolved");
path: lib/AST/ASTDumper.cpp
user: login: rintaro
body: It's a dumper. IMO we should include the information as much as possible. That being said let me move this to the `else` branch below
created_at: 2025-03-06T19:39:18Z
author_association: MEMBER
diff_hunk: @@ -4945,8 +4945,18 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
   void visitAvailableAttr(AvailableAttr *Attr, Label label) {
     printCommon(Attr, "available_attr", label);
 
-    printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
-                  Label::always("domain"));
+    printFlag(Attr->isGroupMember(), "group_member");
+    printFlag(Attr->isGroupedWithWildcard(), "group_with_wildcard");
+    printFlag(Attr->isGroupTerminator(), "group_terminator");
+
+    auto domainOrIdentifier = Attr->getDomainOrIdentifier();
+    printFlag(domainOrIdentifier.isResolved(), "resolved");
path: lib/AST/ASTDumper.cpp
user: login: tshortli
body: Thanks, I think that would satisfy me. I realize it's meant for debugging, but I think we should strive to omit extraneous details where we can as they can make reading the dumps overwhelming
created_at: 2025-03-06T20:57:47Z
author_association: CONTRIBUTOR

PR comments:
user: login: tshortli
created_at: 2025-03-06T19:11:59Z
body: In my head, `ASTGen` should not need to know about `AvailabilityDomain` or `AvailabilityDomainOrIdentifier` at all because parsing should always just parse an `Identifier` and construct `AvailableAttr`s and `AvailabilitySpec`s with that. Now that you've abstracted away creation of `@_unavailableInEmbedded` attributes I think it should be possible, am I missing a reason this complexity needs to be bridged to `ASTGen`?
author_association: CONTRIBUTOR
user: login: rintaro
created_at: 2025-03-06T19:31:34Z
body: I'm planning to make it simple in followups. We need `AvailabilityDomainOrIdentifier` in ASTGen at this point only because we need to extract `Identifier` from `AvailabilitySpec`. And we need to do that because availability macros are stored as list of `AvailabilitySpec`.. which is not necessary . It could be just a list of `{Identifier, VersionTuple}`.
author_association: MEMBER
user: login: rintaro
created_at: 2025-03-06T21:18:52Z
body: @swift-ci Please smoke test
author_association: MEMBER
user: login: rintaro
created_at: 2025-03-07T12:16:19Z
body: @swift-ci Please smoke test
author_association: MEMBER
user: login: rintaro
created_at: 2025-03-07T15:19:04Z
body: @swift-ci Please smoke test
author_association: MEMBER