blob: ee9f0a21356076bbe63ee08639590e11344de846 [file] [log] [blame]
//===--- OverloadChoice.h - A Choice from an Overload Set ------*- C++ -*-===//
//
// 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 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/FunctionRefKind.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
namespace swift {
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 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 selects a key path subscripting operation.
KeyPathApplication,
/// \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 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 the two bits above.
llvm::PointerIntPair<Type, 3, unsigned> BaseAndBits;
/// \brief Either the declaration pointer (if the low bit is clear) or the
/// overload choice kind shifted two bits with the low bit set.
uintptr_t DeclOrKind;
/// The kind of function reference.
/// FIXME: This needs two bits. Can we pack them somewhere?
FunctionRefKind TheFunctionRefKind;
public:
OverloadChoice()
: BaseAndBits(nullptr, 0), DeclOrKind(0),
TheFunctionRefKind(FunctionRefKind::Unapplied) {}
OverloadChoice(Type base, ValueDecl *value,
FunctionRefKind functionRefKind)
: BaseAndBits(base, 0),
TheFunctionRefKind(functionRefKind) {
assert(!base || !base->hasTypeParameter());
assert((reinterpret_cast<uintptr_t>(value) & (uintptr_t)0x03) == 0 &&
"Badly aligned decl");
DeclOrKind = reinterpret_cast<uintptr_t>(value);
}
OverloadChoice(Type base, OverloadChoiceKind kind)
: BaseAndBits(base, 0),
DeclOrKind((uintptr_t)kind << 2 | (uintptr_t)0x03),
TheFunctionRefKind(FunctionRefKind::Unapplied) {
assert(base && "Must have a base type for overload choice");
assert(!base->hasTypeParameter());
assert(kind != OverloadChoiceKind::Decl &&
kind != OverloadChoiceKind::DeclViaDynamic &&
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),
TheFunctionRefKind(FunctionRefKind::Unapplied) {
assert(base->getRValueType()->is<TupleType>() && "Must have tuple type");
}
bool isInvalid() const {
return BaseAndBits.getPointer().isNull()
&& BaseAndBits.getInt() == 0
&& DeclOrKind == 0
&& TheFunctionRefKind == FunctionRefKind::Unapplied;
}
/// Retrieve an overload choice for a declaration that was found via
/// dynamic lookup.
static OverloadChoice getDeclViaDynamic(Type base, ValueDecl *value,
FunctionRefKind functionRefKind) {
OverloadChoice result;
result.BaseAndBits.setPointer(base);
result.DeclOrKind = reinterpret_cast<uintptr_t>(value) | 0x02;
result.TheFunctionRefKind = functionRefKind;
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,
FunctionRefKind functionRefKind) {
OverloadChoice result;
result.BaseAndBits.setPointer(base);
result.BaseAndBits.setInt(IsBridgedBit);
result.DeclOrKind = reinterpret_cast<uintptr_t>(value);
result.TheFunctionRefKind = functionRefKind;
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,
FunctionRefKind functionRefKind) {
OverloadChoice result;
result.BaseAndBits.setPointer(base);
result.BaseAndBits.setInt(IsUnwrappedOptionalBit);
result.DeclOrKind = reinterpret_cast<uintptr_t>(value);
result.TheFunctionRefKind = functionRefKind;
return result;
}
/// \brief Retrieve the base type used to refer to the declaration.
Type getBaseType() const { return BaseAndBits.getPointer(); }
/// \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 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::DeclViaBridge:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
return true;
case OverloadChoiceKind::BaseType:
case OverloadChoiceKind::TupleIndex:
case OverloadChoiceKind::KeyPathApplication:
return false;
}
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
}
/// \brief Retrieve the declaration that corresponds to this overload choice.
ValueDecl *getDecl() const {
assert(isDecl() && "Not a declaration");
return reinterpret_cast<ValueDecl *>(DeclOrKind & ~(uintptr_t)0x03);
}
/// Get the name of the overload choice.
DeclName getName() const;
/// \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);
}
FunctionRefKind getFunctionRefKind() const {
assert(isDecl() && "only makes sense for declaration choices");
return TheFunctionRefKind;
}
};
} // end namespace constraints
} // end namespace swift
#endif // LLVM_SWIFT_SEMA_OVERLOADCHOICE_H