Repository: apple/swift
File: lib/Sema/TypeCheckAttr.cpp (C++)

Code before:
      /*FnRetType=*/TupleType::getEmpty(context), declContext);
  func->setSynthesized(true);
  // It's never useful to provide a dynamic replacement of this function--it is
  // just a pass-through to MainType.main.
  func->setIsDynamic(false);

  auto *params = context.Allocate<MainTypeAttrParams>();
  params->mainFunction = mainFunction;
  params->attr = attr;
  func->setBodySynthesizer(synthesizeMainBody, params);

  iterableDeclContext->addMember(func);

  return func;
}

void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) {
  auto &context = D->getASTContext();

  SourceFile *file = D->getDeclContext()->getParentSourceFile();
  assert(file);

  auto *func = evaluateOrDefault(context.evaluator,
                                 SynthesizeMainFunctionRequest{D},
                                 nullptr);

  if (!func)
    return;

  // Register the func as the main decl in the module. If there are multiples
  // they will be diagnosed.
  if (file->registerMainDecl(func, attr->getLocation()))
    attr->setInvalid();
}

/// Determine whether the given context is an extension to an Objective-C class
/// where the class is defined in the Objective-C module and the extension is
/// defined within its module.
static bool isObjCClassExtensionInOverlay(DeclContext *dc) {
  // Check whether we have an extension.
  auto ext = dyn_cast<ExtensionDecl>(dc);
  if (!ext)
    return false;

  // Find the extended class.
  auto classDecl = ext->getSelfClassDecl();
  if (!classDecl)
    return false;

  auto clangLoader = dc->getASTContext().getClangModuleLoader();
  if (!clangLoader) return false;

Review comment (suggestion):
How about 
```suggestion
    // Offer fix-its to add the `main` function for different combinations of
    // effects, starting with no effects.
```



Code after:
    // (locator could not be simplified to anchor)
    // TODO: emit notes for each of the ambiguous candidates
    if (candidates.size() != 1) {
      context.Diags.diagnose(nominal->getLoc(), diag::ambiguous_decl_ref,
                             DeclNameRef(context.Id_main));
      attr->setInvalid();
      return nullptr;
    }
    mainFunction = dyn_cast<FuncDecl>(
        candidates[0].overloadChoices[locator].choice.getDecl());
  }

  if (!mainFunction) {
    const bool hasAsyncSupport =
        AvailabilityRange::forDeploymentTarget(context).isContainedIn(
            context.getBackDeployedConcurrencyAvailability());

    auto location = attr->getLocation();
    auto fixLocation = braces.Start;

    context.Diags.diagnose(location, diag::attr_MainType_without_main, nominal,
                           hasAsyncSupport);

    // Offer fix-its to add the `main` function for different combinations of
    // effects, starting with no effects.

    context.Diags.diagnose(location, diag::note_add_main_sync)
        .fixItInsertAfter(fixLocation, generateMainFunctionText(
                                           context, nominal, /*isThrows*/ false,
                                           /*isAsync*/ false)
                                           .str());

    context.Diags.diagnose(location, diag::note_add_main_sync_throws)
        .fixItInsertAfter(fixLocation, generateMainFunctionText(
                                           context, nominal, /*isThrows*/ true,
                                           /*isAsync*/ false)
                                           .str());

    if (hasAsyncSupport) {
      context.Diags.diagnose(location, diag::note_add_main_async)
          .fixItInsertAfter(fixLocation,
                            generateMainFunctionText(context, nominal,
                                                     /*isThrows*/ false,
                                                     /*isAsync*/ true)
                                .str());

      context.Diags.diagnose(location, diag::note_add_main_async_throws)
          .fixItInsertAfter(fixLocation,
                            generateMainFunctionText(context, nominal,
                                                     /*isThrows*/ true,
                                                     /*isAsync*/ true)