//===--- 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/Expr.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, _copyable, _error, _executor, // the 'BuiltinExecutor' type _escapable, _job, _nativeObject, _never, _rawPointer, _rawUnsafeContinuation, _void, _word, _swiftInt, // Swift.Int _serialExecutor, // the '_Concurrency.SerialExecutor' protocol _taskExecutor, // the '_Concurrency.TaskExecutor' protocol _actor, // the '_Concurrency.Actor' protocol _distributedActor, // the 'Distributed.DistributedActor' protocol _unsafeRawBufferPointer, // UnsafeRawBufferPointer _unconstrainedAny, // any ~Copyable & ~Escapable }; 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 _swiftInt: return SC.Context.getIntType(); case _serialExecutor: return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor) ->getDeclaredInterfaceType(); case _taskExecutor: if (auto ty = SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)) { return ty->getDeclaredInterfaceType(); } else { return nullptr; } case _actor: return SC.Context.getProtocol(KnownProtocolKind::Actor) ->getDeclaredInterfaceType(); case _distributedActor: return SC.Context.getProtocol(KnownProtocolKind::DistributedActor) ->getDeclaredInterfaceType(); case _unsafeRawBufferPointer: return SC.Context.getUnsafeRawBufferPointerType(); case _copyable: return SC.Context.getProtocol(KnownProtocolKind::Copyable) ->getDeclaredInterfaceType(); case _escapable: return SC.Context.getProtocol(KnownProtocolKind::Escapable) ->getDeclaredInterfaceType(); case _unconstrainedAny: return SC.Context.getUnconstrainedAnyExistentialType(); } } enum RepresentationSynthesizer { _thin, _thick }; /// 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)); } template struct RepMetatypeTypeSynthesizer { S Sub; RepresentationSynthesizer Rep; }; template constexpr RepMetatypeTypeSynthesizer _metatype(S sub, RepresentationSynthesizer rep ) { return {sub, rep}; } template Type synthesizeType(SynthesisContext &SC, const RepMetatypeTypeSynthesizer &M) { auto instanceType = synthesizeType(SC, M.Sub); return MetatypeType::get(instanceType, synthesizeMetatypeRepresentation(M.Rep)); } /// A synthesizer which generates an existential type from a requirement type. template struct ExistentialTypeSynthesizer { S Sub; }; template constexpr ExistentialTypeSynthesizer _existential(S sub) { return {sub}; } template Type synthesizeType(SynthesisContext &SC, const ExistentialTypeSynthesizer &M) { return ExistentialType::get(synthesizeType(SC, M.Sub)); } /// A synthesizer which generates an existential type from a requirement type. template struct BincompatIfTypeAvailableTypeSynthesizer { bool condition; S Sub; FallbackS FallbackSub; }; template constexpr BincompatIfTypeAvailableTypeSynthesizer _bincompatType( bool bincompatCondition, S sub, FallbackS fallbackSub) { return {bincompatCondition, sub, {fallbackSub}}; } template Type synthesizeType(SynthesisContext &SC, const BincompatIfTypeAvailableTypeSynthesizer &M) { if (M.condition) { return synthesizeType(SC, M.Sub); } else { return synthesizeType(SC, M.FallbackSub); } } MetatypeRepresentation inline synthesizeMetatypeRepresentation(RepresentationSynthesizer rep) { switch (rep) { case _thin: return MetatypeRepresentation::Thin; case _thick: return MetatypeRepresentation::Thick; // TOOD: maybe add _objc? } llvm_unreachable("bad kind"); } /// 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)); } template struct RepExistentialMetatypeTypeSynthesizer { S Sub; RepresentationSynthesizer Rep; }; template constexpr RepExistentialMetatypeTypeSynthesizer _existentialMetatype(S sub, RepresentationSynthesizer rep) { return {sub, rep}; } template Type synthesizeType(SynthesisContext &SC, const RepExistentialMetatypeTypeSynthesizer &M) { return ExistentialMetatypeType::get(synthesizeType(SC, M.Sub), synthesizeMetatypeRepresentation(M.Rep)); } /// 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, const char *label = nullptr) { auto argLabelIdent = (label ? SC.Context.getIdentifier(label) : Identifier()); auto type = synthesizeType(SC, s); auto PD = new (SC.Context) ParamDecl(SourceLoc(), SourceLoc(), argLabelIdent, 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 _consuming(G sub) { return {ParamSpecifier::Consuming, sub}; } template constexpr SpecifiedParamSynthesizer _inout(G sub) { return {ParamSpecifier::InOut, sub}; } template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const SpecifiedParamSynthesizer &s, const char *label = nullptr) { auto param = synthesizeParamDecl(SC, s.sub, label); param->setSpecifier(s.specifier); return param; } template struct SendingParamSynthesizer { S sub; }; template constexpr SendingParamSynthesizer _sending(S sub) { return {sub}; } template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const SendingParamSynthesizer &s, const char *label = nullptr) { auto param = synthesizeParamDecl(SC, s.sub, label); if (SC.Context.LangOpts.hasFeature(Feature::SendingArgsAndResults)) param->setSending(); 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); } template void synthesizeDefaultArgument(SynthesisContext &SC, const S &s, ParamDecl *param) { synthesizeDefaultArgumentFromExpr(SC, s, param); } template void synthesizeDefaultArgumentFromExpr(SynthesisContext &SC, const S &s, ParamDecl *param) { // FIXME: this works except that we tend to crash in diagnostics trying // to render the default argument if you mess up the call. auto expr = synthesizeExpr(SC, s); param->setDefaultArgumentKind(DefaultArgumentKind::Normal); param->setDefaultExpr(expr); } /// Default arguments. template struct DefaultedSynthesizer { S sub; A arg; }; template constexpr DefaultedSynthesizer _defaulted(S sub, A arg) { return {sub, arg}; } template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const DefaultedSynthesizer &s, const char *label = nullptr) { auto param = synthesizeParamDecl(SC, s.sub, label); synthesizeDefaultArgument(SC, s.arg, param); return param; } template FunctionType::Param synthesizeParamType(SynthesisContext &SC, const DefaultedSynthesizer &s) { return synthesizeParamType(s.sub); } /// Labels. template struct LabelSynthesizer { const char *label; S sub; }; template constexpr LabelSynthesizer _label(const char *label, S sub) { return {label, sub}; } template ParamDecl *synthesizeParamDecl(SynthesisContext &SC, const LabelSynthesizer &s) { return synthesizeParamDecl(SC, s.sub, s.label); } template FunctionType::Param synthesizeParamType(SynthesisContext &SC, const LabelSynthesizer &s) { auto label = SC.Context.getIdentifier(s.label); return synthesizeParamType(SC, s.sub).withLabel(label); } /// 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. template struct ThrowsSynthesizer { S sub; }; template struct AsyncSynthesizer { S sub; }; template struct NoescapeSynthesizer { S sub; }; template struct SendableModSynthesizer { 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}; } template constexpr SendableModSynthesizer _sendable(S sub) { return {sub}; } inline ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, RepresentationSynthesizer 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(); } template ASTExtInfo synthesizeExtInfo(SynthesisContext &SC, const SendableModSynthesizer &s) { return synthesizeExtInfo(SC, s.sub).withSendable(); } /// 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)); } /// Expressions. enum SingletonExprSynthesizer { _nil }; inline Expr *synthesizeExpr(SynthesisContext &SC, SingletonExprSynthesizer s) { switch (s) { case _nil: return new (SC.Context) NilLiteralExpr(SourceLoc(), /*implicit*/true); } llvm_unreachable("bad singleton kind"); } inline void synthesizeDefaultArgument(SynthesisContext &SC, SingletonExprSynthesizer s, ParamDecl *param) { switch (s) { case _nil: { auto expr = synthesizeExpr(SC, s); param->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral); param->setDefaultExpr(expr); return; } /* default: synthesizeDefaultArgumentFromExpr(SC, s, param); return; */ } } } // end namespace swift #endif