template<int KIND>
auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
- const ScalarConstant<TypeCategory::Integer> &c) -> std::optional<Scalar> {
+ const SomeKindScalar<TypeCategory::Integer> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::ConvertSigned(x)};
template<int KIND>
auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
- const ScalarConstant<TypeCategory::Real> &c) -> std::optional<Scalar> {
+ const SomeKindScalar<TypeCategory::Real> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{x.template ToInteger<Scalar>()};
auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
- using Ty = typename std::decay<decltype(x)>::type;
+ using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
template<int KIND>
auto RealExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
- const ScalarConstant<TypeCategory::Integer> &c) -> std::optional<Scalar> {
+ const SomeKindScalar<TypeCategory::Integer> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::FromInteger(x)};
template<int KIND>
auto RealExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
- const ScalarConstant<TypeCategory::Real> &c) -> std::optional<Scalar> {
+ const SomeKindScalar<TypeCategory::Real> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::Convert(x)};
template<int KIND>
auto RealExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
- const Scalar &a, const ScalarConstant<TypeCategory::Integer> &b)
+ const Scalar &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
template<int KIND>
auto RealExpr<KIND>::RealPart::FoldScalar(FoldingContext &context,
- const SameKindComplexScalar &z) -> std::optional<Scalar> {
+ const evaluate::Scalar<Complex> &z) -> std::optional<Scalar> {
return {z.REAL()};
}
template<int KIND>
auto RealExpr<KIND>::AIMAG::FoldScalar(FoldingContext &context,
- const SameKindComplexScalar &z) -> std::optional<Scalar> {
+ const evaluate::Scalar<Complex> &z) -> std::optional<Scalar> {
return {z.AIMAG()};
}
auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
- using Ty = typename std::decay<decltype(x)>::type;
+ using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
template<int KIND>
auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
- const Scalar &a, const ScalarConstant<TypeCategory::Integer> &b)
+ const Scalar &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
template<int KIND>
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
- const SameKindRealScalar &a, const SameKindRealScalar &b)
+ const evaluate::Scalar<Part> &a, const evaluate::Scalar<Part> &b)
-> std::optional<Scalar> {
return {Scalar{a, b}};
}
auto ComplexExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
- using Ty = typename std::decay<decltype(x)>::type;
+ using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
-> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
- using Ty = typename std::decay<decltype(x)>::type;
+ using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
- using Ty = typename std::decay<decltype(x)>::type;
+ using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
protected:
using OperandType = A;
using Operand = Expr<OperandType>;
- using OperandScalarConstant = typename OperandType::Value;
+ using OperandScalarConstant = Scalar<OperandType>;
public:
using Result = RESULT;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Unary)
Unary(const Operand &a) : operand_{a} {}
protected:
using LeftType = A;
using Left = Expr<LeftType>;
- using LeftScalar = typename LeftType::Value;
+ using LeftScalar = Scalar<LeftType>;
using RightType = B;
using Right = Expr<RightType>;
- using RightScalar = typename RightType::Value;
+ using RightScalar = Scalar<RightType>;
public:
using Result = RESULT;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Binary)
Binary(const Left &a, const Right &b) : left_{a}, right_{b} {}
template<int KIND> class Expr<Type<TypeCategory::Integer, KIND>> {
public:
using Result = Type<TypeCategory::Integer, KIND>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
struct ConvertInteger
: public Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const ScalarConstant<TypeCategory::Integer> &);
+ FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>> {
using Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const ScalarConstant<TypeCategory::Real> &);
+ FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
};
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<int KIND> class Expr<Type<TypeCategory::Real, KIND>> {
public:
using Result = Type<TypeCategory::Real, KIND>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
+ using Complex = typename Result::Complex;
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
// and part access operations (resp.). Conversions between kinds of
: public Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const ScalarConstant<TypeCategory::Integer> &);
+ FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>> {
using Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const ScalarConstant<TypeCategory::Real> &);
+ FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
};
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
using Binary<IntPower, Result, Result,
SomeKind<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
- const ScalarConstant<TypeCategory::Integer> &);
+ const SomeKindScalar<TypeCategory::Integer> &);
};
struct Max : public Bin<Max> {
using Bin<Max>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
- using SameKindComplex = Type<TypeCategory::Complex, KIND>;
- using SameKindComplexScalar = typename SameKindComplex::Value;
- template<typename CRTP>
- using SameKindComplexUn = Unary<CRTP, Result, SameKindComplex>;
- struct RealPart : public SameKindComplexUn<RealPart> {
- using SameKindComplexUn<RealPart>::SameKindComplexUn;
+ template<typename CRTP> using ComplexUn = Unary<CRTP, Result, Complex>;
+ struct RealPart : public ComplexUn<RealPart> {
+ using ComplexUn<RealPart>::ComplexUn;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const SameKindComplexScalar &);
+ FoldingContext &, const evaluate::Scalar<Complex> &);
};
- struct AIMAG : public SameKindComplexUn<AIMAG> {
- using SameKindComplexUn<AIMAG>::SameKindComplexUn;
+ struct AIMAG : public ComplexUn<AIMAG> {
+ using ComplexUn<AIMAG>::ComplexUn;
static std::optional<Scalar> FoldScalar(
- FoldingContext &, const SameKindComplexScalar &);
+ FoldingContext &, const evaluate::Scalar<Complex> &);
};
CLASS_BOILERPLATE(Expr)
template<int KIND> class Expr<Type<TypeCategory::Complex, KIND>> {
public:
using Result = Type<TypeCategory::Complex, KIND>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
+ using Part = typename Result::Part;
using FoldableTrait = std::true_type;
+
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Parentheses : public Un<Parentheses> {
using Binary<IntPower, Result, Result,
SomeKind<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
- const ScalarConstant<TypeCategory::Integer> &);
+ const SomeKindScalar<TypeCategory::Integer> &);
};
- using SameKindReal = Type<TypeCategory::Real, KIND>;
- using SameKindRealScalar = typename SameKindReal::Value;
- struct CMPLX : public Binary<CMPLX, Result, SameKindReal> {
- using Binary<CMPLX, Result, SameKindReal>::Binary;
+ struct CMPLX : public Binary<CMPLX, Result, Part> {
+ using Binary<CMPLX, Result, Part>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &,
- const SameKindRealScalar &, const SameKindRealScalar &);
+ const evaluate::Scalar<Part> &, const evaluate::Scalar<Part> &);
};
CLASS_BOILERPLATE(Expr)
template<int KIND> class Expr<Type<TypeCategory::Character, KIND>> {
public:
using Result = Type<TypeCategory::Character, KIND>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Concat : public Bin<Concat> {
// Dynamically polymorphic comparisons whose operands are expressions of
// the same supported kind of a particular type category.
template<TypeCategory CAT> struct CategoryComparison {
- using Scalar = typename Type<TypeCategory::Logical, 1>::Value;
+ using Scalar = Scalar<Type<TypeCategory::Logical, 1>>;
CLASS_BOILERPLATE(CategoryComparison)
template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>;
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> {
public:
using Result = Type<TypeCategory::Logical, KIND>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
struct Not : Unary<Not, Result> {
using Unary<Not, Result>::Unary;
template<TypeCategory CAT> class Expr<SomeKind<CAT>> {
public:
using Result = SomeKind<CAT>;
- using Scalar = typename Result::Value;
+ using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Expr)
template<int KIND> using KindExpr = Expr<Type<CAT, KIND>>;
static void ConvertToSameRealKind(SomeKindRealExpr &x, SomeKindRealExpr &y) {
std::visit(
[&](auto &xk, auto &yk) {
- using xt = typename std::decay<decltype(xk)>::type;
- using yt = typename std::decay<decltype(yk)>::type;
+ using xt = std::decay_t<decltype(xk)>;
+ using yt = std::decay_t<decltype(yk)>;
constexpr int kindDiff{xt::Result::kind - yt::Result::kind};
if constexpr (kindDiff < 0) {
x.u = yt{xk};
namespace Fortran::evaluate {
std::optional<std::int64_t> GenericScalar::ToInt64() const {
- if (const auto *j{std::get_if<ScalarConstant<TypeCategory::Integer>>(&u)}) {
+ if (const auto *j{std::get_if<SomeKindScalar<TypeCategory::Integer>>(&u)}) {
return std::visit(
[](const auto &k) { return std::optional<std::int64_t>{k.ToInt64()}; },
j->u);
}
std::optional<std::string> GenericScalar::ToString() const {
- if (const auto *c{std::get_if<ScalarConstant<TypeCategory::Character>>(&u)}) {
+ if (const auto *c{std::get_if<SomeKindScalar<TypeCategory::Character>>(&u)}) {
if (const std::string * s{std::get_if<std::string>(&c->u)}) {
return std::optional<std::string>{*s};
}
return std::nullopt;
}
-// There's some opaque type-fu going on below. Given a GenericScalar, we
-// figure out its intrinsic type category, and then (for each category),
-// we figure out its kind from the type of the constant. Then, given
-// the category, kind, and constant, we construct a GenericExpr around
-// the constant.
+// TODO pmk: maybe transplant these templates to type.h/expression.h?
+
+// There's some admittedly opaque type-fu going on below.
+// Given a GenericScalar value, we want to be able to (re-)wrap it as
+// a GenericExpr. So we extract its value, then build up an expression
+// around it. The subtle magic is in the first template, whose result
+// is a specific expression whose Fortran type category and kind are inferred
+// from the type of the scalar constant.
+template<typename A> Expr<ScalarValueType<A>> ScalarConstantToExpr(const A &x) {
+ return {x};
+}
+
+template<typename A>
+Expr<SomeKind<A::category>> ToSomeKindExpr(const Expr<A> &x) {
+ return {x};
+}
+
+template<TypeCategory CAT>
+Expr<SomeKind<CAT>> SomeKindScalarToExpr(const SomeKindScalar<CAT> &x) {
+ return std::visit(
+ [](const auto &c) { return ToSomeKindExpr(ScalarConstantToExpr(c)); },
+ x.u);
+}
+
GenericExpr GenericScalar::ToGenericExpr() const {
return std::visit(
- [](const auto &c) -> GenericExpr {
- using cType = typename std::decay<decltype(c)>::type;
- constexpr TypeCategory cat{cType::category};
- return {std::visit(
- [&](const auto &value) -> Expr<SomeKind<cat>> {
- using valueType = typename std::decay<decltype(value)>::type;
- using Ty = typename TypeOfScalarValue<valueType>::type;
- return {Expr<Ty>{value}};
- },
- c.u)};
- },
- u);
+ [&](const auto &c) { return GenericExpr{SomeKindScalarToExpr(c)}; }, u);
}
} // namespace Fortran::evaluate
template<TypeCategory C, int KIND> struct TypeBase {
static constexpr TypeCategory category{C};
+ static constexpr TypeCategory GetCategory() { return C; };
static constexpr int kind{KIND};
static constexpr bool hasLen{false};
static std::string Dump() {
}
};
+template<typename T> using Scalar = typename T::Scalar;
+
template<TypeCategory C, int KIND> struct Type;
template<int KIND>
struct Type<TypeCategory::Integer, KIND>
: public TypeBase<TypeCategory::Integer, KIND> {
- using Value = value::Integer<8 * KIND>;
+ using Scalar = value::Integer<8 * KIND>;
};
template<>
struct Type<TypeCategory::Real, 2> : public TypeBase<TypeCategory::Real, 2> {
- using Value = value::Real<typename Type<TypeCategory::Integer, 2>::Value, 11>;
+ using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 2>>, 11>;
using Complex = Type<TypeCategory::Complex, 2>;
};
template<>
struct Type<TypeCategory::Real, 4> : public TypeBase<TypeCategory::Real, 4> {
- using Value = value::Real<typename Type<TypeCategory::Integer, 4>::Value, 24>;
- using Complex = Type<TypeCategory::Complex, 2>;
+ using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 4>>, 24>;
+ using Complex = Type<TypeCategory::Complex, 4>;
};
template<>
struct Type<TypeCategory::Real, 8> : public TypeBase<TypeCategory::Real, 8> {
- using Value = value::Real<typename Type<TypeCategory::Integer, 8>::Value, 53>;
- using Complex = Type<TypeCategory::Complex, 2>;
+ using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 8>>, 53>;
+ using Complex = Type<TypeCategory::Complex, 8>;
};
template<>
struct Type<TypeCategory::Real, 10> : public TypeBase<TypeCategory::Real, 10> {
- using Value = value::Real<value::Integer<80>, 64, false>;
- using Complex = Type<TypeCategory::Complex, 2>;
+ using Scalar = value::Real<value::Integer<80>, 64, false>;
+ using Complex = Type<TypeCategory::Complex, 10>;
};
template<>
struct Type<TypeCategory::Real, 16> : public TypeBase<TypeCategory::Real, 16> {
- using Value =
- value::Real<typename Type<TypeCategory::Integer, 16>::Value, 112>;
- using Complex = Type<TypeCategory::Complex, 2>;
+ using Scalar = value::Real<value::Integer<128>, 112>;
+ using Complex = Type<TypeCategory::Complex, 16>;
};
// The KIND type parameter on COMPLEX is the kind of each of its components.
struct Type<TypeCategory::Complex, KIND>
: public TypeBase<TypeCategory::Complex, KIND> {
using Part = Type<TypeCategory::Real, KIND>;
- using Value = value::Complex<typename Part::Value>;
+ using Scalar = value::Complex<Scalar<Part>>;
};
template<int KIND> struct Type<TypeCategory::Character, KIND> {
static constexpr TypeCategory category{TypeCategory::Character};
static constexpr int kind{KIND};
static constexpr bool hasLen{true};
- using Value = std::string;
+ using Scalar = std::string;
static std::string Dump() {
return EnumToString(category) + '(' + std::to_string(kind) + ')';
}
template<int KIND>
struct Type<TypeCategory::Logical, KIND>
: public TypeBase<TypeCategory::Logical, KIND> {
- using Value = value::Logical<8 * KIND>;
+ using Scalar = value::Logical<8 * KIND>;
};
// Convenience type aliases:
#define FOR_EACH_CATEGORY(M) \
M(Integer, INTEGER) \
- M(Real, REAL) M(Complex, COMPLEX) M(Character, CHARACTER) \
- M(Logical, LOGICAL)
+ M(Real, REAL) M(Complex, COMPLEX) M(Character, CHARACTER) M(Logical, LOGICAL)
// These macros and template create instances of std::variant<> that can contain
// applications of some class template to all of the supported kinds of
#undef MAKE
#undef TKIND
-// Map scalar constant value types back to their Fortran types.
-// For every type T = Type<CAT, KIND>, TypeOfScalarValue<T::Value>::type == T.
+// Map scalar value types back to their Fortran types.
+// For every type T = Type<CAT, KIND>, TypeOfScalarValue<T>> == T.
// E.g., TypeOfScalarValue<Integer<32>> is Type<TypeCategory::Integer, 4>.
-template<typename CONST> struct TypeOfScalarValue;
+template<typename CONST> struct GetTypeOfScalarValue;
#define TOSV(cat, kind) \
template<> \
- struct TypeOfScalarValue<typename Type<TypeCategory::cat, kind>::Value> { \
+ struct GetTypeOfScalarValue<Scalar<Type<TypeCategory::cat, kind>>> { \
using type = Type<TypeCategory::cat, kind>; \
};
#define M(k) TOSV(Integer, k)
#undef M
#undef TOSV
-// Holds a scalar constant of any kind within a particular intrinsic type
+template<typename CONST>
+using ScalarValueType = typename GetTypeOfScalarValue<CONST>::type;
+
+// Holds a scalar value of any kind within a particular intrinsic type
// category.
-template<TypeCategory CAT> struct ScalarConstant {
+template<TypeCategory CAT> struct SomeKindScalar {
static constexpr TypeCategory category{CAT};
- CLASS_BOILERPLATE(ScalarConstant)
+ CLASS_BOILERPLATE(SomeKindScalar)
- template<int KIND> using KindScalar = typename Type<CAT, KIND>::Value;
- template<typename A> ScalarConstant(const A &x) : u{x} {}
+ template<int KIND> using KindScalar = Scalar<Type<CAT, KIND>>;
+ template<typename A> SomeKindScalar(const A &x) : u{x} {}
template<typename A>
- ScalarConstant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
+ SomeKindScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
typename KindsVariant<CAT, KindScalar>::type u;
CLASS_BOILERPLATE(GenericScalar)
template<TypeCategory CAT, int KIND>
- GenericScalar(const typename Type<CAT, KIND>::Value &x)
- : u{ScalarConstant<CAT>{x}} {}
+ GenericScalar(const Scalar<Type<CAT, KIND>> &x) : u{SomeKindScalar<CAT>{x}} {}
template<TypeCategory CAT, int KIND>
- GenericScalar(typename Type<CAT, KIND>::Value &&x)
- : u{ScalarConstant<CAT>{std::move(x)}} {}
+ GenericScalar(Scalar<Type<CAT, KIND>> &&x)
+ : u{SomeKindScalar<CAT>{std::move(x)}} {}
template<typename A> GenericScalar(const A &x) : u{x} {}
template<typename A>
std::optional<std::string> ToString() const;
GenericExpr ToGenericExpr() const;
- std::variant<ScalarConstant<TypeCategory::Integer>,
- ScalarConstant<TypeCategory::Real>, ScalarConstant<TypeCategory::Complex>,
- ScalarConstant<TypeCategory::Character>,
- ScalarConstant<TypeCategory::Logical>>
+ std::variant<SomeKindScalar<TypeCategory::Integer>,
+ SomeKindScalar<TypeCategory::Real>, SomeKindScalar<TypeCategory::Complex>,
+ SomeKindScalar<TypeCategory::Character>,
+ SomeKindScalar<TypeCategory::Logical>>
u;
};
// Represents a type of any supported kind within a particular category.
template<TypeCategory CAT> struct SomeKind {
static constexpr TypeCategory category{CAT};
- using Value = ScalarConstant<CAT>;
+ using Scalar = SomeKindScalar<CAT>;
};
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_TYPE_H_
state = backtrack;
const auto &parser{std::get<J>(ps_)};
static_assert(std::is_same_v<resultType,
- typename std::decay<decltype(parser)>::type::resultType>);
+ typename std::decay_t<decltype(parser)>::resultType>);
result = parser.Parse(state);
if (!result.has_value()) {
state.CombineFailedParses(std::move(prevState));
if (sign == parser::Sign::Negative) {
std::visit(
[](auto &rk) {
- using t = typename std::decay<decltype(rk)>::type;
+ using t = std::decay_t<decltype(rk)>;
rk = typename t::Negate{rk};
},
result->u);
if (auto joined{common::JoinOptionals(std::move(converted))}) {
return {std::visit(
[](auto &&rx, auto &&ix) -> evaluate::SomeKindComplexExpr {
- using realExpr = typename std::decay<decltype(rx)>::type;
- using zExpr = evaluate::Expr<typename realExpr::SameKindComplex>;
+ using realExpr = std::decay_t<decltype(rx)>;
+ using zExpr = evaluate::Expr<typename realExpr::Complex>;
return {zExpr{typename zExpr::CMPLX{std::move(rx), std::move(ix)}}};
},
std::move(joined->first.u), std::move(joined->second.u))};
TEST(Type::category == Fortran::common::TypeCategory::Logical);
TEST(Type::kind == KIND);
TEST(!Type::hasLen);
- using Value = typename Type::Value;
+ using Value = Fortran::evaluate::Scalar<Type>;
MATCH(8 * KIND, Value::bits);
TEST(!Value{}.IsTrue());
TEST(!Value{false}.IsTrue());
using namespace Fortran::evaluate;
using namespace Fortran::common;
-using Real2 = typename Type<TypeCategory::Real, 2>::Value;
-using Real4 = typename Type<TypeCategory::Real, 4>::Value;
-using Real8 = typename Type<TypeCategory::Real, 8>::Value;
-using Real10 = typename Type<TypeCategory::Real, 10>::Value;
-using Real16 = typename Type<TypeCategory::Real, 16>::Value;
-using Integer4 = typename Type<TypeCategory::Integer, 4>::Value;
-using Integer8 = typename Type<TypeCategory::Integer, 8>::Value;
+using Real2 = Scalar<Type<TypeCategory::Real, 2>>;
+using Real4 = Scalar<Type<TypeCategory::Real, 4>>;
+using Real8 = Scalar<Type<TypeCategory::Real, 8>>;
+using Real10 = Scalar<Type<TypeCategory::Real, 10>>;
+using Real16 = Scalar<Type<TypeCategory::Real, 16>>;
+using Integer4 = Scalar<Type<TypeCategory::Integer, 4>>;
+using Integer8 = Scalar<Type<TypeCategory::Integer, 8>>;
void dumpTest() {
struct {