mirror of
https://github.com/apple/swift.git
synced 2026-06-27 12:25:55 +02:00
422136e1a2
Before the changes:
- `git grep -E "enum class .+ : uint8_t \{" | wc -l`: 90
- `git grep -E "enum class .+ : unsigned char \{" | wc -l`: 26
343 lines
11 KiB
C++
343 lines
11 KiB
C++
//===--- ArgumentSource.h - Abstracted source of an argument ----*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// A structure for holding an abstracted source of a call argument.
|
|
// It's either:
|
|
//
|
|
// - an expression, yielding an l-value or r-value
|
|
// - an RValue
|
|
// - an LValue
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_LOWERING_ARGUMENTSOURCE_H
|
|
#define SWIFT_LOWERING_ARGUMENTSOURCE_H
|
|
|
|
#include "swift/Basic/ExternalUnion.h"
|
|
#include "RValue.h"
|
|
#include "LValue.h"
|
|
|
|
namespace swift {
|
|
namespace Lowering {
|
|
class Conversion;
|
|
|
|
/// A means of generating an argument.
|
|
///
|
|
/// This is useful as a way to pass values around without either:
|
|
/// - requiring them to have already been evaluated or
|
|
/// - requiring them to come from an identifiable expression.
|
|
///
|
|
/// Being able to propagate values is important because there are a
|
|
/// number of cases (involving, say, property accessors) where values
|
|
/// are implicitly or previously generated. However, being able to
|
|
/// propagate Expr*s is also important because there are several kinds
|
|
/// of expressions (such as closures) which can be emitted more
|
|
/// efficiently with a known target abstraction level.
|
|
///
|
|
/// Because an ArgumentSource might contain an unevaluated expression,
|
|
/// care must be taken when dealing with multiple ArgumentSources to
|
|
/// preserve the original evaluation order of the program. APIs
|
|
/// working with multiple ArgumentSources should document the order in
|
|
/// which they plan to evaluate them.
|
|
class ArgumentSource {
|
|
enum class Kind : uint8_t {
|
|
Invalid,
|
|
RValue,
|
|
LValue,
|
|
Expr,
|
|
Tuple,
|
|
};
|
|
|
|
struct RValueStorage {
|
|
RValue Value;
|
|
SILLocation Loc;
|
|
};
|
|
struct LValueStorage {
|
|
LValue Value;
|
|
SILLocation Loc;
|
|
};
|
|
struct TupleStorage {
|
|
CanTupleType SubstType;
|
|
SILLocation Loc;
|
|
std::vector<ArgumentSource> Elements;
|
|
|
|
TupleStorage(CanTupleType type, SILLocation loc,
|
|
MutableArrayRef<ArgumentSource> elements)
|
|
: SubstType(type), Loc(loc) {
|
|
assert(type->getNumElements() == elements.size());
|
|
Elements.reserve(elements.size());
|
|
for (auto i : indices(elements)) {
|
|
Elements.push_back(std::move(elements[i]));
|
|
}
|
|
}
|
|
};
|
|
|
|
using StorageMembers =
|
|
ExternalUnionMembers<void, RValueStorage, LValueStorage,
|
|
Expr*, TupleStorage>;
|
|
|
|
static StorageMembers::Index getStorageIndexForKind(Kind kind) {
|
|
switch (kind) {
|
|
case Kind::Invalid: return StorageMembers::indexOf<void>();
|
|
case Kind::RValue:
|
|
return StorageMembers::indexOf<RValueStorage>();
|
|
case Kind::LValue: return StorageMembers::indexOf<LValueStorage>();
|
|
case Kind::Expr: return StorageMembers::indexOf<Expr*>();
|
|
case Kind::Tuple: return StorageMembers::indexOf<TupleStorage>();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
ExternalUnion<Kind, StorageMembers, getStorageIndexForKind> Storage;
|
|
Kind StoredKind;
|
|
|
|
public:
|
|
ArgumentSource() : StoredKind(Kind::Invalid) {}
|
|
ArgumentSource(SILLocation loc, RValue &&value) : StoredKind(Kind::RValue) {
|
|
Storage.emplaceAggregate<RValueStorage>(StoredKind, std::move(value), loc);
|
|
}
|
|
ArgumentSource(SILLocation loc, LValue &&value) : StoredKind(Kind::LValue) {
|
|
Storage.emplaceAggregate<LValueStorage>(StoredKind, std::move(value), loc);
|
|
}
|
|
ArgumentSource(Expr *e) : StoredKind(Kind::Expr) {
|
|
assert(e && "initializing ArgumentSource with null expression");
|
|
Storage.emplace<Expr*>(StoredKind, e);
|
|
}
|
|
ArgumentSource(SILLocation loc, CanTupleType type,
|
|
MutableArrayRef<ArgumentSource> elements)
|
|
: StoredKind(Kind::Tuple) {
|
|
Storage.emplace<TupleStorage>(StoredKind, type, loc, elements);
|
|
}
|
|
|
|
// Cannot be copied.
|
|
ArgumentSource(const ArgumentSource &other) = delete;
|
|
ArgumentSource &operator=(const ArgumentSource &other) = delete;
|
|
|
|
// Can be moved.
|
|
ArgumentSource(ArgumentSource &&other) : StoredKind(other.StoredKind) {
|
|
Storage.moveConstruct(StoredKind, std::move(other.Storage));
|
|
}
|
|
|
|
ArgumentSource &operator=(ArgumentSource &&other) {
|
|
Storage.moveAssign(StoredKind, other.StoredKind, std::move(other.Storage));
|
|
StoredKind = other.StoredKind;
|
|
other.Storage.destruct(other.StoredKind);
|
|
other.StoredKind = Kind::Invalid;
|
|
return *this;
|
|
}
|
|
|
|
~ArgumentSource() {
|
|
Storage.destruct(StoredKind);
|
|
}
|
|
|
|
explicit operator bool() const & {
|
|
switch (StoredKind) {
|
|
case Kind::Invalid:
|
|
return false;
|
|
case Kind::RValue:
|
|
return !asKnownRValue().isNull();
|
|
case Kind::LValue:
|
|
return asKnownLValue().isValid();
|
|
case Kind::Expr:
|
|
return asKnownExpr() != nullptr;
|
|
case Kind::Tuple:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
CanType getSubstType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("argument source is invalid");
|
|
case Kind::RValue:
|
|
return asKnownRValue().getType();
|
|
case Kind::LValue:
|
|
return CanInOutType::get(asKnownLValue().getSubstFormalType());
|
|
case Kind::Expr:
|
|
return asKnownExpr()->getType()->getCanonicalType();
|
|
case Kind::Tuple:
|
|
return Storage.get<TupleStorage>(StoredKind).SubstType;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
SILType getSILSubstType(SILGenFunction &SGF) const &;
|
|
|
|
CanType getSubstRValueType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("argument source is invalid");
|
|
case Kind::RValue:
|
|
return asKnownRValue().getType();
|
|
case Kind::LValue:
|
|
return asKnownLValue().getSubstFormalType();
|
|
case Kind::Expr:
|
|
return asKnownExpr()->getType()->getInOutObjectType()->getCanonicalType();
|
|
case Kind::Tuple:
|
|
return Storage.get<TupleStorage>(StoredKind).SubstType;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
SILType getSILSubstRValueType(SILGenFunction &SGF) const &;
|
|
|
|
bool hasLValueType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::Invalid: llvm_unreachable("argument source is invalid");
|
|
case Kind::RValue:
|
|
return false;
|
|
case Kind::LValue: return true;
|
|
case Kind::Expr: return asKnownExpr()->isSemanticallyInOutExpr();
|
|
case Kind::Tuple: return false;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
SILLocation getLocation() const & {
|
|
switch (StoredKind) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("argument source is invalid");
|
|
case Kind::RValue:
|
|
return getKnownRValueLocation();
|
|
case Kind::LValue:
|
|
return getKnownLValueLocation();
|
|
case Kind::Expr:
|
|
return asKnownExpr();
|
|
case Kind::Tuple:
|
|
return getKnownTupleLocation();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool isExpr() const & { return StoredKind == Kind::Expr; }
|
|
bool isRValue() const & { return StoredKind == Kind::RValue; }
|
|
bool isLValue() const & { return StoredKind == Kind::LValue; }
|
|
bool isTuple() const & { return StoredKind == Kind::Tuple; }
|
|
|
|
/// Given that this source is storing an RValue, extract and clear
|
|
/// that value.
|
|
RValue &&asKnownRValue(SILGenFunction &SGF) && {
|
|
return std::move(Storage.get<RValueStorage>(StoredKind).Value);
|
|
}
|
|
|
|
SILLocation getKnownRValueLocation() const & {
|
|
return Storage.get<RValueStorage>(StoredKind).Loc;
|
|
}
|
|
|
|
/// Given that this source is storing an LValue, extract and clear
|
|
/// that value.
|
|
LValue &&asKnownLValue() && {
|
|
return std::move(Storage.get<LValueStorage>(StoredKind).Value);
|
|
}
|
|
SILLocation getKnownLValueLocation() const & {
|
|
return Storage.get<LValueStorage>(StoredKind).Loc;
|
|
}
|
|
|
|
/// Given that this source is an expression, extract and clear
|
|
/// that expression.
|
|
Expr *asKnownExpr() && {
|
|
Expr *result = Storage.get<Expr*>(StoredKind);
|
|
Storage.resetToEmpty<Expr*>(StoredKind, Kind::Invalid);
|
|
StoredKind = Kind::Invalid;
|
|
return result;
|
|
}
|
|
|
|
SILLocation getKnownTupleLocation() const & {
|
|
return Storage.get<TupleStorage>(StoredKind).Loc;
|
|
}
|
|
|
|
template <class ResultType>
|
|
ResultType withKnownTupleElementSources(
|
|
llvm::function_ref<ResultType(SILLocation loc, CanTupleType type,
|
|
MutableArrayRef<ArgumentSource> elts)> callback) && {
|
|
auto &tuple = Storage.get<TupleStorage>(StoredKind);
|
|
|
|
auto result = callback(tuple.Loc, tuple.SubstType, tuple.Elements);
|
|
|
|
// We've consumed the tuple.
|
|
Storage.resetToEmpty<TupleStorage>(StoredKind, Kind::Invalid);
|
|
StoredKind = Kind::Invalid;
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Return an unowned handle to the r-value stored in this source. Undefined
|
|
/// if this ArgumentSource is not an rvalue.
|
|
RValue &peekRValue() &;
|
|
|
|
RValue getAsRValue(SILGenFunction &SGF, SGFContext C = SGFContext()) &&;
|
|
ManagedValue getAsSingleValue(SILGenFunction &SGF,
|
|
SGFContext C = SGFContext()) &&;
|
|
ManagedValue getAsSingleValue(SILGenFunction &SGF,
|
|
AbstractionPattern origFormalType,
|
|
SGFContext C = SGFContext()) &&;
|
|
|
|
ManagedValue getConverted(SILGenFunction &SGF, const Conversion &conversion,
|
|
SGFContext C = SGFContext()) &&;
|
|
|
|
void forwardInto(SILGenFunction &SGF, Initialization *dest) &&;
|
|
void forwardInto(SILGenFunction &SGF, AbstractionPattern origFormalType,
|
|
Initialization *dest, const TypeLowering &destTL) &&;
|
|
|
|
/// If we have an rvalue, borrow the rvalue into a new ArgumentSource and
|
|
/// return the ArgumentSource. Otherwise, assert.
|
|
ArgumentSource borrow(SILGenFunction &SGF) const &;
|
|
|
|
ManagedValue materialize(SILGenFunction &SGF) &&;
|
|
|
|
/// Emit this value to memory so that it follows the abstraction
|
|
/// patterns of the original formal type.
|
|
///
|
|
/// \param expectedType - the lowering of getSubstType() under the
|
|
/// abstractions of origFormalType
|
|
ManagedValue materialize(SILGenFunction &SGF,
|
|
AbstractionPattern origFormalType,
|
|
SILType expectedType = SILType()) &&;
|
|
|
|
// This is a hack and should be avoided.
|
|
void rewriteType(CanType newType) &;
|
|
|
|
/// Whether this argument source requires the callee to evaluate.
|
|
bool requiresCalleeToEvaluate() const;
|
|
|
|
void dump() const;
|
|
void dump(raw_ostream &os, unsigned indent = 0) const;
|
|
|
|
private:
|
|
/// Private helper constructor for delayed borrowed rvalues.
|
|
ArgumentSource(SILLocation loc, RValue &&rv, Kind kind);
|
|
|
|
// Make the non-move accessors private to make it more difficult
|
|
// to accidentally re-emit values.
|
|
const RValue &asKnownRValue() const & {
|
|
return Storage.get<RValueStorage>(StoredKind).Value;
|
|
}
|
|
|
|
// Make the non-move accessors private to make it more difficult
|
|
// to accidentally re-emit values.
|
|
const LValue &asKnownLValue() const & {
|
|
return Storage.get<LValueStorage>(StoredKind).Value;
|
|
}
|
|
|
|
Expr *asKnownExpr() const & {
|
|
return Storage.get<Expr*>(StoredKind);
|
|
}
|
|
|
|
RValue getKnownTupleAsRValue(SILGenFunction &SGF, SGFContext C) &&;
|
|
};
|
|
|
|
} // end namespace Lowering
|
|
} // end namespace swift
|
|
|
|
#endif
|