//===--- ASTSynthesis.h - Convenient Swift AST synthesis --------*- 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_ASTSYNTHESIS_H #define SWIFT_ASTSYNTHESIS_H #include "swift/AST/Types.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/GenericParamList.h" #include "swift/AST/ParameterList.h" namespace swift { struct SynthesisContext { ASTContext &Context; DeclContext *DC; GenericParamList *GenericParams = nullptr; SynthesisContext(ASTContext &ctx, DeclContext *DC) : Context(ctx), DC(DC) {} }; /// Allow literal types to be passed at an arbitrary position /// in the type-synthesis DSL. inline Type synthesizeType(SynthesisContext &SC, Type type) { return type; } /// A synthesizer which generates a specific type. enum SingletonTypeSynthesizer { _any, _bridgeObject, _error, _executor, _job, _nativeObject, _never, _rawPointer, _rawUnsafeContinuation, _void, _word, _serialExecutor, }; inline Type synthesizeType(SynthesisContext &SC, SingletonTypeSynthesizer kind) { switch (kind) { case _any: return SC.Context.getAnyExistentialType(); case _bridgeObject: return SC.Context.TheBridgeObjectType; case _error: return SC.Context.getErrorExistentialType(); case _executor: return SC.Context.TheExecutorType; case _job: return SC.Context.TheJobType; case _nativeObject: return SC.Context.TheNativeObjectType; case _never: return SC.Context.getNeverType(); case _rawPointer: return SC.Context.TheRawPointerType; case _rawUnsafeContinuation: return SC.Context.TheRawUnsafeContinuationType; case _void: return SC.Context.TheEmptyTupleType; case _word: return BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(), SC.Context); case _serialExecutor: return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor) ->getDeclaredInterfaceType(); } } /// A synthesizer which generates an integer type. struct IntegerTypeSynthesizer { unsigned BitWidth; }; constexpr inline IntegerTypeSynthesizer _int(unsigned bitWidth) { return {bitWidth}; } inline Type synthesizeType(SynthesisContext &SC, IntegerTypeSynthesizer S) { return BuiltinIntegerType::get(S.BitWidth, SC.Context); } /// A synthesizer which generates a vector type. template struct VectorTypeSynthesizer { unsigned Count; S Sub; }; template constexpr VectorTypeSynthesizer _vector(unsigned count, S sub) { return {count, sub}; } template Type synthesizeType(SynthesisContext &SC, const VectorTypeSynthesizer &V) { return BuiltinVectorType::get(SC.Context, synthesizeType(SC, V.Sub), V.Count); } /// A synthesizer which generates a metatype type. template struct MetatypeTypeSynthesizer { S Sub; }; template constexpr MetatypeTypeSynthesizer _metatype(S sub) { return {sub}; } template Type synthesizeType(SynthesisContext &SC, const MetatypeTypeSynthesizer &M) { return MetatypeType::get(synthesizeType(SC, M.Sub)); } /// A synthesizer which generates an existential metatype type. template struct ExistentialMetatypeTypeSynthesizer { S Sub; }; template constexpr ExistentialMetatypeTypeSynthesizer _existentialMetatype(S sub) { return {sub}; } template Type synthesizeType(SynthesisContext &SC, const ExistentialMetatypeTypeSynthesizer &M) { return ExistentialMetatypeType::get(synthesizeType(SC, M.Sub)); } /// A synthesizer that generates a MoveOnly wrapper of a type. template struct MoveOnlyTypeSynthesizer { S Sub; }; template constexpr MoveOnlyTypeSynthesizer _moveOnly(S sub) { return {sub}; } template Type synthesizeType(SynthesisContext &SC, const MoveOnlyTypeSynthesizer &M) { // Until we get the actual move only type, we just return the synthesized // type. return synthesizeType(SC, M.Sub); } /// Helper types for variadic synthesis. template struct VariadicSynthesizerStorage; template <> struct VariadicSynthesizerStorage<> { constexpr VariadicSynthesizerStorage() {} template void visit(Fn &&fn) const {} }; template struct VariadicSynthesizerStorage { Head head; VariadicSynthesizerStorage tail; constexpr VariadicSynthesizerStorage(Head head, Tail... tail) : head(head), tail(tail...) {} template void visit(Fn &&fn) const { fn(head); tail.visit(fn); } }; /// A synthesizer which generates a generic type parameter. struct TypeParamTypeSynthesizer { unsigned Index; }; constexpr inline TypeParamTypeSynthesizer _typeparam(unsigned index) { return {index}; } inline Type synthesizeType(SynthesisContext &SC, const TypeParamTypeSynthesizer &S) { assert(SC.GenericParams); return SC.GenericParams->getParams()[S.Index]->getDeclaredInterfaceType(); } /// Synthesize tuple type elements. template TupleTypeElt synthesizeTupleTypeElt(SynthesisContext &SC, S s) { return synthesizeType(SC, s); } struct CollectTupleTypeElements { SynthesisContext &SC; SmallVectorImpl &Elts; template void operator()(const S &s) const { Elts.push_back(synthesizeTupleTypeElt(SC, s)); } }; /// Synthesize tuple types. template struct TupleSynthesizer { VariadicSynthesizerStorage Elements; }; template constexpr TupleSynthesizer _tuple(Elts... elts) { return {{elts...}}; } template Type synthesizeType(SynthesisContext &SC, const TupleSynthesizer &tuple) { SmallVector elts; tuple.Elements.visit(CollectTupleTypeElements{SC, elts}); return TupleType::get(elts, SC.Context); } /// Synthesize parameter declarations. template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const S &s) { auto type = synthesizeType(SC, s); auto PD = new (SC.Context) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), SC.DC); PD->setSpecifier(ParamSpecifier::Default); PD->setInterfaceType(type); PD->setImplicit(); return PD; } template FunctionType::Param synthesizeParamType(SynthesisContext &SC, const S &s) { auto type = synthesizeType(SC, s); return type; } /// Parameter specifiers. template struct SpecifiedParamSynthesizer { ParamSpecifier specifier; S sub; }; template constexpr SpecifiedParamSynthesizer _owned(G sub) { // TODO: We should probably synthesize decls to use the standard `consuming` // modifier, once we're certain doing so won't break anything. return {ParamSpecifier::LegacyOwned, sub}; } template constexpr SpecifiedParamSynthesizer _inout(G sub) { return {ParamSpecifier::InOut, sub}; } template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const SpecifiedParamSynthesizer &s) { auto param = synthesizeParamDecl(SC, s.sub); param->setSpecifier(s.specifier); return param; } template FunctionType::Param synthesizeParamType(SynthesisContext &SC, const SpecifiedParamSynthesizer &s) { auto param = synthesizeParamType(SC, s.sub); auto flags = param.getParameterFlags(); if (s.specifier != ParamSpecifier::Default) flags = flags.withValueOwnership(s.specifier); return param.withFlags(flags); } /// Synthesize a parameter list. template struct ParameterListSynthesizer { VariadicSynthesizerStorage params; }; template constexpr ParameterListSynthesizer _parameters(Params... ps) { return {{ps...}}; } struct CollectParamDecls { SynthesisContext &SC; SmallVectorImpl &Results; template void operator()(const S &s) const { // Found by argument-dependent lookup. Results.push_back(synthesizeParamDecl(SC, s)); } }; template ParameterList *synthesizeParameterList(SynthesisContext &SC, const ParameterListSynthesizer &list) { SmallVector decls; list.params.visit(CollectParamDecls{SC, decls}); return ParameterList::create(SC.Context, decls); } struct CollectParamTypes { SynthesisContext &SC; SmallVectorImpl &Results; template void operator()(const S &s) const { // Found by argument-dependent lookup. Results.push_back(synthesizeParamType(SC, s)); } }; template void synthesizeParameterTypes(SynthesisContext &SC, const ParameterListSynthesizer &list, SmallVectorImpl &types) { list.params.visit(CollectParamTypes{SC, types}); } /// Synthesize function ExtInfo. enum FunctionRepresentationSynthesizer { _thin, _thick }; template struct ThrowsSynthesizer { S sub; }; template struct AsyncSynthesizer { S sub; }; template struct NoescapeSynthesizer { S sub; }; template constexpr ThrowsSynthesizer _throws(S sub) { return {sub}; } template constexpr AsyncSynthesizer _async(S sub) { return {sub}; } template constexpr NoescapeSynthesizer _noescape(S sub) { return {sub}; } inline ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, FunctionRepresentationSynthesizer kind) { switch (kind) { case _thin: return ASTExtInfo().withRepresentation( FunctionTypeRepresentation::Thin); case _thick: return ASTExtInfo().withRepresentation( FunctionTypeRepresentation::Swift); } } template ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, const ThrowsSynthesizer &s) { return synthesizeExtInfo(SC, s.sub).withThrows(); } template ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, const AsyncSynthesizer &s) { return synthesizeExtInfo(SC, s.sub).withAsync(); } template ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, const NoescapeSynthesizer &s) { return synthesizeExtInfo(SC, s.sub).withNoEscape(); } /// Synthesize a function type. template struct FunctionTypeSynthesizer { ExtInfoS extInfo; ResultS result; ParamsS parameters; }; template FunctionTypeSynthesizer _function(ExtInfoS extInfo, ResultS result, ParamsS params) { return {extInfo, result, params}; } template Type synthesizeType(SynthesisContext &SC, const FunctionTypeSynthesizer &fn) { SmallVector paramTypes; synthesizeParameterTypes(SC, fn.parameters, paramTypes); auto extInfo = synthesizeExtInfo(SC, fn.extInfo); auto resultType = synthesizeType(SC, fn.result); return FunctionType::get(paramTypes, resultType, extInfo); } /// Synthesize optionals. template struct OptionalSynthesizer { S sub; }; template constexpr OptionalSynthesizer _optional(S sub) { return {sub}; } template Type synthesizeType(SynthesisContext &SC, const OptionalSynthesizer &s) { return OptionalType::get(synthesizeType(SC, s.sub)); } } // end namespace swift #endif