//===--- OverloadChoice.h - A Choice from an Overload Set ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 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 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(type) & (uintptr_t)0x03) == 0 && "Badly aligned decl"); DeclOrKind = reinterpret_cast(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() && "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(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(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(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 declaration that corresponds to this overload choice. ValueDecl *getDecl() const { assert(isDecl() && "Not a declaration"); return reinterpret_cast(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(DeclOrKind); } }; } } // end namespace swift::constraints #endif // LLVM_SWIFT_SEMA_OVERLOADCHOICE_H