Revision ac4b68fbf45853ba4b9e327cb42f93f42a8fa252 authored by Ellie Shin on 17 March 2023, 04:14:20 UTC, committed by Ellie Shin on 17 March 2023, 04:14:20 UTC
1 parent f2c68fb
Raw File
TypeCheckMacros.cpp
//===--- TypeCheckMacros.cpp -  Macro Handling ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// This file implements support for the evaluation of macros.
//
//===----------------------------------------------------------------------===//

#include "TypeCheckMacros.h"
#include "TypeChecker.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Expr.h"
#include "swift/AST/MacroDefinition.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/PluginRegistry.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Parse/Lexer.h"
#include "swift/Subsystems.h"
#include "llvm/Config/config.h"

#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#else
#include <dlfcn.h>
#endif

using namespace swift;

extern "C" void *swift_ASTGen_resolveMacroType(const void *macroType);
extern "C" void swift_ASTGen_destroyMacro(void *macro);

extern "C" void *swift_ASTGen_resolveExecutableMacro(
    const char *moduleName, ptrdiff_t moduleNameLength,
    const char *typeName, ptrdiff_t typeNameLength,
    void * opaquePluginHandle);
extern "C" void swift_ASTGen_destroyExecutableMacro(void *macro);

extern "C" ptrdiff_t swift_ASTGen_expandFreestandingMacro(
    void *diagEngine, void *macro, uint8_t externalKind,
    const char *discriminator, ptrdiff_t discriminatorLength, void *sourceFile,
    const void *sourceLocation, const char **evaluatedSource,
    ptrdiff_t *evaluatedSourceLength);

extern "C" ptrdiff_t swift_ASTGen_expandAttachedMacro(
    void *diagEngine, void *macro, uint8_t externalKind,
    const char *discriminator, ptrdiff_t discriminatorLength,
    uint8_t rawMacroRole,
    void *customAttrSourceFile, const void *customAttrSourceLocation,
    void *declarationSourceFile, const void *declarationSourceLocation,
    void *parentDeclSourceFile, const void *parentDeclSourceLocation,
    const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);

extern "C" void swift_ASTGen_initializePlugin(void *handle);
extern "C" void swift_ASTGen_deinitializePlugin(void *handle);

/// Produce the mangled name for the nominal type descriptor of a type
/// referenced by its module and type name.
static std::string mangledNameForTypeMetadataAccessor(
    StringRef moduleName, StringRef typeName, Node::Kind typeKind) {
  using namespace Demangle;

  //  kind=Global
  //    kind=NominalTypeDescriptor
  //      kind=Type
  //        kind=Structure|Enum|Class
  //          kind=Module, text=moduleName
  //          kind=Identifier, text=typeName
  Demangle::Demangler D;
  auto *global = D.createNode(Node::Kind::Global);
  {
    auto *nominalDescriptor =
        D.createNode(Node::Kind::TypeMetadataAccessFunction);
    {
      auto *type = D.createNode(Node::Kind::Type);
      {
        auto *module = D.createNode(Node::Kind::Module, moduleName);
        auto *identifier = D.createNode(Node::Kind::Identifier, typeName);
        auto *structNode = D.createNode(typeKind);
        structNode->addChild(module, D);
        structNode->addChild(identifier, D);
        type->addChild(structNode, D);
      }
      nominalDescriptor->addChild(type, D);
    }
    global->addChild(nominalDescriptor, D);
  }

  auto mangleResult = mangleNode(global);
  assert(mangleResult.isSuccess());
  return mangleResult.result();
}

#if SWIFT_SWIFT_PARSER
/// Look for macro's type metadata given its external module and type name.
static void const *lookupMacroTypeMetadataByExternalName(
    ASTContext &ctx, StringRef moduleName, StringRef typeName,
    void *libraryHint = nullptr
) {
  // Look up the type metadata accessor as a struct, enum, or class.
  const Demangle::Node::Kind typeKinds[] = {
    Demangle::Node::Kind::Structure,
    Demangle::Node::Kind::Enum,
    Demangle::Node::Kind::Class
  };

  void *accessorAddr = nullptr;
  for (auto typeKind : typeKinds) {
    auto symbolName = mangledNameForTypeMetadataAccessor(
        moduleName, typeName, typeKind);
    accessorAddr = ctx.getAddressOfSymbol(symbolName.c_str(), libraryHint);
    if (accessorAddr)
      break;
  }

  if (!accessorAddr)
    return nullptr;

  // Call the accessor to form type metadata.
  using MetadataAccessFunc = const void *(MetadataRequest);
  auto accessor = reinterpret_cast<MetadataAccessFunc*>(accessorAddr);
  return accessor(MetadataRequest(MetadataState::Complete));
}
#endif

/// Handle the "A.B" spelling of an external macro definition, from early
/// pitches of the expression-macros proposal, which is also used as the syntax
/// for builtin macro definitions.
///
/// \returns The macro definition if the pattern is recognized, or \c None
/// otherwise.
static Optional<MacroDefinition> handleOldStyleOrBuiltinMacroDefinition(
    ASTContext &ctx, Expr *expr
) {
  auto memberExpr = dyn_cast<UnresolvedDotExpr>(expr);
  if (!memberExpr)
    return None;

  Expr *base = memberExpr->getBase();
  auto baseDeclRef = dyn_cast<UnresolvedDeclRefExpr>(base);
  if (!baseDeclRef)
    return None;

  if (memberExpr->getName().isSpecial() ||
      baseDeclRef->getName().isSpecial())
    return None;

  Identifier moduleName = baseDeclRef->getName().getBaseIdentifier();
  Identifier typeName = memberExpr->getName().getBaseIdentifier();

  // If this is a reference to the builtin module, check if it's a known
  // builtin macro.
  if (moduleName.str().equals("Builtin") && ctx.SILOpts.ParseStdlib) {
    if (typeName.str() == "ExternalMacro") {
      return MacroDefinition::forBuiltin(BuiltinMacroKind::ExternalMacro);
    }

    ctx.Diags.diagnose(
        memberExpr->getLoc(), diag::macro_definition_unknown_builtin,
        typeName
    );

    return MacroDefinition::forInvalid();
  }

  std::string newCode;
  {
    llvm::raw_string_ostream out(newCode);
    out << "#externalMacro(module: \"" << moduleName << "\", type: \""
        << typeName << "\")";
  }

  ctx.Diags.diagnose(
      memberExpr->getLoc(), diag::macro_definition_old_style
  ).fixItReplace(memberExpr->getSourceRange(), newCode);

  return MacroDefinition::forExternal(moduleName, typeName);
}

/// Translate an argument provided as a string literal into an identifier,
/// or return \c None and emit an error if it cannot be done.
Optional<Identifier> getIdentifierFromStringLiteralArgument(
    ASTContext &ctx, MacroExpansionExpr *expansion, unsigned index) {
  auto argList = expansion->getArgs();

  // If there's no argument here, an error was diagnosed elsewhere.
  if (!argList || index >= argList->size()) {
    return None;
  }

  auto arg = argList->getExpr(index);
  auto stringLiteral = dyn_cast<StringLiteralExpr>(arg);
  if (!stringLiteral) {
    ctx.Diags.diagnose(
        arg->getLoc(), diag::external_macro_arg_not_type_name, index
    );

    return None;
  }


  auto contents = stringLiteral->getValue();
  if (!Lexer::isIdentifier(contents)) {
    ctx.Diags.diagnose(
        arg->getLoc(), diag::external_macro_arg_not_type_name, index
    );

    return None;
  }

  return ctx.getIdentifier(contents);
}

/// For a macro expansion expression that is known to be #externalMacro,
/// handle the definition.
static MacroDefinition handleExternalMacroDefinition(
    ASTContext &ctx, MacroExpansionExpr *expansion) {
  // Dig out the module and type name.
  auto moduleName = getIdentifierFromStringLiteralArgument(ctx, expansion, 0);
  if (!moduleName) {
    return MacroDefinition::forInvalid();
  }

  auto typeName = getIdentifierFromStringLiteralArgument(ctx, expansion, 1);
  if (!typeName) {
    return MacroDefinition::forInvalid();
  }

  return MacroDefinition::forExternal(*moduleName, *typeName);
}

MacroDefinition MacroDefinitionRequest::evaluate(
    Evaluator &evaluator, MacroDecl *macro
) const {
  ASTContext &ctx = macro->getASTContext();

  // If no definition was provided, the macro is... undefined, of course.
  auto definition = macro->definition;
  if (!definition)
    return MacroDefinition::forUndefined();

  // Recognize the "A.B" spelling of external macro definitions from early
  // pitches of the feature. This spelling is also used for builtin macro
  // definitions.
  if (auto oldStyleOrBuiltinResult =
          handleOldStyleOrBuiltinMacroDefinition(ctx, definition)) {
    return *oldStyleOrBuiltinResult;
  }

  // At this point, we must have a macro expansion expression.
  auto expansion = dyn_cast<MacroExpansionExpr>(definition);
  if (!expansion) {
    ctx.Diags.diagnose(
        definition->getLoc(), diag::macro_definition_not_expansion
    );

    return MacroDefinition::forInvalid();
  }

  // Handle #externalMacro without requiring a declaration at all.
  // Note: this is a workaround to allow newer compilers to work with
  // older standard libraries.
  if (expansion->getMacroName().getBaseName().userFacingName() ==
          "externalMacro") {
    return handleExternalMacroDefinition(ctx, expansion);
  }

  // Type-check the macro expansion.
  Type resultType = macro->mapTypeIntoContext(macro->getResultInterfaceType());

  constraints::ContextualTypeInfo contextualType {
    TypeLoc::withoutLoc(resultType),
    // FIXME: Add a contextual type purpose for macro definition checking.
    ContextualTypePurpose::CTP_CoerceOperand
  };

  PrettyStackTraceDecl debugStack("type checking macro definition", macro);
  Type typeCheckedType = TypeChecker::typeCheckExpression(
      definition, macro, contextualType,
      TypeCheckExprFlags::DisableMacroExpansions);
  if (!typeCheckedType)
    return MacroDefinition::forInvalid();

  // Dig out the macro that was expanded.
  auto expandedMacro =
      dyn_cast_or_null<MacroDecl>(expansion->getMacroRef().getDecl());
  if (!expandedMacro)
    return MacroDefinition::forInvalid();

  // FIXME: Only external macros are supported at this point.
  auto builtinKind = expandedMacro->getBuiltinKind();
  if (builtinKind != BuiltinMacroKind::ExternalMacro) {
    ctx.Diags.diagnose(
        definition->getLoc(), diag::macro_definition_unsupported
    );

    return MacroDefinition::forInvalid();
  }

  return handleExternalMacroDefinition(ctx, expansion);
}

/// Load a plugin library based on a module name.
static void *loadPluginByName(StringRef searchPath,
                              StringRef moduleName,
                              llvm::vfs::FileSystem &fs,
                              PluginRegistry *registry) {
  SmallString<128> fullPath(searchPath);
  llvm::sys::path::append(fullPath, "lib" + moduleName + LTDL_SHLIB_EXT);
  if (fs.getRealPath(fullPath, fullPath))
    return nullptr;
  auto loadResult = registry->loadLibraryPlugin(fullPath);
  return loadResult ? *loadResult : nullptr;
}

void *CompilerPluginLoadRequest::evaluate(
    Evaluator &evaluator, ASTContext *ctx, Identifier moduleName
) const {
  auto fs = ctx->SourceMgr.getFileSystem();
  auto &searchPathOpts = ctx->SearchPathOpts;
  auto *registry = ctx->getPluginRegistry();
  for (const auto &path : searchPathOpts.PluginSearchPaths) {
    if (auto found = loadPluginByName(path, moduleName.str(), *fs, registry))
      return found;
  }

  return nullptr;
}

static Optional<ExternalMacroDefinition>
resolveInProcessMacro(
    ASTContext &ctx, Identifier moduleName, Identifier typeName,
    void *libraryHint = nullptr
) {
#if SWIFT_SWIFT_PARSER
  /// Look for the type metadata given the external module and type names.
  auto macroMetatype = lookupMacroTypeMetadataByExternalName(
      ctx, moduleName.str(), typeName.str(), libraryHint);
  if (macroMetatype) {
    // Check whether the macro metatype is in-process.
    if (auto inProcess = swift_ASTGen_resolveMacroType(macroMetatype)) {
      // Make sure we clean up after the macro.
      ctx.addCleanup([inProcess]() {
        swift_ASTGen_destroyMacro(inProcess);
      });

      return ExternalMacroDefinition{
          ExternalMacroDefinition::PluginKind::InProcess, inProcess};
    }
  }
#endif
  return None;
}

static Optional<ExternalMacroDefinition>
resolveExecutableMacro(ASTContext &ctx, Identifier moduleName,
                      Identifier typeName) {
#if SWIFT_SWIFT_PARSER
  // Find macros in exectuable plugins.
  auto *executablePlugin =
      ctx.lookupExecutablePluginByModuleName(moduleName);
  if (!executablePlugin)
    return None;

  // FIXME: Ideally this should be done right after invoking the plugin.
  // But plugin loading is in libAST and it can't link ASTGen symbols.
  if (!executablePlugin->isInitialized()) {
    swift_ASTGen_initializePlugin(executablePlugin);
    executablePlugin->setCleanup([executablePlugin] {
      swift_ASTGen_deinitializePlugin(executablePlugin);
    });
  }

  if (auto *execMacro = swift_ASTGen_resolveExecutableMacro(
          moduleName.str().data(), moduleName.str().size(),
          typeName.str().data(), typeName.str().size(), executablePlugin)) {
    // Make sure we clean up after the macro.
    ctx.addCleanup(
        [execMacro]() { swift_ASTGen_destroyExecutableMacro(execMacro); });
    return ExternalMacroDefinition{
        ExternalMacroDefinition::PluginKind::Executable, execMacro};
  }
#endif

  return None;
}

Optional<ExternalMacroDefinition>
ExternalMacroDefinitionRequest::evaluate(Evaluator &evaluator, ASTContext *ctx,
                                         Identifier moduleName,
                                         Identifier typeName) const {
  // Try to load a plugin module from the plugin search paths. If it
  // succeeds, resolve in-process from that plugin
  CompilerPluginLoadRequest loadRequest{ctx, moduleName};
  if (auto loadedLibrary = evaluateOrDefault(
          evaluator, loadRequest, nullptr)) {
    if (auto inProcess = resolveInProcessMacro(
            *ctx, moduleName, typeName, loadedLibrary))
      return *inProcess;
  }

  // Try to resolve in-process.
  if (auto inProcess = resolveInProcessMacro(*ctx, moduleName, typeName))
    return *inProcess;

  // Try executable plugins.
  if (auto executableMacro =
          resolveExecutableMacro(*ctx, moduleName, typeName)) {
    return executableMacro;
  }

  return None;
}

/// Adjust the given mangled name for a macro expansion to produce a valid
/// buffer name.
static std::string adjustMacroExpansionBufferName(StringRef name) {
  std::string result;
  if (name.startswith(MANGLING_PREFIX_STR)) {
    result += MACRO_EXPANSION_BUFFER_MANGLING_PREFIX;
    name = name.drop_front(StringRef(MANGLING_PREFIX_STR).size());
  }

  result += name;
  result += ".swift";
  return result;
}

ArrayRef<unsigned> ExpandMemberAttributeMacros::evaluate(Evaluator &evaluator,
                                                         Decl *decl) const {
  if (decl->isImplicit())
    return { };

  auto *parentDecl = decl->getDeclContext()->getAsDecl();
  if (!parentDecl)
    return { };

  if (isa<PatternBindingDecl>(decl))
    return { };

  SmallVector<unsigned, 2> bufferIDs;
  parentDecl->forEachAttachedMacro(MacroRole::MemberAttribute,
      [&](CustomAttr *attr, MacroDecl *macro) {
        if (auto bufferID = expandAttributes(attr, macro, decl))
          bufferIDs.push_back(*bufferID);
      });

  return parentDecl->getASTContext().AllocateCopy(bufferIDs);
}

ArrayRef<unsigned> ExpandSynthesizedMemberMacroRequest::evaluate(
    Evaluator &evaluator, Decl *decl
) const {
  SmallVector<unsigned, 2> bufferIDs;
  decl->forEachAttachedMacro(MacroRole::Member,
      [&](CustomAttr *attr, MacroDecl *macro) {
        if (auto bufferID = expandMembers(attr, macro, decl))
          bufferIDs.push_back(*bufferID);
      });

  return decl->getASTContext().AllocateCopy(bufferIDs);
}

ArrayRef<unsigned>
ExpandPeerMacroRequest::evaluate(Evaluator &evaluator, Decl *decl) const {
  SmallVector<unsigned, 2> bufferIDs;
  decl->forEachAttachedMacro(MacroRole::Peer,
      [&](CustomAttr *attr, MacroDecl *macro) {
        if (auto bufferID = expandPeers(attr, macro, decl))
          bufferIDs.push_back(*bufferID);
      });

  return decl->getASTContext().AllocateCopy(bufferIDs);
}

static Identifier makeIdentifier(ASTContext &ctx, StringRef name) {
  return ctx.getIdentifier(name);
}

static Identifier makeIdentifier(ASTContext &ctx, std::nullptr_t) {
  return Identifier();
}

/// Diagnose macro expansions that produce any of the following declarations:
///   - Import declarations
///   - Operator and precedence group declarations
///   - Macro declarations
///   - Extensions
///   - Types with `@main` attributes
///   - Top-level default literal type overrides
///   - Value decls with names not covered by the macro declaration.
static void validateMacroExpansion(SourceFile *expansionBuffer,
                                   MacroDecl *macro,
                                   ValueDecl *attachedTo,
                                   MacroRole role) {
  // Gather macro-introduced names
  llvm::SmallVector<DeclName, 2> introducedNames;
  macro->getIntroducedNames(role, attachedTo, introducedNames);

  llvm::SmallDenseSet<DeclName, 2> coversName(introducedNames.begin(),
                                              introducedNames.end());

  for (auto *decl : expansionBuffer->getTopLevelDecls()) {
    auto &ctx = decl->getASTContext();

    // Certain macro roles can generate special declarations.
    if ((isa<AccessorDecl>(decl) && role == MacroRole::Accessor) ||
        (isa<ExtensionDecl>(decl) && role == MacroRole::Conformance)) {
      continue;
    }

    // Diagnose invalid declaration kinds.
    if (isa<ImportDecl>(decl) ||
        isa<OperatorDecl>(decl) ||
        isa<PrecedenceGroupDecl>(decl) ||
        isa<MacroDecl>(decl) ||
        isa<ExtensionDecl>(decl)) {
      decl->diagnose(diag::invalid_decl_in_macro_expansion,
                     decl->getDescriptiveKind());
      decl->setInvalid();

      if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
        extension->setExtendedNominal(nullptr);
      }

      continue;
    }

    // Diagnose `@main` types.
    if (auto *mainAttr = decl->getAttrs().getAttribute<MainTypeAttr>()) {
      ctx.Diags.diagnose(mainAttr->getLocation(),
                         diag::invalid_main_type_in_macro_expansion);
      mainAttr->setInvalid();
    }

    // Diagnose default literal type overrides.
    if (auto *typeAlias = dyn_cast<TypeAliasDecl>(decl)) {
      auto name = typeAlias->getBaseIdentifier();
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(_, __, typeName,     \
                                                  supportsOverride)    \
      if (supportsOverride && name == makeIdentifier(ctx, typeName)) { \
        typeAlias->diagnose(diag::literal_type_in_macro_expansion,     \
                            makeIdentifier(ctx, typeName));            \
        typeAlias->setInvalid();                                       \
        continue;                                                      \
      }
#include "swift/AST/KnownProtocols.def"
#undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
    }

    // Diagnose value decls with names not covered by the macro
    if (auto *value = dyn_cast<ValueDecl>(decl)) {
      auto baseName = value->getBaseName();
      if (baseName.isSpecial()) {
        baseName = ctx.getIdentifier(baseName.userFacingName());
      }

      // $-prefixed names are unique names. These are always allowed.
      if (baseName.getIdentifier().hasDollarPrefix()) {
        continue;
      }

      if (coversName.count(baseName) ||
          coversName.count(MacroDecl::getArbitraryName())) {
        continue;
      }

      value->diagnose(diag::invalid_macro_introduced_name,
                      baseName, macro->getBaseName());
    }
  }
}

/// Determine whether the given source file is from an expansion of the given
/// macro.
static bool isFromExpansionOfMacro(SourceFile *sourceFile, MacroDecl *macro,
                                   MacroRole role) {
  while (sourceFile) {
    auto expansion = sourceFile->getMacroExpansion();
    if (!expansion)
      return false;

    if (auto expansionExpr = dyn_cast_or_null<MacroExpansionExpr>(
            expansion.dyn_cast<Expr *>())) {
      if (expansionExpr->getMacroRef().getDecl() == macro)
        return true;
    } else if (auto expansionDecl = dyn_cast_or_null<MacroExpansionDecl>(
            expansion.dyn_cast<Decl *>())) {
      if (expansionDecl->getMacroRef().getDecl() == macro)
        return true;
    } else if (auto *macroAttr = sourceFile->getAttachedMacroAttribute()) {
      auto *decl = expansion.dyn_cast<Decl *>();
      auto *macroDecl = decl->getResolvedMacro(macroAttr);
      if (!macroDecl)
        return false;

      return macroDecl == macro &&
             sourceFile->getFulfilledMacroRole() == role;
    } else {
      llvm_unreachable("Unknown macro expansion node kind");
    }

    sourceFile = sourceFile->getEnclosingSourceFile();
  }

  return false;
}

Expr *swift::expandMacroExpr(
    DeclContext *dc, Expr *expr, ConcreteDeclRef macroRef, Type expandedType
) {
  ASTContext &ctx = dc->getASTContext();
  SourceManager &sourceMgr = ctx.SourceMgr;

  auto moduleDecl = dc->getParentModule();
  auto sourceFile = moduleDecl->getSourceFileContainingLocation(expr->getLoc());
  if (!sourceFile)
    return nullptr;

  // Evaluate the macro.
  NullTerminatedStringRef evaluatedSource;

  MacroDecl *macro = cast<MacroDecl>(macroRef.getDecl());

  if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression)) {
    ctx.Diags.diagnose(expr->getLoc(), diag::macro_recursive, macro->getName());
    return nullptr;
  }

  std::string discriminator;
  auto macroDef = macro->getDefinition();
  switch (macroDef.kind) {
  case MacroDefinition::Kind::Undefined:
  case MacroDefinition::Kind::Invalid:
    // Already diagnosed as an error elsewhere.
    return nullptr;

  case MacroDefinition::Kind::Builtin: {
    switch (macroDef.getBuiltinKind()) {
    case BuiltinMacroKind::ExternalMacro:
      ctx.Diags.diagnose(
          expr->getLoc(), diag::external_macro_outside_macro_definition);
      return nullptr;
    }
  }

  case MacroDefinition::Kind::External: {
    // Retrieve the external definition of the macro.
    auto external = macroDef.getExternalMacro();
    ExternalMacroDefinitionRequest request{
      &ctx, external.moduleName, external.macroTypeName
    };
    auto externalDef = evaluateOrDefault(ctx.evaluator, request, None);
    if (!externalDef) {
      ctx.Diags.diagnose(
          expr->getLoc(), diag::external_macro_not_found,
          external.moduleName.str(),
          external.macroTypeName.str(),
          macro->getName()
      );
      macro->diagnose(diag::decl_declared_here, macro->getName());
      return nullptr;
    }

#if SWIFT_SWIFT_PARSER
    PrettyStackTraceExpr debugStack(ctx, "expanding macro", expr);

    // Builtin macros are handled via ASTGen.
    auto astGenSourceFile = sourceFile->exportedSourceFile;
    if (!astGenSourceFile)
      return nullptr;

    if (auto expansionExpr = dyn_cast<MacroExpansionExpr>(expr)) {
      Mangle::ASTMangler mangler;
      discriminator = mangler.mangleMacroExpansion(expansionExpr);
    }

    const char *evaluatedSourceAddress;
    ptrdiff_t evaluatedSourceLength;
    swift_ASTGen_expandFreestandingMacro(
        &ctx.Diags, externalDef->opaqueHandle,
        static_cast<uint32_t>(externalDef->kind), discriminator.data(),
        discriminator.size(), astGenSourceFile,
        expr->getStartLoc().getOpaquePointerValue(), &evaluatedSourceAddress,
        &evaluatedSourceLength);
    if (!evaluatedSourceAddress)
      return nullptr;
    evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress,
                                              (size_t)evaluatedSourceLength);
    break;
#else
    ctx.Diags.diagnose(expr->getLoc(), diag::macro_unsupported);
    return nullptr;
#endif
  }
  }

  // Figure out a reasonable name for the macro expansion buffer.
  std::string bufferName;
  if (discriminator.empty())
    bufferName = "macro-expansion";
  else {
    bufferName = adjustMacroExpansionBufferName(discriminator);
  }

  // Dump macro expansions to standard output, if requested.
  if (ctx.LangOpts.DumpMacroExpansions) {
    llvm::errs() << bufferName << " as " << expandedType.getString()
                 << "\n------------------------------\n"
                 << evaluatedSource
                 << "\n------------------------------\n";
  }

  // Create a new source buffer with the contents of the expanded macro.
  auto macroBuffer =
      llvm::MemoryBuffer::getMemBufferCopy(evaluatedSource, bufferName);
  unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
  auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID);
  GeneratedSourceInfo sourceInfo{
    GeneratedSourceInfo::ExpressionMacroExpansion,
    Lexer::getCharSourceRangeFromSourceRange(
      sourceMgr, expr->getSourceRange()),
    macroBufferRange,
    ASTNode(expr).getOpaqueValue(),
    dc
  };
  sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo);
  free((void*)evaluatedSource.data());

  // Create a source file to hold the macro buffer. This is automatically
  // registered with the enclosing module.
  auto macroSourceFile = new (ctx) SourceFile(
      *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID,
      /*parsingOpts=*/{}, /*isPrimary=*/false);
  macroSourceFile->setImports(sourceFile->getImports());

  // Retrieve the parsed expression from the list of top-level items.
  auto topLevelItems = macroSourceFile->getTopLevelItems();
  Expr *expandedExpr = nullptr;
  if (topLevelItems.size() != 1) {
    ctx.Diags.diagnose(
        macroBufferRange.getStart(), diag::expected_macro_expansion_expr);
    return nullptr;
  }

  auto codeItem = topLevelItems.front();
  if (auto *expr = codeItem.dyn_cast<Expr *>())
    expandedExpr = expr;

  if (!expandedExpr) {
    ctx.Diags.diagnose(
        macroBufferRange.getStart(), diag::expected_macro_expansion_expr);
    return nullptr;
  }

  // Type-check the expanded expression.
  // FIXME: Would like to pass through type checking options like "discarded"
  // that are captured by TypeCheckExprOptions.
  constraints::ContextualTypeInfo contextualType {
    TypeLoc::withoutLoc(expandedType),
    // FIXME: Add a contextual type purpose for macro expansion.
    ContextualTypePurpose::CTP_CoerceOperand
  };

  PrettyStackTraceExpr debugStack(
      ctx, "type checking expanded macro", expandedExpr);
  Type realExpandedType = TypeChecker::typeCheckExpression(
      expandedExpr, dc, contextualType);
  if (!realExpandedType)
    return nullptr;

  assert((expandedType->isEqual(realExpandedType) ||
          realExpandedType->hasError()) &&
         "Type checking changed the result type?");
  return expandedExpr;
}

/// Expands the given macro expansion declaration.
Optional<unsigned>
swift::expandFreestandingMacro(MacroExpansionDecl *med) {
  auto *dc = med->getDeclContext();
  ASTContext &ctx = dc->getASTContext();
  SourceManager &sourceMgr = ctx.SourceMgr;

  auto moduleDecl = dc->getParentModule();
  auto sourceFile = moduleDecl->getSourceFileContainingLocation(med->getLoc());
  if (!sourceFile)
    return None;

  // Evaluate the macro.
  NullTerminatedStringRef evaluatedSource;

  MacroDecl *macro = cast<MacroDecl>(med->getMacroRef().getDecl());
  assert(macro->getMacroRoles().contains(MacroRole::Declaration));

  if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression) ||
      isFromExpansionOfMacro(sourceFile, macro, MacroRole::Declaration)) {
    med->diagnose(diag::macro_recursive, macro->getName());
    return None;
  }

  auto macroDef = macro->getDefinition();
  switch (macroDef.kind) {
  case MacroDefinition::Kind::Undefined:
  case MacroDefinition::Kind::Invalid:
    // Already diagnosed as an error elsewhere.
    return None;

  case MacroDefinition::Kind::Builtin: {
    switch (macroDef.getBuiltinKind()) {
    case BuiltinMacroKind::ExternalMacro:
      // FIXME: Error here.
      return None;
    }
  }

  case MacroDefinition::Kind::External: {
    // Retrieve the external definition of the macro.
    auto external = macroDef.getExternalMacro();
    ExternalMacroDefinitionRequest request{
        &ctx, external.moduleName, external.macroTypeName
    };
    auto externalDef = evaluateOrDefault(ctx.evaluator, request, None);
    if (!externalDef) {
      med->diagnose(diag::external_macro_not_found,
                    external.moduleName.str(),
                    external.macroTypeName.str(),
                    macro->getName()
      );
      macro->diagnose(diag::decl_declared_here, macro->getName());
      return None;
    }

    // Make sure freestanding macros are enabled before we expand.
    if (!ctx.LangOpts.hasFeature(Feature::FreestandingMacros) &&
        !macro->getMacroRoles().contains(MacroRole::Expression)) {
      med->diagnose(
          diag::macro_experimental, "freestanding", "FreestandingMacros");
      return None;
    }

#if SWIFT_SWIFT_PARSER
    PrettyStackTraceDecl debugStack("expanding declaration macro", med);

    // Builtin macros are handled via ASTGen.
    auto astGenSourceFile = sourceFile->exportedSourceFile;
    if (!astGenSourceFile)
      return None;

    Mangle::ASTMangler mangler;
    auto discriminator = mangler.mangleMacroExpansion(med);

    const char *evaluatedSourceAddress;
    ptrdiff_t evaluatedSourceLength;
    swift_ASTGen_expandFreestandingMacro(
        &ctx.Diags, externalDef->opaqueHandle,
        static_cast<uint32_t>(externalDef->kind), discriminator.data(),
        discriminator.size(), astGenSourceFile,
        med->getStartLoc().getOpaquePointerValue(), &evaluatedSourceAddress,
        &evaluatedSourceLength);
    if (!evaluatedSourceAddress)
      return None;
    evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress,
                                              (size_t)evaluatedSourceLength);
    break;
#else
    med->diagnose(diag::macro_unsupported);
    return None;
#endif
  }
  }

  // Figure out a reasonable name for the macro expansion buffer.
  std::string bufferName;
  {
    Mangle::ASTMangler mangler;
    bufferName = adjustMacroExpansionBufferName(
        mangler.mangleMacroExpansion(med));
  }

  // Dump macro expansions to standard output, if requested.
  if (ctx.LangOpts.DumpMacroExpansions) {
    llvm::errs() << bufferName
                 << "\n------------------------------\n"
                 << evaluatedSource
                 << "\n------------------------------\n";
  }

  // Create a new source buffer with the contents of the expanded macro.
  auto macroBuffer =
      llvm::MemoryBuffer::getMemBufferCopy(evaluatedSource, bufferName);
  unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
  auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID);
  GeneratedSourceInfo sourceInfo{
      GeneratedSourceInfo::FreestandingDeclMacroExpansion,
      Lexer::getCharSourceRangeFromSourceRange(
        sourceMgr, med->getSourceRange()),
      macroBufferRange,
      ASTNode(med).getOpaqueValue(),
      dc
  };
  sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo);
  free((void*)evaluatedSource.data());

  // Create a source file to hold the macro buffer. This is automatically
  // registered with the enclosing module.
  auto macroSourceFile = new (ctx) SourceFile(
      *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID,
      /*parsingOpts=*/{}, /*isPrimary=*/false);
  macroSourceFile->setImports(sourceFile->getImports());

  validateMacroExpansion(macroSourceFile, macro,
                         /*attachedTo*/nullptr,
                         MacroRole::Declaration);

  PrettyStackTraceDecl debugStack(
      "type checking expanded declaration macro", med);

  auto topLevelItems = macroSourceFile->getTopLevelItems();
  for (auto item : topLevelItems) {
    if (auto *decl = item.dyn_cast<Decl *>())
      decl->setDeclContext(dc);
  }
  return macroBufferID;
}

// If this storage declaration is a variable with an explicit initializer,
// return the range from the `=` to the end of the explicit initializer.
static Optional<SourceRange> getExplicitInitializerRange(
    AbstractStorageDecl *storage) {
  auto var = dyn_cast<VarDecl>(storage);
  if (!var)
    return None;

  auto pattern = var->getParentPatternBinding();
  if (!pattern)
    return None;

  unsigned index = pattern->getPatternEntryIndexForVarDecl(var);
  SourceLoc equalLoc = pattern->getEqualLoc(index);
  SourceRange initRange = pattern->getOriginalInitRange(index);
  if (equalLoc.isInvalid() || initRange.End.isInvalid())
    return None;

  return SourceRange(equalLoc, initRange.End);
}

static SourceFile *
evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr,
                      bool passParentContext, MacroRole role) {
  DeclContext *dc;
  if (role == MacroRole::Peer) {
    dc = attachedTo->getDeclContext();
  } else if (role == MacroRole::Conformance) {
    // Conformance macros always expand to extensions at file-scope.
    dc = attachedTo->getDeclContext()->getParentSourceFile();
  } else {
    dc = attachedTo->getInnermostDeclContext();
  }

  ASTContext &ctx = dc->getASTContext();
  SourceManager &sourceMgr = ctx.SourceMgr;

  auto moduleDecl = dc->getParentModule();

  auto attrSourceFile =
    moduleDecl->getSourceFileContainingLocation(attr->AtLoc);
  if (!attrSourceFile)
    return nullptr;

  auto declSourceFile =
      moduleDecl->getSourceFileContainingLocation(attachedTo->getStartLoc());
  if (!declSourceFile)
    return nullptr;

  Decl *parentDecl = nullptr;
  SourceFile *parentDeclSourceFile = nullptr;
  if (passParentContext) {
    parentDecl = attachedTo->getDeclContext()->getAsDecl();
    if (!parentDecl)
      return nullptr;

    parentDeclSourceFile =
      moduleDecl->getSourceFileContainingLocation(parentDecl->getLoc());
    if (!parentDeclSourceFile)
      return nullptr;
  }

  if (isFromExpansionOfMacro(attrSourceFile, macro, role) ||
      isFromExpansionOfMacro(declSourceFile, macro, role) ||
      isFromExpansionOfMacro(parentDeclSourceFile, macro, role)) {
    attachedTo->diagnose(diag::macro_recursive, macro->getName());
    return nullptr;
  }

  // Evaluate the macro.
  NullTerminatedStringRef evaluatedSource;

  std::string discriminator;
  auto macroDef = macro->getDefinition();
  switch (macroDef.kind) {
  case MacroDefinition::Kind::Undefined:
  case MacroDefinition::Kind::Invalid:
    // Already diagnosed as an error elsewhere.
    return nullptr;

  case MacroDefinition::Kind::Builtin: {
    switch (macroDef.getBuiltinKind()) {
    case BuiltinMacroKind::ExternalMacro:
      // FIXME: Error here.
      return nullptr;
    }
  }

  case MacroDefinition::Kind::External: {
    // Retrieve the external definition of the macro.
    auto external = macroDef.getExternalMacro();
    ExternalMacroDefinitionRequest request{
        &ctx, external.moduleName, external.macroTypeName
    };
    auto externalDef = evaluateOrDefault(ctx.evaluator, request, None);
    if (!externalDef) {
      attachedTo->diagnose(diag::external_macro_not_found,
                        external.moduleName.str(),
                        external.macroTypeName.str(),
                        macro->getName()
      );
      macro->diagnose(diag::decl_declared_here, macro->getName());
      return nullptr;
    }

#if SWIFT_SWIFT_PARSER
    PrettyStackTraceDecl debugStack("expanding attached macro", attachedTo);

    auto astGenAttrSourceFile = attrSourceFile->exportedSourceFile;
    if (!astGenAttrSourceFile)
      return nullptr;

    auto astGenDeclSourceFile = declSourceFile->exportedSourceFile;
    if (!astGenDeclSourceFile)
      return nullptr;

    void *astGenParentDeclSourceFile = nullptr;
    const void *parentDeclLoc = nullptr;
    if (passParentContext) {
      astGenParentDeclSourceFile = parentDeclSourceFile->exportedSourceFile;
      if (!astGenParentDeclSourceFile)
        return nullptr;

      parentDeclLoc = parentDecl->getStartLoc().getOpaquePointerValue();
    }

    Decl *searchDecl = attachedTo;
    if (auto var = dyn_cast<VarDecl>(attachedTo))
      searchDecl = var->getParentPatternBinding();

    {
      Mangle::ASTMangler mangler;
      discriminator =
        mangler.mangleAttachedMacroExpansion(attachedTo, attr, role);
    }

    const char *evaluatedSourceAddress;
    ptrdiff_t evaluatedSourceLength;
    swift_ASTGen_expandAttachedMacro(
        &ctx.Diags, externalDef->opaqueHandle,
        static_cast<uint32_t>(externalDef->kind), discriminator.data(),
        discriminator.size(), static_cast<uint32_t>(role), astGenAttrSourceFile,
        attr->AtLoc.getOpaquePointerValue(), astGenDeclSourceFile,
        searchDecl->getStartLoc().getOpaquePointerValue(),
        astGenParentDeclSourceFile, parentDeclLoc, &evaluatedSourceAddress,
        &evaluatedSourceLength);
    if (!evaluatedSourceAddress)
      return nullptr;
    evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress,
                                              (size_t)evaluatedSourceLength);
    break;
#else
    attachedTo->diagnose(diag::macro_unsupported);
    return nullptr;
#endif
  }
  }

  // Figure out a reasonable name for the macro expansion buffer.
  std::string bufferName = adjustMacroExpansionBufferName(discriminator);

  // Dump macro expansions to standard output, if requested.
  if (ctx.LangOpts.DumpMacroExpansions) {
    llvm::errs() << bufferName
                 << "\n------------------------------\n"
                 << evaluatedSource
                 << "\n------------------------------\n";
  }

  CharSourceRange generatedOriginalSourceRange;
  GeneratedSourceInfo::Kind generatedSourceKind;
  switch (role) {
  case MacroRole::Accessor: {
    generatedSourceKind = GeneratedSourceInfo::AccessorMacroExpansion;

    // Compute the location where the accessors will be added.
    auto storage = cast<AbstractStorageDecl>(attachedTo);
    auto bracesRange = storage->getBracesRange();
    if (bracesRange.Start.isValid()) {
      // We have braces already, so insert them inside the leading '{'.
      generatedOriginalSourceRange = CharSourceRange(
         Lexer::getLocForEndOfToken(sourceMgr, bracesRange.Start), 0);
    } else if (auto initRange = getExplicitInitializerRange(storage)) {
      // The accessor had an initializer, so the initializer (including
      // the `=`) is replaced by the accessors.
      generatedOriginalSourceRange =
          Lexer::getCharSourceRangeFromSourceRange(sourceMgr, *initRange);
    } else {
      // The accessors go at the end.
      SourceLoc endLoc = storage->getEndLoc();
      if (auto var = dyn_cast<VarDecl>(storage)) {
        if (auto pattern = var->getParentPattern())
          endLoc = pattern->getEndLoc();
      }

      generatedOriginalSourceRange = CharSourceRange(
         Lexer::getLocForEndOfToken(sourceMgr, endLoc), 0);
    }

    break;
  }

  case MacroRole::MemberAttribute: {
    generatedSourceKind = GeneratedSourceInfo::MemberAttributeMacroExpansion;
    SourceLoc startLoc;
    if (auto valueDecl = dyn_cast<ValueDecl>(attachedTo))
      startLoc = valueDecl->getAttributeInsertionLoc(/*forModifier=*/false);
    else
      startLoc = attachedTo->getStartLoc();

    generatedOriginalSourceRange = CharSourceRange(startLoc, 0);
    break;
  }

  case MacroRole::Member: {
    generatedSourceKind = GeneratedSourceInfo::MemberMacroExpansion;

    // Semantically, we insert members right before the closing brace.
    SourceLoc rightBraceLoc;
    if (auto nominal = dyn_cast<NominalTypeDecl>(attachedTo)) {
      rightBraceLoc = nominal->getBraces().End;
    } else {
      auto ext = cast<ExtensionDecl>(parentDecl);
      rightBraceLoc = ext->getBraces().End;
    }

    generatedOriginalSourceRange = CharSourceRange(rightBraceLoc, 0);
    break;
  }

  case MacroRole::Peer: {
    generatedSourceKind = GeneratedSourceInfo::PeerMacroExpansion;
    SourceLoc afterDeclLoc =
        Lexer::getLocForEndOfToken(sourceMgr, attachedTo->getEndLoc());
    generatedOriginalSourceRange = CharSourceRange(afterDeclLoc, 0);
    break;
  }

  case MacroRole::Conformance: {
    generatedSourceKind = GeneratedSourceInfo::ConformanceMacroExpansion;
    SourceLoc afterDeclLoc =
        Lexer::getLocForEndOfToken(sourceMgr, attachedTo->getEndLoc());
    generatedOriginalSourceRange = CharSourceRange(afterDeclLoc, 0);
    break;
  }

  case MacroRole::Expression:
  case MacroRole::Declaration:
    llvm_unreachable("freestanding macro in attached macro evaluation");
  }

  // Create a new source buffer with the contents of the expanded macro.
  auto macroBuffer =
      llvm::MemoryBuffer::getMemBufferCopy(evaluatedSource, bufferName);
  unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
  auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID);
  GeneratedSourceInfo sourceInfo{
      generatedSourceKind,
      generatedOriginalSourceRange,
      macroBufferRange,
      ASTNode(attachedTo).getOpaqueValue(),
      dc,
      attr
  };
  sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo);
  free((void*)evaluatedSource.data());

  // Create a source file to hold the macro buffer. This is automatically
  // registered with the enclosing module.
  auto macroSourceFile = new (ctx) SourceFile(
      *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID,
      /*parsingOpts=*/{}, /*isPrimary=*/false);
  macroSourceFile->setImports(declSourceFile->getImports());

  validateMacroExpansion(macroSourceFile, macro,
                         dyn_cast<ValueDecl>(attachedTo), role);
  return macroSourceFile;
}

Optional<unsigned> swift::expandAccessors(
    AbstractStorageDecl *storage, CustomAttr *attr, MacroDecl *macro
) {
  // Evaluate the macro.
  auto macroSourceFile = evaluateAttachedMacro(macro, storage, attr,
                                               /*passParentContext*/false,
                                               MacroRole::Accessor);
  if (!macroSourceFile)
    return None;

  PrettyStackTraceDecl debugStack(
      "type checking expanded declaration macro", storage);

  // Trigger parsing of the sequence of accessor declarations. This has the
  // side effect of registering those accessor declarations with the storage
  // declaration, so there is nothing further to do.
  for (auto decl : macroSourceFile->getTopLevelItems()) {
    auto accessor = dyn_cast_or_null<AccessorDecl>(decl.dyn_cast<Decl *>());
    if (!accessor)
      continue;

    if (accessor->isObservingAccessor())
      continue;

    // If any non-observing accessor was added, remove the initializer if
    // there is one.
    if (auto var = dyn_cast<VarDecl>(storage)) {
      if (auto binding = var->getParentPatternBinding()) {
        unsigned index = binding->getPatternEntryIndexForVarDecl(var);
        binding->setInit(index, nullptr);
        break;
      }
    }
  }

  return macroSourceFile->getBufferID();
}

ArrayRef<unsigned> ExpandAccessorMacros::evaluate(
    Evaluator &evaluator, AbstractStorageDecl *storage
) const {
  llvm::SmallVector<unsigned, 1> bufferIDs;
  storage->forEachAttachedMacro(MacroRole::Accessor,
      [&](CustomAttr *customAttr, MacroDecl *macro) {
        if (auto bufferID = expandAccessors(
                storage, customAttr, macro))
          bufferIDs.push_back(*bufferID);
      });

  return storage->getASTContext().AllocateCopy(bufferIDs);
}

Optional<unsigned>
swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) {
  // Evaluate the macro.
  auto macroSourceFile = evaluateAttachedMacro(macro, member, attr,
                                               /*passParentContext*/true,
                                               MacroRole::MemberAttribute);
  if (!macroSourceFile)
    return None;

  PrettyStackTraceDecl debugStack(
      "type checking expanded declaration macro", member);

  auto topLevelDecls = macroSourceFile->getTopLevelDecls();
  for (auto decl : topLevelDecls) {
    // Add the new attributes to the semantic attribute list.
    SmallVector<DeclAttribute *, 2> attrs(decl->getAttrs().begin(),
                                          decl->getAttrs().end());
    for (auto *attr : attrs) {
      member->getAttrs().add(attr);
    }
  }

  return macroSourceFile->getBufferID();
}

Optional<unsigned>
swift::expandMembers(CustomAttr *attr, MacroDecl *macro, Decl *decl) {
  // Evaluate the macro.
  auto macroSourceFile = evaluateAttachedMacro(macro, decl, attr,
                                               /*passParentContext*/false,
                                               MacroRole::Member);
  if (!macroSourceFile)
    return None;

  PrettyStackTraceDecl debugStack(
      "type checking expanded declaration macro", decl);

  auto topLevelDecls = macroSourceFile->getTopLevelDecls();
  for (auto member : topLevelDecls) {
    // Note that synthesized members are not considered implicit. They have
    // proper source ranges that should be validated, and ASTScope does not
    // expand implicit scopes to the parent scope tree.

    if (auto *nominal = dyn_cast<NominalTypeDecl>(decl)) {
      nominal->addMember(member);
    } else if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
      extension->addMember(member);
    }
  }

  return macroSourceFile->getBufferID();
}

Optional<unsigned>
swift::expandPeers(CustomAttr *attr, MacroDecl *macro, Decl *decl) {
  auto macroSourceFile = evaluateAttachedMacro(macro, decl, attr,
                                               /*passParentContext*/false,
                                               MacroRole::Peer);
  if (!macroSourceFile)
    return None;

  PrettyStackTraceDecl debugStack("applying expanded peer macro", decl);
  return macroSourceFile->getBufferID();
}

ArrayRef<unsigned>
ExpandConformanceMacros::evaluate(Evaluator &evaluator,
                                  NominalTypeDecl *nominal) const {
  SmallVector<unsigned, 2> bufferIDs;
  nominal->forEachAttachedMacro(MacroRole::Conformance,
      [&](CustomAttr *attr, MacroDecl *macro) {
        if (auto bufferID = expandConformances(attr, macro, nominal))
          bufferIDs.push_back(*bufferID);
      });

  return nominal->getASTContext().AllocateCopy(bufferIDs);
}

Optional<unsigned>
swift::expandConformances(CustomAttr *attr, MacroDecl *macro,
                          NominalTypeDecl *nominal) {
  auto macroSourceFile =
      evaluateAttachedMacro(macro, nominal, attr,
                            /*passParentContext*/false,
                            MacroRole::Conformance);

  if (!macroSourceFile)
    return None;

  PrettyStackTraceDecl debugStack(
      "applying expanded conformance macro", nominal);

  auto topLevelDecls = macroSourceFile->getTopLevelDecls();
  for (auto *decl : topLevelDecls) {
    auto *extension = dyn_cast<ExtensionDecl>(decl);
    if (!extension)
      continue;

    // Bind the extension to the original nominal type.
    extension->setExtendedNominal(nominal);
    nominal->addExtension(extension);

    // Make it accessible to getTopLevelDecls()
    if (auto file = dyn_cast<FileUnit>(
            decl->getDeclContext()->getModuleScopeContext()))
      file->getOrCreateSynthesizedFile().addTopLevelDecl(extension);
  }

  return macroSourceFile->getBufferID();
}

ConcreteDeclRef
ResolveMacroRequest::evaluate(Evaluator &evaluator,
                              UnresolvedMacroReference macroRef,
                              DeclContext *dc) const {
  auto &ctx = dc->getASTContext();
  auto roles = macroRef.getMacroRoles();
  auto foundMacros = TypeChecker::lookupMacros(
      dc, macroRef.getMacroName(), SourceLoc(), roles);
  if (foundMacros.empty())
    return ConcreteDeclRef();

  // If we already have a MacroExpansionExpr, use that. Otherwise,
  // create one.
  MacroExpansionExpr *macroExpansion;
  if (auto *expr = macroRef.getExpr()) {
    macroExpansion = expr;
  } else {
    SourceRange genericArgsRange = macroRef.getGenericArgsRange();
    macroExpansion = new (ctx) MacroExpansionExpr(
      dc, macroRef.getSigilLoc(), macroRef.getMacroName(),
      macroRef.getMacroNameLoc(), genericArgsRange.Start,
      macroRef.getGenericArgs(), genericArgsRange.End,
      macroRef.getArgs(), roles);
  }

  Expr *result = macroExpansion;
  TypeChecker::typeCheckExpression(
      result, dc, {}, TypeCheckExprFlags::DisableMacroExpansions);

  // If we couldn't resolve a macro decl, the attribute is invalid.
  if (!macroExpansion->getMacroRef() && macroRef.getAttr())
    macroRef.getAttr()->setInvalid();

  return macroExpansion->getMacroRef();
}
back to top