//===--- ExistentialLayout.h - Existential type decomposition ---*- 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 defines the ExistentialLayout struct. // //===----------------------------------------------------------------------===// #ifndef SWIFT_EXISTENTIAL_LAYOUT_H #define SWIFT_EXISTENTIAL_LAYOUT_H #include "swift/Basic/ArrayRefView.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Type.h" namespace swift { class ProtocolDecl; class ProtocolType; class ProtocolCompositionType; struct ExistentialLayout { enum Kind { Class, Error, Opaque }; ExistentialLayout() { hasExplicitAnyObject = false; containsNonObjCProtocol = false; singleProtocol = nullptr; } ExistentialLayout(ProtocolType *type); ExistentialLayout(ProtocolCompositionType *type); /// The explicit superclass constraint, if any. Type explicitSuperclass; /// Whether the existential contains an explicit '& AnyObject' constraint. bool hasExplicitAnyObject : 1; /// Whether any protocol members are non-@objc. bool containsNonObjCProtocol : 1; /// Return the kind of this existential (class/error/opaque). Kind getKind() { if (requiresClass()) return Kind::Class; if (isErrorExistential()) return Kind::Error; // The logic here is that opaque is the complement of class + error, // i.e. we don't have more concrete information guiding the layout // and it doesn't fall into the special-case Error representation. return Kind::Opaque; } bool isAnyObject() const; bool isObjC() const { // FIXME: Does the superclass have to be @objc? return ((explicitSuperclass || hasExplicitAnyObject || !getProtocols().empty()) && !containsNonObjCProtocol); } /// Whether the existential requires a class, either via an explicit /// '& AnyObject' member or because of a superclass or protocol constraint. bool requiresClass() const; /// Returns the existential's superclass, if any; this is either an explicit /// superclass term in a composition type, or the superclass of one of the /// protocols. Type getSuperclass() const; /// Does this existential contain the Error protocol? bool isExistentialWithError(ASTContext &ctx) const; /// Does this existential consist of an Error protocol only with no other /// constraints? bool isErrorExistential() const; static inline ProtocolType *getProtocolType(const Type &Ty) { return cast(Ty.getPointer()); } typedef ArrayRefView ProtocolTypeArrayRef; ProtocolTypeArrayRef getProtocols() const & { if (singleProtocol) return llvm::makeArrayRef(&singleProtocol, 1); return protocols; } /// The returned ArrayRef may point directly to \c this->singleProtocol, so /// calling this on a temporary is likely to be incorrect. ProtocolTypeArrayRef getProtocols() const && = delete; LayoutConstraint getLayoutConstraint() const; private: // The protocol from a ProtocolType Type singleProtocol; /// Zero or more protocol constraints from a ProtocolCompositionType ArrayRef protocols; }; } #endif // SWIFT_EXISTENTIAL_LAYOUT_H