//===--- SILWitnessVisitor.h - Witness method table visitor -----*- 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 defines the SILWitnessVisitor class, which is used to generate and // perform lookups in witness method tables for protocols and protocol // conformances. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SILWITNESSVISITOR_H #define SWIFT_SIL_SILWITNESSVISITOR_H #include "swift/AST/ASTVisitor.h" #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" namespace swift { /// A CRTP class for visiting the witnesses of a protocol. /// /// The design here is that each entry (or small group of entries) /// gets turned into a call to the implementation class describing /// the exact variant of witness. For example, for member /// variables, there should be separate callbacks for adding a /// getter/setter pair, for just adding a getter, and for adding a /// physical projection (if we decide to support that). /// /// You must override the following methods: /// - addOutOfLineBaseProtocol() /// - addMethod() /// - addConstructor() /// - addAssociatedType() template class SILWitnessVisitor : public ASTVisitor { T &asDerived() { return *static_cast(this); } public: void visitProtocolDecl(ProtocolDecl *protocol) { // Visit inherited protocols. // TODO: We need to figure out all the guarantees we want here. // It would be abstractly good to allow conversion to a base // protocol to be trivial, but it's not clear that there's // really a structural guarantee we can rely on here. for (auto baseProto : protocol->getInheritedProtocols(nullptr)) { // ObjC protocols do not have witnesses. if (!Lowering::TypeConverter::protocolRequiresWitnessTable(baseProto)) continue; asDerived().addOutOfLineBaseProtocol(baseProto); } /// Visit the witnesses for the direct members of a protocol. for (Decl *member : protocol->getMembers()) ASTVisitor::visit(member); } /// Fallback for unexpected protocol requirements. void visitDecl(Decl *d) { d->print(llvm::errs()); llvm_unreachable("unhandled protocol requirement"); } void visitAbstractStorageDecl(AbstractStorageDecl *sd) { asDerived().addMethod(sd->getGetter()); if (sd->isSettable(sd->getDeclContext())) { asDerived().addMethod(sd->getSetter()); if (sd->getMaterializeForSetFunc()) asDerived().addMethod(sd->getMaterializeForSetFunc()); } } void visitConstructorDecl(ConstructorDecl *cd) { asDerived().addConstructor(cd); } void visitFuncDecl(FuncDecl *func) { // Accessors are emitted by their var/subscript declaration. if (func->isAccessor()) return; asDerived().addMethod(func); } void visitAssociatedTypeDecl(AssociatedTypeDecl *td) { SmallVector protos; for (auto p : td->getConformingProtocols(nullptr)) protos.push_back(p); ProtocolType::canonicalizeProtocols(protos); asDerived().addAssociatedType(td, protos); } void visitTypeAliasDecl(TypeAliasDecl *tad) { // We don't care about these by themselves for witnesses. } void visitPatternBindingDecl(PatternBindingDecl *pbd) { // We only care about the contained VarDecls. } void visitIfConfigDecl(IfConfigDecl *icd) { // We only care about the active members, which were already subsumed by the // enclosing type. } }; } // end namespace swift #endif