[flang] Put templates back into implementation header

Original-commit: flang-compiler/f18@8949924351
Reviewed-on: https://github.com/flang-compiler/f18/pull/900
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-12-31 13:58:26 -08:00
parent 8deb4bbeb7
commit ceb8196023
2 changed files with 352 additions and 355 deletions

View File

@ -45,6 +45,7 @@
namespace Fortran::evaluate {
// Utilities
template<typename T> class Folder {
public:
explicit Folder(FoldingContext &c) : context_{c} {}
@ -63,7 +64,6 @@ public:
private:
FoldingContext &context_;
};
FOR_EACH_SPECIFIC_TYPE(extern template class Folder, )
// FoldOperation() rewrites expression tree nodes.
// If there is any possibility that the rewritten node will
@ -119,6 +119,357 @@ template<typename T>
Expr<T> FoldOperation(FoldingContext &, ArrayConstructor<T> &&);
Expr<SomeDerived> FoldOperation(FoldingContext &, StructureConstructor &&);
template<typename T>
std::optional<Expr<T>> Folder<T>::GetNamedConstantValue(const Symbol &symbol0) {
const Symbol &symbol{ResolveAssociations(symbol0).GetUltimate()};
if (IsNamedConstant(symbol)) {
if (const auto *object{
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
if (object->initWasValidated()) {
const auto *constant{UnwrapConstantValue<T>(object->init())};
return Expr<T>{DEREF(constant)};
}
if (const auto &init{object->init()}) {
if (auto dyType{DynamicType::From(symbol)}) {
semantics::ObjectEntityDetails *mutableObject{
const_cast<semantics::ObjectEntityDetails *>(object)};
auto converted{
ConvertToType(*dyType, std::move(mutableObject->init().value()))};
// Reset expression now to prevent infinite loops if the init
// expression depends on symbol itself.
mutableObject->set_init(std::nullopt);
if (converted) {
*converted = Fold(context_, std::move(*converted));
auto *unwrapped{UnwrapExpr<Expr<T>>(*converted)};
CHECK(unwrapped);
if (auto *constant{UnwrapConstantValue<T>(*unwrapped)}) {
if (symbol.Rank() > 0) {
if (constant->Rank() == 0) {
// scalar expansion
if (auto symShape{GetShape(context_, symbol)}) {
if (auto extents{AsConstantExtents(context_, *symShape)}) {
*constant = constant->Reshape(std::move(*extents));
CHECK(constant->Rank() == symbol.Rank());
}
}
}
if (constant->Rank() == symbol.Rank()) {
NamedEntity base{symbol};
if (auto lbounds{AsConstantExtents(
context_, GetLowerBounds(context_, base))}) {
constant->set_lbounds(*std::move(lbounds));
}
}
}
mutableObject->set_init(AsGenericExpr(Expr<T>{*constant}));
if (auto constShape{GetShape(context_, *constant)}) {
if (auto symShape{GetShape(context_, symbol)}) {
if (CheckConformance(context_.messages(), *constShape,
*symShape, "initialization expression",
"PARAMETER")) {
mutableObject->set_initWasValidated();
return std::move(*unwrapped);
}
} else {
context_.messages().Say(symbol.name(),
"Could not determine the shape of the PARAMETER"_err_en_US);
}
} else {
context_.messages().Say(symbol.name(),
"Could not determine the shape of the initialization expression"_err_en_US);
}
mutableObject->set_init(std::nullopt);
} else {
std::stringstream ss;
unwrapped->AsFortran(ss);
context_.messages().Say(symbol.name(),
"Initialization expression for PARAMETER '%s' (%s) cannot be computed as a constant value"_err_en_US,
symbol.name(), ss.str());
}
} else {
std::stringstream ss;
init->AsFortran(ss);
context_.messages().Say(symbol.name(),
"Initialization expression for PARAMETER '%s' (%s) cannot be converted to its type (%s)"_err_en_US,
symbol.name(), ss.str(), dyType->AsFortran());
}
}
}
}
}
return std::nullopt;
}
template<typename T>
std::optional<Constant<T>> Folder<T>::GetFoldedNamedConstantValue(
const Symbol &symbol) {
if (auto value{GetNamedConstantValue(symbol)}) {
Expr<T> folded{Fold(context_, std::move(*value))};
if (const Constant<T> *value{UnwrapConstantValue<T>(folded)}) {
return *value;
}
}
return std::nullopt;
}
static std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) {
ss = FoldOperation(context, std::move(ss));
return std::visit(
common::visitors{
[](IndirectSubscriptIntegerExpr &expr)
-> std::optional<Constant<SubscriptInteger>> {
if (auto constant{
GetScalarConstantValue<SubscriptInteger>(expr.value())}) {
return Constant<SubscriptInteger>{*constant};
} else {
return std::nullopt;
}
},
[&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> {
auto lower{triplet.lower()}, upper{triplet.upper()};
std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())};
if (!lower) {
lower = GetLowerBound(context, base, dim);
}
if (!upper) {
upper =
ComputeUpperBound(context, GetLowerBound(context, base, dim),
GetExtent(context, base, dim));
}
auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)};
if (lbi && ubi && stride && *stride != 0) {
std::vector<SubscriptInteger::Scalar> values;
while ((*stride > 0 && *lbi <= *ubi) ||
(*stride < 0 && *lbi >= *ubi)) {
values.emplace_back(*lbi);
*lbi += *stride;
}
return Constant<SubscriptInteger>{std::move(values),
ConstantSubscripts{
static_cast<ConstantSubscript>(values.size())}};
} else {
return std::nullopt;
}
},
},
ss.u);
}
template<typename T>
std::optional<Constant<T>> Folder<T>::Folding(ArrayRef &aRef) {
std::vector<Constant<SubscriptInteger>> subscripts;
int dim{0};
for (Subscript &ss : aRef.subscript()) {
if (auto constant{GetConstantSubscript(context_, ss, aRef.base(), dim++)}) {
subscripts.emplace_back(std::move(*constant));
} else {
return std::nullopt;
}
}
if (Component * component{aRef.base().UnwrapComponent()}) {
return GetConstantComponent(*component, &subscripts);
} else if (std::optional<Constant<T>> array{
GetFoldedNamedConstantValue(aRef.base().GetLastSymbol())}) {
return ApplySubscripts(*array, subscripts);
} else {
return std::nullopt;
}
}
template<typename T>
std::optional<Constant<T>> Folder<T>::ApplySubscripts(const Constant<T> &array,
const std::vector<Constant<SubscriptInteger>> &subscripts) {
const auto &shape{array.shape()};
const auto &lbounds{array.lbounds()};
int rank{GetRank(shape)};
CHECK(rank == static_cast<int>(subscripts.size()));
std::size_t elements{1};
ConstantSubscripts resultShape;
ConstantSubscripts ssLB;
for (const auto &ss : subscripts) {
CHECK(ss.Rank() <= 1);
if (ss.Rank() == 1) {
resultShape.push_back(static_cast<ConstantSubscript>(ss.size()));
elements *= ss.size();
ssLB.push_back(ss.lbounds().front());
}
}
ConstantSubscripts ssAt(rank, 0), at(rank, 0), tmp(1, 0);
std::vector<Scalar<T>> values;
while (elements-- > 0) {
bool increment{true};
int k{0};
for (int j{0}; j < rank; ++j) {
if (subscripts[j].Rank() == 0) {
at[j] = subscripts[j].GetScalarValue().value().ToInt64();
} else {
CHECK(k < GetRank(resultShape));
tmp[0] = ssLB[j] + ssAt[j];
at[j] = subscripts[j].At(tmp).ToInt64();
if (increment) {
if (++ssAt[j] == resultShape[k]) {
ssAt[j] = 0;
} else {
increment = false;
}
}
++k;
}
if (at[j] < lbounds[j] || at[j] >= lbounds[j] + shape[j]) {
context_.messages().Say(
"Subscript value (%jd) is out of range on dimension %d in reference to a constant array value"_err_en_US,
static_cast<std::intmax_t>(at[j]), j + 1);
return std::nullopt;
}
}
values.emplace_back(array.At(at));
CHECK(!increment || elements == 0);
CHECK(k == GetRank(resultShape));
}
if constexpr (T::category == TypeCategory::Character) {
return Constant<T>{array.LEN(), std::move(values), std::move(resultShape)};
} else if constexpr (std::is_same_v<T, SomeDerived>) {
return Constant<T>{array.result().derivedTypeSpec(), std::move(values),
std::move(resultShape)};
} else {
return Constant<T>{std::move(values), std::move(resultShape)};
}
}
template<typename T>
std::optional<Constant<T>> Folder<T>::ApplyComponent(
Constant<SomeDerived> &&structures, const Symbol &component,
const std::vector<Constant<SubscriptInteger>> *subscripts) {
if (auto scalar{structures.GetScalarValue()}) {
if (auto *expr{scalar->Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (!subscripts) {
return std::move(*value);
} else {
return ApplySubscripts(*value, *subscripts);
}
}
}
} else {
// A(:)%scalar_component & A(:)%array_component(subscripts)
std::unique_ptr<ArrayConstructor<T>> array;
if (structures.empty()) {
return std::nullopt;
}
ConstantSubscripts at{structures.lbounds()};
do {
StructureConstructor scalar{structures.At(at)};
if (auto *expr{scalar.Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (!array.get()) {
// This technique ensures that character length or derived type
// information is propagated to the array constructor.
auto *typedExpr{UnwrapExpr<Expr<T>>(*expr)};
CHECK(typedExpr);
array = std::make_unique<ArrayConstructor<T>>(*typedExpr);
}
if (subscripts) {
if (auto element{ApplySubscripts(*value, *subscripts)}) {
CHECK(element->Rank() == 0);
array->Push(Expr<T>{std::move(*element)});
} else {
return std::nullopt;
}
} else {
CHECK(value->Rank() == 0);
array->Push(Expr<T>{*value});
}
} else {
return std::nullopt;
}
}
} while (structures.IncrementSubscripts(at));
// Fold the ArrayConstructor<> into a Constant<>.
CHECK(array);
Expr<T> result{Fold(context_, Expr<T>{std::move(*array)})};
if (auto *constant{UnwrapConstantValue<T>(result)}) {
return constant->Reshape(common::Clone(structures.shape()));
}
}
return std::nullopt;
}
template<typename T>
std::optional<Constant<T>> Folder<T>::GetConstantComponent(Component &component,
const std::vector<Constant<SubscriptInteger>> *subscripts) {
if (std::optional<Constant<SomeDerived>> structures{std::visit(
common::visitors{
[&](const Symbol &symbol) {
return Folder<SomeDerived>{context_}
.GetFoldedNamedConstantValue(symbol);
},
[&](ArrayRef &aRef) {
return Folder<SomeDerived>{context_}.Folding(aRef);
},
[&](Component &base) {
return Folder<SomeDerived>{context_}.GetConstantComponent(base);
},
[&](CoarrayRef &) {
return std::optional<Constant<SomeDerived>>{};
},
},
component.base().u)}) {
return ApplyComponent(
std::move(*structures), component.GetLastSymbol(), subscripts);
} else {
return std::nullopt;
}
}
template<typename T> Expr<T> Folder<T>::Folding(Designator<T> &&designator) {
if constexpr (T::category == TypeCategory::Character) {
if (auto *substring{common::Unwrap<Substring>(designator.u)}) {
if (std::optional<Expr<SomeCharacter>> folded{
substring->Fold(context_)}) {
if (auto value{GetScalarConstantValue<T>(*folded)}) {
return Expr<T>{*value};
}
}
if (auto length{ToInt64(Fold(context_, substring->LEN()))}) {
if (*length == 0) {
return Expr<T>{Constant<T>{Scalar<T>{}}};
}
}
}
}
return std::visit(
common::visitors{
[&](SymbolRef &&symbol) {
if (auto constant{GetFoldedNamedConstantValue(*symbol)}) {
return Expr<T>{std::move(*constant)};
}
return Expr<T>{std::move(designator)};
},
[&](ArrayRef &&aRef) {
aRef = FoldOperation(context_, std::move(aRef));
if (auto c{Folding(aRef)}) {
return Expr<T>{std::move(*c)};
} else {
return Expr<T>{Designator<T>{std::move(aRef)}};
}
},
[&](Component &&component) {
component = FoldOperation(context_, std::move(component));
if (auto c{GetConstantComponent(component)}) {
return Expr<T>{std::move(*c)};
} else {
return Expr<T>{Designator<T>{std::move(component)}};
}
},
[&](auto &&x) {
return Expr<T>{
Designator<T>{FoldOperation(context_, std::move(x))}};
},
},
std::move(designator.u));
}
// helpers to fold intrinsic function references
// Define callable types used in a common utility that
// takes care of array and cast/conversion aspects for elemental intrinsics

View File

@ -11,360 +11,6 @@
namespace Fortran::evaluate {
template<typename T>
std::optional<Expr<T>> Folder<T>::GetNamedConstantValue(const Symbol &symbol0) {
const Symbol &symbol{ResolveAssociations(symbol0).GetUltimate()};
if (IsNamedConstant(symbol)) {
if (const auto *object{
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
if (object->initWasValidated()) {
const auto *constant{UnwrapConstantValue<T>(object->init())};
CHECK(constant);
return Expr<T>{*constant};
}
if (const auto &init{object->init()}) {
if (auto dyType{DynamicType::From(symbol)}) {
semantics::ObjectEntityDetails *mutableObject{
const_cast<semantics::ObjectEntityDetails *>(object)};
auto converted{
ConvertToType(*dyType, std::move(mutableObject->init().value()))};
// Reset expression now to prevent infinite loops if the init
// expression depends on symbol itself.
mutableObject->set_init(std::nullopt);
if (converted) {
*converted = Fold(context_, std::move(*converted));
auto *unwrapped{UnwrapExpr<Expr<T>>(*converted)};
CHECK(unwrapped);
if (auto *constant{UnwrapConstantValue<T>(*unwrapped)}) {
if (symbol.Rank() > 0) {
if (constant->Rank() == 0) {
// scalar expansion
if (auto symShape{GetShape(context_, symbol)}) {
if (auto extents{AsConstantExtents(context_, *symShape)}) {
*constant = constant->Reshape(std::move(*extents));
CHECK(constant->Rank() == symbol.Rank());
}
}
}
if (constant->Rank() == symbol.Rank()) {
NamedEntity base{symbol};
if (auto lbounds{AsConstantExtents(
context_, GetLowerBounds(context_, base))}) {
constant->set_lbounds(*std::move(lbounds));
}
}
}
mutableObject->set_init(AsGenericExpr(Expr<T>{*constant}));
if (auto constShape{GetShape(context_, *constant)}) {
if (auto symShape{GetShape(context_, symbol)}) {
if (CheckConformance(context_.messages(), *constShape,
*symShape, "initialization expression",
"PARAMETER")) {
mutableObject->set_initWasValidated();
return std::move(*unwrapped);
}
} else {
context_.messages().Say(symbol.name(),
"Could not determine the shape of the PARAMETER"_err_en_US);
}
} else {
context_.messages().Say(symbol.name(),
"Could not determine the shape of the initialization expression"_err_en_US);
}
mutableObject->set_init(std::nullopt);
} else {
std::stringstream ss;
unwrapped->AsFortran(ss);
context_.messages().Say(symbol.name(),
"Initialization expression for PARAMETER '%s' (%s) cannot be computed as a constant value"_err_en_US,
symbol.name(), ss.str());
}
} else {
std::stringstream ss;
init->AsFortran(ss);
context_.messages().Say(symbol.name(),
"Initialization expression for PARAMETER '%s' (%s) cannot be converted to its type (%s)"_err_en_US,
symbol.name(), ss.str(), dyType->AsFortran());
}
}
}
}
}
return std::nullopt;
}
template<typename T>
std::optional<Constant<T>> Folder<T>::GetFoldedNamedConstantValue(
const Symbol &symbol) {
if (auto value{GetNamedConstantValue(symbol)}) {
Expr<T> folded{Fold(context_, std::move(*value))};
if (const Constant<T> *value{UnwrapConstantValue<T>(folded)}) {
return *value;
}
}
return std::nullopt;
}
static std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) {
ss = FoldOperation(context, std::move(ss));
return std::visit(
common::visitors{
[](IndirectSubscriptIntegerExpr &expr)
-> std::optional<Constant<SubscriptInteger>> {
if (auto constant{
GetScalarConstantValue<SubscriptInteger>(expr.value())}) {
return Constant<SubscriptInteger>{*constant};
} else {
return std::nullopt;
}
},
[&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> {
auto lower{triplet.lower()}, upper{triplet.upper()};
std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())};
if (!lower) {
lower = GetLowerBound(context, base, dim);
}
if (!upper) {
upper =
ComputeUpperBound(context, GetLowerBound(context, base, dim),
GetExtent(context, base, dim));
}
auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)};
if (lbi && ubi && stride && *stride != 0) {
std::vector<SubscriptInteger::Scalar> values;
while ((*stride > 0 && *lbi <= *ubi) ||
(*stride < 0 && *lbi >= *ubi)) {
values.emplace_back(*lbi);
*lbi += *stride;
}
return Constant<SubscriptInteger>{std::move(values),
ConstantSubscripts{
static_cast<ConstantSubscript>(values.size())}};
} else {
return std::nullopt;
}
},
},
ss.u);
}
template<typename T>
std::optional<Constant<T>> Folder<T>::Folding(ArrayRef &aRef) {
std::vector<Constant<SubscriptInteger>> subscripts;
int dim{0};
for (Subscript &ss : aRef.subscript()) {
if (auto constant{GetConstantSubscript(context_, ss, aRef.base(), dim++)}) {
subscripts.emplace_back(std::move(*constant));
} else {
return std::nullopt;
}
}
if (Component * component{aRef.base().UnwrapComponent()}) {
return GetConstantComponent(*component, &subscripts);
} else if (std::optional<Constant<T>> array{
GetFoldedNamedConstantValue(aRef.base().GetLastSymbol())}) {
return ApplySubscripts(*array, subscripts);
} else {
return std::nullopt;
}
}
template<typename T>
std::optional<Constant<T>> Folder<T>::ApplySubscripts(const Constant<T> &array,
const std::vector<Constant<SubscriptInteger>> &subscripts) {
const auto &shape{array.shape()};
const auto &lbounds{array.lbounds()};
int rank{GetRank(shape)};
CHECK(rank == static_cast<int>(subscripts.size()));
std::size_t elements{1};
ConstantSubscripts resultShape;
ConstantSubscripts ssLB;
for (const auto &ss : subscripts) {
CHECK(ss.Rank() <= 1);
if (ss.Rank() == 1) {
resultShape.push_back(static_cast<ConstantSubscript>(ss.size()));
elements *= ss.size();
ssLB.push_back(ss.lbounds().front());
}
}
ConstantSubscripts ssAt(rank, 0), at(rank, 0), tmp(1, 0);
std::vector<Scalar<T>> values;
while (elements-- > 0) {
bool increment{true};
int k{0};
for (int j{0}; j < rank; ++j) {
if (subscripts[j].Rank() == 0) {
at[j] = subscripts[j].GetScalarValue().value().ToInt64();
} else {
CHECK(k < GetRank(resultShape));
tmp[0] = ssLB[j] + ssAt[j];
at[j] = subscripts[j].At(tmp).ToInt64();
if (increment) {
if (++ssAt[j] == resultShape[k]) {
ssAt[j] = 0;
} else {
increment = false;
}
}
++k;
}
if (at[j] < lbounds[j] || at[j] >= lbounds[j] + shape[j]) {
context_.messages().Say(
"Subscript value (%jd) is out of range on dimension %d in reference to a constant array value"_err_en_US,
static_cast<std::intmax_t>(at[j]), j + 1);
return std::nullopt;
}
}
values.emplace_back(array.At(at));
CHECK(!increment || elements == 0);
CHECK(k == GetRank(resultShape));
}
if constexpr (T::category == TypeCategory::Character) {
return Constant<T>{array.LEN(), std::move(values), std::move(resultShape)};
} else if constexpr (std::is_same_v<T, SomeDerived>) {
return Constant<T>{array.result().derivedTypeSpec(), std::move(values),
std::move(resultShape)};
} else {
return Constant<T>{std::move(values), std::move(resultShape)};
}
}
template<typename T>
std::optional<Constant<T>> Folder<T>::ApplyComponent(
Constant<SomeDerived> &&structures, const Symbol &component,
const std::vector<Constant<SubscriptInteger>> *subscripts) {
if (auto scalar{structures.GetScalarValue()}) {
if (auto *expr{scalar->Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (!subscripts) {
return std::move(*value);
} else {
return ApplySubscripts(*value, *subscripts);
}
}
}
} else {
// A(:)%scalar_component & A(:)%array_component(subscripts)
std::unique_ptr<ArrayConstructor<T>> array;
if (structures.empty()) {
return std::nullopt;
}
ConstantSubscripts at{structures.lbounds()};
do {
StructureConstructor scalar{structures.At(at)};
if (auto *expr{scalar.Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (!array.get()) {
// This technique ensures that character length or derived type
// information is propagated to the array constructor.
auto *typedExpr{UnwrapExpr<Expr<T>>(*expr)};
CHECK(typedExpr);
array = std::make_unique<ArrayConstructor<T>>(*typedExpr);
}
if (subscripts) {
if (auto element{ApplySubscripts(*value, *subscripts)}) {
CHECK(element->Rank() == 0);
array->Push(Expr<T>{std::move(*element)});
} else {
return std::nullopt;
}
} else {
CHECK(value->Rank() == 0);
array->Push(Expr<T>{*value});
}
} else {
return std::nullopt;
}
}
} while (structures.IncrementSubscripts(at));
// Fold the ArrayConstructor<> into a Constant<>.
CHECK(array);
Expr<T> result{Fold(context_, Expr<T>{std::move(*array)})};
if (auto *constant{UnwrapConstantValue<T>(result)}) {
return constant->Reshape(common::Clone(structures.shape()));
}
}
return std::nullopt;
}
template<typename T>
std::optional<Constant<T>> Folder<T>::GetConstantComponent(Component &component,
const std::vector<Constant<SubscriptInteger>> *subscripts) {
if (std::optional<Constant<SomeDerived>> structures{std::visit(
common::visitors{
[&](const Symbol &symbol) {
return Folder<SomeDerived>{context_}
.GetFoldedNamedConstantValue(symbol);
},
[&](ArrayRef &aRef) {
return Folder<SomeDerived>{context_}.Folding(aRef);
},
[&](Component &base) {
return Folder<SomeDerived>{context_}.GetConstantComponent(base);
},
[&](CoarrayRef &) {
return std::optional<Constant<SomeDerived>>{};
},
},
component.base().u)}) {
return ApplyComponent(
std::move(*structures), component.GetLastSymbol(), subscripts);
} else {
return std::nullopt;
}
}
template<typename T> Expr<T> Folder<T>::Folding(Designator<T> &&designator) {
if constexpr (T::category == TypeCategory::Character) {
if (auto *substring{common::Unwrap<Substring>(designator.u)}) {
if (std::optional<Expr<SomeCharacter>> folded{
substring->Fold(context_)}) {
if (auto value{GetScalarConstantValue<T>(*folded)}) {
return Expr<T>{*value};
}
}
if (auto length{ToInt64(Fold(context_, substring->LEN()))}) {
if (*length == 0) {
return Expr<T>{Constant<T>{Scalar<T>{}}};
}
}
}
}
return std::visit(
common::visitors{
[&](SymbolRef &&symbol) {
if (auto constant{GetFoldedNamedConstantValue(*symbol)}) {
return Expr<T>{std::move(*constant)};
}
return Expr<T>{std::move(designator)};
},
[&](ArrayRef &&aRef) {
aRef = FoldOperation(context_, std::move(aRef));
if (auto c{Folding(aRef)}) {
return Expr<T>{std::move(*c)};
} else {
return Expr<T>{Designator<T>{std::move(aRef)}};
}
},
[&](Component &&component) {
component = FoldOperation(context_, std::move(component));
if (auto c{GetConstantComponent(component)}) {
return Expr<T>{std::move(*c)};
} else {
return Expr<T>{Designator<T>{std::move(component)}};
}
},
[&](auto &&x) {
return Expr<T>{
Designator<T>{FoldOperation(context_, std::move(x))}};
},
},
std::move(designator.u));
}
FOR_EACH_SPECIFIC_TYPE(template class Folder, )
Expr<SomeDerived> FoldOperation(
FoldingContext &context, StructureConstructor &&structure) {
StructureConstructor result{structure.derivedTypeSpec()};