//===--- TypeCheckRequest.cpp - Type Checking Request ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 the TypeCheckRequest type, which describes a
//  request to the type checker to compute certain information.
//
//===----------------------------------------------------------------------===//
#include "swift/Sema/TypeCheckRequest.h"
#include "swift/AST/Decl.h"
#include "swift/AST/TypeRepr.h"

using namespace swift;

SourceLoc TypeCheckRequest::getLoc() const {
  switch (getPayloadKind(getKind())) {
#define DELEGATE_GET_LOC(PayloadName)             \
  case PayloadKind::PayloadName:                  \
    return get##PayloadName##Payload()->getLoc();

  DELEGATE_GET_LOC(Class)
  DELEGATE_GET_LOC(Enum)

  case PayloadKind::InheritedClauseEntry: {
    auto payload = getInheritedClauseEntryPayload();
    if (auto typeDecl = payload.first.dyn_cast<TypeDecl *>())
      return typeDecl->getInherited()[payload.second].getLoc();

    return payload.first.get<ExtensionDecl *>()->getInherited()[payload.second]
             .getLoc();
  }

  DELEGATE_GET_LOC(Protocol)

  case PayloadKind::DeclContextLookup:
    return getDeclContextLookupPayload().Loc;

  case PayloadKind::TypeResolution:
    return std::get<0>(getTypeResolutionPayload())->getLoc();

  DELEGATE_GET_LOC(TypeDeclResolution)

#undef DELEGATE_GET_LOC
  }

  llvm_unreachable("Unhandled PayloadKind in switch.");
}

Decl *TypeCheckRequest::getAnchor() const {
  switch (getPayloadKind(getKind())) {
#define DECL_PAYLOAD(PayloadName)               \
  case PayloadKind::PayloadName:                \
    return get##PayloadName##Payload();

#define NO_DECL_PAYLOAD(PayloadName)            \
  case PayloadKind::PayloadName:                \
    return nullptr;

  DECL_PAYLOAD(Class)
  DECL_PAYLOAD(Enum)

  case PayloadKind::InheritedClauseEntry: {
    auto payload = getInheritedClauseEntryPayload();
    if (auto typeDecl = payload.first.dyn_cast<TypeDecl *>())
      return typeDecl;

    return payload.first.get<ExtensionDecl *>();
  }

  DECL_PAYLOAD(Protocol)

  case PayloadKind::DeclContextLookup: {
    auto dc = getDeclContextLookupPayload().DC;
    if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
      return nominal;
    if (auto ext = dyn_cast<ExtensionDecl>(dc))
      return ext;
    return nullptr;
  }

  NO_DECL_PAYLOAD(TypeResolution)
  DECL_PAYLOAD(TypeDeclResolution)

#undef NO_DECL_PAYLOAD
#undef DECL_PAYLOAD
  }

  llvm_unreachable("Unhandled PayloadKind in switch.");
}

bool swift::operator==(const TypeCheckRequest &x, const TypeCheckRequest &y) {
  // Check the request kinds.
  if (x.getKind() != y.getKind()) return false;

  // Check the payload.
  switch (TypeCheckRequest::getPayloadKind(x.getKind())) {
#define TYPE_CHECK_REQUEST_PAYLOAD(PayloadName,...)                     \
  case TypeCheckRequest::PayloadKind::PayloadName:                      \
    return x.get##PayloadName##Payload() == y.get##PayloadName##Payload();
#include "swift/Sema/TypeCheckRequestPayloads.def"
  }

  llvm_unreachable("Unhandled PayloadKind in switch.");
}
