mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
And do a first pass of auditing existing uses of the parameter specifiers to make sure that we look at the ValueOwnership mapping in most cases instead of individual modifiers.
389 lines
12 KiB
C++
389 lines
12 KiB
C++
//===--- 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 <class S>
|
|
struct VectorTypeSynthesizer {
|
|
unsigned Count;
|
|
S Sub;
|
|
};
|
|
template <class S>
|
|
constexpr VectorTypeSynthesizer<S> _vector(unsigned count, S sub) {
|
|
return {count, sub};
|
|
}
|
|
template <class S>
|
|
Type synthesizeType(SynthesisContext &SC,
|
|
const VectorTypeSynthesizer<S> &V) {
|
|
return BuiltinVectorType::get(SC.Context, synthesizeType(SC, V.Sub),
|
|
V.Count);
|
|
}
|
|
|
|
/// A synthesizer which generates a metatype type.
|
|
template <class S>
|
|
struct MetatypeTypeSynthesizer {
|
|
S Sub;
|
|
};
|
|
template <class S>
|
|
constexpr MetatypeTypeSynthesizer<S> _metatype(S sub) {
|
|
return {sub};
|
|
}
|
|
template <class S>
|
|
Type synthesizeType(SynthesisContext &SC,
|
|
const MetatypeTypeSynthesizer<S> &M) {
|
|
return MetatypeType::get(synthesizeType(SC, M.Sub));
|
|
}
|
|
|
|
/// A synthesizer which generates an existential metatype type.
|
|
template <class S>
|
|
struct ExistentialMetatypeTypeSynthesizer {
|
|
S Sub;
|
|
};
|
|
template <class S>
|
|
constexpr ExistentialMetatypeTypeSynthesizer<S> _existentialMetatype(S sub) {
|
|
return {sub};
|
|
}
|
|
template <class S>
|
|
Type synthesizeType(SynthesisContext &SC,
|
|
const ExistentialMetatypeTypeSynthesizer<S> &M) {
|
|
return ExistentialMetatypeType::get(synthesizeType(SC, M.Sub));
|
|
}
|
|
|
|
/// A synthesizer that generates a MoveOnly wrapper of a type.
|
|
template <class S>
|
|
struct MoveOnlyTypeSynthesizer {
|
|
S Sub;
|
|
};
|
|
template <class S>
|
|
constexpr MoveOnlyTypeSynthesizer<S> _moveOnly(S sub) {
|
|
return {sub};
|
|
}
|
|
template <class S>
|
|
Type synthesizeType(SynthesisContext &SC, const MoveOnlyTypeSynthesizer<S> &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 <class... Ss>
|
|
struct VariadicSynthesizerStorage;
|
|
|
|
template <>
|
|
struct VariadicSynthesizerStorage<> {
|
|
constexpr VariadicSynthesizerStorage() {}
|
|
|
|
template <class Fn>
|
|
void visit(Fn &&fn) const {}
|
|
};
|
|
template <class Head, class... Tail>
|
|
struct VariadicSynthesizerStorage<Head, Tail...> {
|
|
Head head;
|
|
VariadicSynthesizerStorage<Tail...> tail;
|
|
constexpr VariadicSynthesizerStorage(Head head, Tail... tail)
|
|
: head(head), tail(tail...) {}
|
|
|
|
template <class Fn>
|
|
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 <class S>
|
|
TupleTypeElt synthesizeTupleTypeElt(SynthesisContext &SC, S s) {
|
|
return synthesizeType(SC, s);
|
|
}
|
|
struct CollectTupleTypeElements {
|
|
SynthesisContext &SC;
|
|
SmallVectorImpl<TupleTypeElt> &Elts;
|
|
|
|
template <class S>
|
|
void operator()(const S &s) const {
|
|
Elts.push_back(synthesizeTupleTypeElt(SC, s));
|
|
}
|
|
};
|
|
|
|
/// Synthesize tuple types.
|
|
template <class... Elts>
|
|
struct TupleSynthesizer {
|
|
VariadicSynthesizerStorage<Elts...> Elements;
|
|
};
|
|
template <class... Elts>
|
|
constexpr TupleSynthesizer<Elts...> _tuple(Elts... elts) {
|
|
return {{elts...}};
|
|
}
|
|
template <class... Elts>
|
|
Type synthesizeType(SynthesisContext &SC,
|
|
const TupleSynthesizer<Elts...> &tuple) {
|
|
SmallVector<TupleTypeElt, sizeof...(Elts)> elts;
|
|
tuple.Elements.visit(CollectTupleTypeElements{SC, elts});
|
|
return TupleType::get(elts, SC.Context);
|
|
}
|
|
|
|
/// Synthesize parameter declarations.
|
|
template <class S>
|
|
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 <class S>
|
|
FunctionType::Param synthesizeParamType(SynthesisContext &SC, const S &s) {
|
|
auto type = synthesizeType(SC, s);
|
|
return type;
|
|
}
|
|
|
|
/// Parameter specifiers.
|
|
template <class S>
|
|
struct SpecifiedParamSynthesizer { ParamSpecifier specifier; S sub; };
|
|
template <class G>
|
|
constexpr SpecifiedParamSynthesizer<G> _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 <class G>
|
|
constexpr SpecifiedParamSynthesizer<G> _inout(G sub) {
|
|
return {ParamSpecifier::InOut, sub};
|
|
}
|
|
template <class S>
|
|
ParamDecl *synthesizeParamDecl(SynthesisContext &SC,
|
|
const SpecifiedParamSynthesizer<S> &s) {
|
|
auto param = synthesizeParamDecl(SC, s.sub);
|
|
param->setSpecifier(s.specifier);
|
|
return param;
|
|
}
|
|
template <class S>
|
|
FunctionType::Param synthesizeParamType(SynthesisContext &SC,
|
|
const SpecifiedParamSynthesizer<S> &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 <class... Params>
|
|
struct ParameterListSynthesizer {
|
|
VariadicSynthesizerStorage<Params...> params;
|
|
};
|
|
template <class... Params>
|
|
constexpr ParameterListSynthesizer<Params...> _parameters(Params... ps) {
|
|
return {{ps...}};
|
|
}
|
|
|
|
struct CollectParamDecls {
|
|
SynthesisContext &SC;
|
|
SmallVectorImpl<ParamDecl*> &Results;
|
|
|
|
template <class S>
|
|
void operator()(const S &s) const {
|
|
// Found by argument-dependent lookup.
|
|
Results.push_back(synthesizeParamDecl(SC, s));
|
|
}
|
|
};
|
|
template <class... Params>
|
|
ParameterList *synthesizeParameterList(SynthesisContext &SC,
|
|
const ParameterListSynthesizer<Params...> &list) {
|
|
SmallVector<ParamDecl*, 4> decls;
|
|
list.params.visit(CollectParamDecls{SC, decls});
|
|
return ParameterList::create(SC.Context, decls);
|
|
}
|
|
|
|
struct CollectParamTypes {
|
|
SynthesisContext &SC;
|
|
SmallVectorImpl<FunctionType::Param> &Results;
|
|
|
|
template <class S>
|
|
void operator()(const S &s) const {
|
|
// Found by argument-dependent lookup.
|
|
Results.push_back(synthesizeParamType(SC, s));
|
|
}
|
|
};
|
|
template <class... Params>
|
|
void synthesizeParameterTypes(SynthesisContext &SC,
|
|
const ParameterListSynthesizer<Params...> &list,
|
|
SmallVectorImpl<FunctionType::Param> &types) {
|
|
list.params.visit(CollectParamTypes{SC, types});
|
|
}
|
|
|
|
/// Synthesize function ExtInfo.
|
|
enum FunctionRepresentationSynthesizer {
|
|
_thin,
|
|
_thick
|
|
};
|
|
template <class S> struct ThrowsSynthesizer { S sub; };
|
|
template <class S> struct AsyncSynthesizer { S sub; };
|
|
template <class S> struct NoescapeSynthesizer { S sub; };
|
|
template <class S>
|
|
constexpr ThrowsSynthesizer<S> _throws(S sub) { return {sub}; }
|
|
template <class S>
|
|
constexpr AsyncSynthesizer<S> _async(S sub) { return {sub}; }
|
|
template <class S>
|
|
constexpr NoescapeSynthesizer<S> _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 <class S>
|
|
ASTExtInfo synthesizeExtInfo(SynthesisContext &SC,
|
|
const ThrowsSynthesizer<S> &s) {
|
|
return synthesizeExtInfo(SC, s.sub).withThrows();
|
|
}
|
|
template <class S>
|
|
ASTExtInfo synthesizeExtInfo(SynthesisContext &SC,
|
|
const AsyncSynthesizer<S> &s) {
|
|
return synthesizeExtInfo(SC, s.sub).withAsync();
|
|
}
|
|
template <class S>
|
|
ASTExtInfo synthesizeExtInfo(SynthesisContext &SC,
|
|
const NoescapeSynthesizer<S> &s) {
|
|
return synthesizeExtInfo(SC, s.sub).withNoEscape();
|
|
}
|
|
|
|
/// Synthesize a function type.
|
|
template <class ExtInfoS, class ResultS, class ParamsS>
|
|
struct FunctionTypeSynthesizer {
|
|
ExtInfoS extInfo;
|
|
ResultS result;
|
|
ParamsS parameters;
|
|
};
|
|
template <class ExtInfoS, class ResultS, class ParamsS>
|
|
FunctionTypeSynthesizer<ExtInfoS, ResultS, ParamsS>
|
|
_function(ExtInfoS extInfo, ResultS result, ParamsS params) {
|
|
return {extInfo, result, params};
|
|
}
|
|
template <class ExtInfoS, class ResultS, class ParamsS>
|
|
Type synthesizeType(SynthesisContext &SC,
|
|
const FunctionTypeSynthesizer<ExtInfoS, ResultS, ParamsS> &fn) {
|
|
SmallVector<FunctionType::Param, 4> 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 <class S>
|
|
struct OptionalSynthesizer {
|
|
S sub;
|
|
};
|
|
template <class S>
|
|
constexpr OptionalSynthesizer<S> _optional(S sub) { return {sub}; }
|
|
template <class S>
|
|
Type synthesizeType(SynthesisContext &SC, const OptionalSynthesizer<S> &s) {
|
|
return OptionalType::get(synthesizeType(SC, s.sub));
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|