//===--- OverloadChoice.h - A Choice from an Overload Set  ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides the \c OverloadChoice class and its related types,
// which is used by the constraint-based type checker to describe the
// selection of a particular overload from a set.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_OVERLOADCHOICE_H
#define SWIFT_SEMA_OVERLOADCHOICE_H

#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/ErrorHandling.h"
#include "swift/AST/Availability.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"

namespace swift {

class TypeDecl;
class ValueDecl;

namespace constraints {
  class ConstraintSystem;

/// \brief The kind of overload choice.
enum class OverloadChoiceKind : int {
  /// \brief The overload choice selects a particular declaration from a
  /// set of declarations.
  Decl,
  /// \brief The overload choice selects a particular declaration that was
  /// found via dynamic lookup and, therefore, might not actually be
  /// available at runtime.
  DeclViaDynamic,
  /// \brief The overload choice selects a particular declaration from a
  /// set of declarations and treats it as a type.
  TypeDecl,
  /// \brief The overload choice equates the member type with the
  /// base type. Used for unresolved member expressions like ".none" that
  /// refer to enum members with unit type.
  BaseType,
  /// \brief The overload choice indexes into a tuple. Index zero will
  /// have the value of this enumerator, index one will have the value of this
  /// enumerator + 1, and so on. Thus, this enumerator must always be last.
  TupleIndex,
  /// \brief The overload choice selects a particular declaration that
  /// was found by bridging the base value type to its Objective-C
  /// class type.
  DeclViaBridge,
  /// \brief The overload choice selects a particular declaration that
  /// was found by unwrapping an optional context type.
  DeclViaUnwrappedOptional,
};

/// \brief Describes a particular choice within an overload set.
///
/// 
class OverloadChoice {
  enum : unsigned {
    /// Indicates whether this overload was immediately specialized.
    IsSpecializedBit = 0x01,
    /// Indicates whether this declaration was bridged, turning a
    /// "Decl" kind into "DeclViaBridge" kind.
    IsBridgedBit = 0x02,
    /// Indicates whether this declaration was resolved by unwrapping an
    /// optional context type, turning a "Decl" kind into
    /// "DeclViaUnwrappedOptional".
    IsUnwrappedOptionalBit = 0x04,
    
    // IsBridged and IsUnwrappedOptional are mutually exclusive, so there is
    // room for another mutually exclusive OverloadChoiceKind to be packed into
    // those two bits.
  };

  /// \brief The base type to be used when referencing the declaration
  /// along with two bits: the low bit indicates whether this overload
  /// was immediately specialized and the second lowest bit indicates
  /// whether the declaration was bridged.
  llvm::PointerIntPair<Type, 3, unsigned> BaseAndBits;

  /// \brief Either the declaration pointer (if the low bit is clear) or the
  /// overload choice kind shifted by 1 with the low bit set.
  uintptr_t DeclOrKind;

public:
  OverloadChoice()
      : BaseAndBits(nullptr, 0), DeclOrKind() {}

  OverloadChoice(
      Type base, ValueDecl *value, bool isSpecialized, ConstraintSystem &CS);
  
  OverloadChoice(Type base, TypeDecl *type, bool isSpecialized)
    : BaseAndBits(base, isSpecialized ? IsSpecializedBit : 0) {
    assert((reinterpret_cast<uintptr_t>(type) & (uintptr_t)0x03) == 0
           && "Badly aligned decl");
    DeclOrKind = reinterpret_cast<uintptr_t>(type) | 0x01;
  }

  OverloadChoice(Type base, OverloadChoiceKind kind)
    : BaseAndBits(base, 0),
      DeclOrKind((uintptr_t)kind << 2 | (uintptr_t)0x03)
      {
    assert(base && "Must have a base type for overload choice");
    assert(kind != OverloadChoiceKind::Decl &&
           kind != OverloadChoiceKind::DeclViaDynamic &&
           kind != OverloadChoiceKind::TypeDecl &&
           kind != OverloadChoiceKind::DeclViaBridge &&
           kind != OverloadChoiceKind::DeclViaUnwrappedOptional &&
           "wrong constructor for decl");
  }

  OverloadChoice(Type base, unsigned index)
    : BaseAndBits(base, 0),
      DeclOrKind(((uintptr_t)index
                  + (uintptr_t)OverloadChoiceKind::TupleIndex) << 2
                 | (uintptr_t)0x03) {
    assert(base->getRValueType()->is<TupleType>() && "Must have tuple type");
  }

  /// Retrieve an overload choice for a declaration that was found via
  /// dynamic lookup.
  static OverloadChoice getDeclViaDynamic(Type base, ValueDecl *value) {
    OverloadChoice result;
    result.BaseAndBits.setPointer(base);
    result.DeclOrKind = reinterpret_cast<uintptr_t>(value) | 0x02;
    return result;
  }

  /// Retrieve an overload choice for a declaration that was found via
  /// bridging to an Objective-C class.
  static OverloadChoice getDeclViaBridge(Type base, ValueDecl *value) {
    OverloadChoice result;
    result.BaseAndBits.setPointer(base);
    result.BaseAndBits.setInt(IsBridgedBit);
    result.DeclOrKind = reinterpret_cast<uintptr_t>(value);
    return result;
  }

  /// Retrieve an overload choice for a declaration that was found
  /// by unwrapping an optional context type.
  static OverloadChoice getDeclViaUnwrappedOptional(Type base,
                                                    ValueDecl *value) {
    OverloadChoice result;
    result.BaseAndBits.setPointer(base);
    result.BaseAndBits.setInt(IsUnwrappedOptionalBit);
    result.DeclOrKind = reinterpret_cast<uintptr_t>(value);
    return result;
  }

  /// \brief Retrieve the base type used to refer to the declaration.
  Type getBaseType() const { return BaseAndBits.getPointer(); }

  /// \brief Determine whether the referenced declaration was immediately
  /// specialized with <...>.
  ///
  /// This value only has meaning when there is no base type.
  bool isSpecialized() const { 
    return BaseAndBits.getInt() & IsSpecializedBit;
  }
  
  /// \brief Determines the kind of overload choice this is.
  OverloadChoiceKind getKind() const {
    switch (DeclOrKind & 0x03) {
    case 0x00: 
      if (BaseAndBits.getInt() & IsBridgedBit)
        return OverloadChoiceKind::DeclViaBridge;
      if (BaseAndBits.getInt() & IsUnwrappedOptionalBit)
        return OverloadChoiceKind::DeclViaUnwrappedOptional;

      return OverloadChoiceKind::Decl;
      
    case 0x01: return OverloadChoiceKind::TypeDecl;
    case 0x02: return OverloadChoiceKind::DeclViaDynamic;
    case 0x03: {
      uintptr_t value = DeclOrKind >> 2;
      if (value >= (uintptr_t)OverloadChoiceKind::TupleIndex)
        return OverloadChoiceKind::TupleIndex;

      return (OverloadChoiceKind)value;
    }

    default: llvm_unreachable("basic math has escaped me");
    }
  }

  /// Determine whether this choice is for a declaration.
  bool isDecl() const {
    switch (getKind()) {
    case OverloadChoiceKind::Decl:
    case OverloadChoiceKind::DeclViaDynamic:
    case OverloadChoiceKind::TypeDecl:
    case OverloadChoiceKind::DeclViaBridge:
    case OverloadChoiceKind::DeclViaUnwrappedOptional:
      return true;

    case OverloadChoiceKind::BaseType:
    case OverloadChoiceKind::TupleIndex:
      return false;
    }
  }

  /// \brief Retrieve the declaraton that corresponds to this overload choice.
  ValueDecl *getDecl() const {
    assert(isDecl() && "Not a declaration");
    return reinterpret_cast<ValueDecl *>(DeclOrKind & ~(uintptr_t)0x03);
  }

  /// \brief Retrieve the tuple index that corresponds to this overload
  /// choice.
  unsigned getTupleIndex() const {
    assert(getKind() == OverloadChoiceKind::TupleIndex);
    return (DeclOrKind >> 2) - (uintptr_t)OverloadChoiceKind::TupleIndex;
  }

  /// \brief Retrieves an opaque choice that ignores the base type.
  void *getOpaqueChoiceSimple() const {
    return reinterpret_cast<void*>(DeclOrKind);
  }
};

} } // end namespace swift::constraints

#endif // LLVM_SWIFT_SEMA_OVERLOADCHOICE_H
