[flang] remove arg->intValue field

Original-commit: flang-compiler/f18@721dc92022
Reviewed-on: https://github.com/flang-compiler/f18/pull/212
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-10-09 12:07:29 -07:00
parent a62636f634
commit f7f2a73a43
11 changed files with 223 additions and 59 deletions

View File

@ -19,6 +19,7 @@
// once here to avoid redundancy and needless translation.
#include "idioms.h"
#include <cinttypes>
namespace Fortran::common {

View File

@ -35,8 +35,7 @@ struct ActualArgument {
std::optional<parser::CharBlock> keyword;
bool isAssumedRank{false};
bool isAlternateReturn{false};
std::optional<int> vectorSize; // TODO: pmk replace with function on value
std::optional<int> intValue; // TODO: pmk replace with function on value
std::optional<int> vectorSize; // TODO
CopyableIndirection<Expr<SomeType>> value;
};

View File

@ -56,7 +56,7 @@ template<typename RESULT>
auto ExpressionBase<RESULT>::Fold(FoldingContext &context)
-> std::optional<Constant<Result>> {
using Const = Constant<Result>;
if constexpr (Result::isSpecificType) {
if constexpr (Result::isSpecificIntrinsicType) {
// Folding an expression of known type category and kind.
return std::visit(
[&](auto &x) -> std::optional<Const> {
@ -97,7 +97,7 @@ auto ExpressionBase<RESULT>::Fold(FoldingContext &context)
[&](auto &x) -> std::optional<Const> {
if constexpr (IsFoldableTrait<std::decay_t<decltype(x)>>) {
if (auto c{x.Fold(context)}) {
if constexpr (ResultType<decltype(*c)>::isSpecificType) {
if constexpr (ResultType<decltype(*c)>::isSpecificIntrinsicType) {
return {Const{c->value}};
} else {
return {Const{common::MoveVariant<GenericScalar>(c->value.u)}};
@ -500,7 +500,7 @@ Expr<SubscriptInteger> Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
template<typename RESULT>
auto ExpressionBase<RESULT>::ScalarValue() const
-> std::optional<Scalar<Result>> {
if constexpr (Result::isSpecificType) {
if constexpr (Result::isSpecificIntrinsicType) {
if (auto *c{std::get_if<Constant<Result>>(&derived().u)}) {
return {c->value};
}
@ -541,12 +541,8 @@ Expr<SomeType>::~Expr() {}
template<typename A>
std::optional<DynamicType> ExpressionBase<A>::GetType() const {
if constexpr (Result::isSpecificType) {
if constexpr (Result::category == TypeCategory::Derived) {
return std::visit([](const auto &x) { return x.GetType(); }, derived().u);
} else {
return Result::GetType();
}
if constexpr (Result::isSpecificIntrinsicType) {
return Result::GetType();
} else {
return std::visit(
[](const auto &x) -> std::optional<DynamicType> {

View File

@ -79,7 +79,7 @@ template<typename T> struct Constant {
Constant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: value(std::move(x)) {}
constexpr std::optional<DynamicType> GetType() const {
if constexpr (Result::isSpecificType) {
if constexpr (Result::isSpecificIntrinsicType) {
return Result::GetType();
} else {
return value.GetType();
@ -115,8 +115,7 @@ class Operation {
public:
using Derived = DERIVED;
using Result = RESULT;
static_assert(Result::isSpecificType);
static_assert(Result::category != TypeCategory::Derived);
static_assert(Result::isSpecificIntrinsicType);
static constexpr std::size_t operands{sizeof...(OPERANDS)};
template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
using IsFoldableTrait = std::true_type;

View File

@ -76,6 +76,7 @@ enum class KindCode {
effectiveKind, // for function results: same "kindArg", possibly defaulted
dimArg, // this argument is DIM=
same, // match any kind; all "same" kinds must be equal
likeMultiply, // for DOT_PRODUCT and MATMUL
};
struct TypePattern {
@ -104,6 +105,7 @@ static constexpr TypePattern AnyNumeric{Numeric, KindCode::any};
static constexpr TypePattern AnyChar{Char, KindCode::any};
static constexpr TypePattern AnyLogical{Logical, KindCode::any};
static constexpr TypePattern AnyRelatable{Relatable, KindCode::any};
static constexpr TypePattern Anything{AnyType, KindCode::any};
// Match some kind of some intrinsic type(s); all "Same" values must match,
// even when not in the same category (e.g., SameComplex and SameReal).
@ -123,6 +125,10 @@ static constexpr TypePattern SameDerivedType{
CategorySet{TypeCategory::Derived}, KindCode::same};
static constexpr TypePattern SameType{AnyType, KindCode::same};
// For DOT_PRODUCT and MATMUL, the result type depends on the arguments
static constexpr TypePattern ResultLogical{Logical, KindCode::likeMultiply};
static constexpr TypePattern ResultNumeric{Numeric, KindCode::likeMultiply};
// Result types with known category and KIND=
static constexpr TypePattern KINDInt{Int, KindCode::effectiveKind};
static constexpr TypePattern KINDReal{Real, KindCode::effectiveKind};
@ -214,9 +220,17 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"bessel_j0", {{"x", SameReal}}, SameReal},
{"bessel_j1", {{"x", SameReal}}, SameReal},
{"bessel_jn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
{"bessel_jn",
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
{"x", SameReal, Rank::scalar}},
SameReal, Rank::vector},
{"bessel_y0", {{"x", SameReal}}, SameReal},
{"bessel_y1", {{"x", SameReal}}, SameReal},
{"bessel_yn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
{"bessel_yn",
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
{"x", SameReal, Rank::scalar}},
SameReal, Rank::vector},
{"bge",
{{"i", AnyInt, Rank::elementalOrBOZ},
{"j", AnyInt, Rank::elementalOrBOZ}},
@ -241,6 +255,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{{"x", SameIntOrReal, Rank::elementalOrBOZ},
{"y", SameIntOrReal, Rank::elementalOrBOZ}, DefaultingKIND},
KINDComplex},
{"command_argument_count", {}, DftInt, Rank::scalar},
{"conjg", {{"z", SameComplex}}, SameComplex},
{"cos", {{"x", SameFloating}}, SameFloating},
{"cosh", {{"x", SameFloating}}, SameFloating},
@ -251,6 +266,18 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
OptionalDIM},
SameType, Rank::array},
{"dim", {{"x", SameIntOrReal}, {"y", SameIntOrReal}}, SameIntOrReal},
{"dot_product",
{{"vector_a", AnyLogical, Rank::vector},
{"vector_b", AnyLogical, Rank::vector}},
ResultLogical, Rank::scalar},
{"dot_product",
{{"vector_a", AnyComplex, Rank::vector},
{"vector_b", AnyNumeric, Rank::vector}},
ResultNumeric, Rank::scalar}, // conjugates vector_a
{"dot_product",
{{"vector_a", AnyIntOrReal, Rank::vector},
{"vector_b", AnyNumeric, Rank::vector}},
ResultNumeric, Rank::scalar},
{"dprod", {{"x", DftReal}, {"y", DftReal}}, DoublePrecision},
{"dshiftl",
{{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
@ -334,6 +361,12 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
SameInt},
{"is_iostat_end", {{"i", AnyInt}}, DftLogical},
{"is_iostat_eor", {{"i", AnyInt}}, DftLogical},
{"lbound", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
KINDInt, Rank::vector},
{"lbound",
{{"array", Anything, Rank::anyOrAssumedRank},
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
KINDInt, Rank::scalar},
{"leadz", {{"i", AnyInt}}, DftInt},
{"len", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
{"len_trim", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
@ -345,6 +378,30 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"log10", {{"x", SameReal}}, SameReal},
{"logical", {{"l", AnyLogical}, DefaultingKIND}, KINDLogical},
{"log_gamma", {{"x", SameReal}}, SameReal},
{"matmul",
{{"array_a", AnyLogical, Rank::vector},
{"array_b", AnyLogical, Rank::matrix}},
ResultLogical, Rank::vector},
{"matmul",
{{"array_a", AnyLogical, Rank::matrix},
{"array_b", AnyLogical, Rank::vector}},
ResultLogical, Rank::vector},
{"matmul",
{{"array_a", AnyLogical, Rank::matrix},
{"array_b", AnyLogical, Rank::matrix}},
ResultLogical, Rank::matrix},
{"matmul",
{{"array_a", AnyNumeric, Rank::vector},
{"array_b", AnyNumeric, Rank::matrix}},
ResultNumeric, Rank::vector},
{"matmul",
{{"array_a", AnyNumeric, Rank::matrix},
{"array_b", AnyNumeric, Rank::vector}},
ResultNumeric, Rank::vector},
{"matmul",
{{"array_a", AnyNumeric, Rank::matrix},
{"array_b", AnyNumeric, Rank::matrix}},
ResultNumeric, Rank::matrix},
{"maskl", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
{"maskr", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
{"maxloc",
@ -377,6 +434,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"norm2", {{"x", SameReal, Rank::array}, OptionalDIM}, SameReal,
Rank::dimReduced},
{"not", {{"i", SameInt}}, SameInt},
// pmk WIP continue here in transformationals with NULL
{"out_of_range",
{{"x", SameIntOrReal}, {"mold", AnyIntOrReal, Rank::scalar}},
DftLogical},
@ -418,6 +476,12 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"sign", {{"a", SameIntOrReal}, {"b", SameIntOrReal}}, SameIntOrReal},
{"sin", {{"x", SameFloating}}, SameFloating},
{"sinh", {{"x", SameFloating}}, SameFloating},
{"size", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
KINDInt, Rank::vector},
{"size",
{{"array", Anything, Rank::anyOrAssumedRank},
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
KINDInt, Rank::scalar},
{"spacing", {{"x", SameReal}}, SameReal},
{"spread",
{{"source", SameType, Rank::known},
@ -430,7 +494,28 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"tan", {{"x", SameFloating}}, SameFloating},
{"tanh", {{"x", SameFloating}}, SameFloating},
{"trailz", {{"i", AnyInt}}, DftInt},
// TODO: pmk: continue here with TRANSFER
{"transfer",
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::scalar}},
SameType, Rank::scalar},
{"transfer",
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::array}},
SameType, Rank::vector},
{"transfer",
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::known},
{"size", AnyInt, Rank::scalar}},
SameType, Rank::vector},
{"transpose", {{"matrix", SameType, Rank::matrix}}, SameType, Rank::matrix},
{"trim", {{"string", AnyChar, Rank::scalar}}, SameChar, Rank::scalar},
{"ubound", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
KINDInt, Rank::vector},
{"ubound",
{{"array", Anything, Rank::anyOrAssumedRank},
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
KINDInt, Rank::scalar},
{"unpack",
{{"vector", SameType, Rank::vector}, {"mask", AnyLogical, Rank::array},
{"field", SameType, Rank::conformable}},
SameType, Rank::conformable},
{"verify",
{{"string", SameChar}, {"set", SameChar},
{"back", AnyLogical, Rank::elemental, Optionality::optional},
@ -629,11 +714,13 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
break;
case KindCode::any: argOk = true; break;
case KindCode::kindArg:
CHECK(type->category == TypeCategory::Integer);
CHECK(kindArg == nullptr);
kindArg = arg;
argOk = arg->intValue.has_value();
argOk = true;
break;
case KindCode::dimArg:
CHECK(type->category == TypeCategory::Integer);
hasDimArg = true;
argOk = true;
break;
@ -732,7 +819,6 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
}
}
// At this point, the call is acceptable.
// Calculate the characteristics of the function result, if any
if (result.categorySet.empty()) {
CHECK(result.kindCode == KindCode::none);
@ -775,9 +861,21 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
CHECK(kindDummyArg != nullptr);
CHECK(result.categorySet == CategorySet{resultType.category});
if (kindArg != nullptr) {
CHECK(kindArg->intValue.has_value());
resultType.kind = *kindArg->intValue;
// TODO pmk: validate this kind!!
if (auto *jExpr{std::get_if<Expr<SomeInteger>>(&kindArg->value->u)}) {
CHECK(jExpr->Rank() == 0);
if (auto value{jExpr->ScalarValue()}) {
if (auto code{value->ToInt64()}) {
if (IsValidKindOfIntrinsicType(resultType.category, *code)) {
resultType.kind = *code;
break;
}
}
}
}
messages.Say("'kind' argument must be a constant scalar integer "
"whose value is a supported kind for the "
"intrinsic result type"_err_en_US);
return std::nullopt;
} else if (kindDummyArg->optionality == Optionality::defaultsToSameKind) {
CHECK(sameArg != nullptr);
resultType = *sameArg->GetType();
@ -787,6 +885,13 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
resultType.kind = defaults.DefaultKind(resultType.category);
}
break;
case KindCode::likeMultiply:
CHECK(dummies >= 2);
CHECK(actualForDummy[0] != nullptr);
CHECK(actualForDummy[1] != nullptr);
resultType = actualForDummy[0]->GetType()->ResultTypeForMultiply(
*actualForDummy[1]->GetType());
break;
case KindCode::typeless:
case KindCode::teamType:
case KindCode::any:
@ -798,6 +903,7 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
default: CRASH_NO_CASE;
}
// At this point, the call is acceptable.
// Determine the rank of the function result.
int resultRank{0};
switch (rank) {
@ -805,6 +911,10 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
case Rank::scalar: resultRank = 0; break;
case Rank::vector: resultRank = 1; break;
case Rank::matrix: resultRank = 2; break;
case Rank::conformable:
CHECK(arrayArg != nullptr);
resultRank = arrayArg->Rank();
break;
case Rank::dimReduced:
CHECK(arrayArg != nullptr);
resultRank = hasDimArg ? arrayArg->Rank() - 1 : 0;
@ -823,7 +933,6 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
case Rank::array:
case Rank::known:
case Rank::anyOrAssumedRank:
case Rank::conformable:
case Rank::dimRemoved:
common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name);
break;

View File

@ -368,7 +368,7 @@ Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&x) {
template<typename T>
Expr<LogicalResult> PackageRelation(
RelationalOperator opr, Expr<T> &&x, Expr<T> &&y) {
static_assert(T::isSpecificType);
static_assert(T::isSpecificIntrinsicType);
return Expr<LogicalResult>{
Relational<SomeType>{Relational<T>{opr, std::move(x), std::move(y)}}};
}

View File

@ -96,7 +96,7 @@ Expr<SomeComplex> MakeComplex(Expr<Type<TypeCategory::Real, KIND>> &&re,
template<typename TO, TypeCategory FROMCAT>
Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
static_assert(TO::isSpecificType);
static_assert(TO::isSpecificIntrinsicType);
if constexpr (FROMCAT != TO::category) {
if constexpr (TO::category == TypeCategory::Complex) {
using Part = typename TO::Part;
@ -134,7 +134,7 @@ Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
}
template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
static_assert(TO::isSpecificType);
static_assert(TO::isSpecificIntrinsicType);
using Value = typename Constant<TO>::Value;
if constexpr (TO::category == TypeCategory::Integer) {
return Expr<TO>{Constant<TO>{Value::ConvertUnsigned(std::move(x)).value}};
@ -290,7 +290,7 @@ template<typename A> Expr<TypeOf<A>> ScalarConstantToExpr(const A &x) {
// for COMPLEX.
template<template<typename> class OPR, typename SPECIFIC>
Expr<SPECIFIC> Combine(Expr<SPECIFIC> &&x, Expr<SPECIFIC> &&y) {
static_assert(SPECIFIC::isSpecificType);
static_assert(SPECIFIC::isSpecificIntrinsicType);
if constexpr (SPECIFIC::category == TypeCategory::Complex &&
(std::is_same_v<OPR<DefaultReal>, Add<DefaultReal>> ||
std::is_same_v<OPR<DefaultReal>, Subtract<DefaultReal>>)) {

View File

@ -13,8 +13,10 @@
// limitations under the License.
#include "type.h"
#include "../common/idioms.h"
#include "../semantics/symbol.h"
#include "../semantics/type.h"
#include <algorithm>
#include <optional>
#include <string>
@ -26,10 +28,13 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &symbol) {
if (auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
if (details->type().has_value()) {
switch (details->type()->category()) {
case semantics::DeclTypeSpec::Category::Intrinsic:
return std::make_optional(
DynamicType{details->type()->intrinsicTypeSpec().category(),
details->type()->intrinsicTypeSpec().kind()});
case semantics::DeclTypeSpec::Category::Intrinsic: {
TypeCategory category{details->type()->intrinsicTypeSpec().category()};
int kind{details->type()->intrinsicTypeSpec().kind()};
if (IsValidKindOfIntrinsicType(category, kind)) {
return std::make_optional(DynamicType{category, kind});
}
} break;
case semantics::DeclTypeSpec::Category::TypeDerived:
case semantics::DeclTypeSpec::Category::ClassDerived:
return std::make_optional(DynamicType{
@ -41,6 +46,48 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &symbol) {
return std::nullopt;
}
DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const {
switch (category) {
case TypeCategory::Integer:
switch (that.category) {
case TypeCategory::Integer:
return DynamicType{TypeCategory::Integer, std::max(kind, that.kind)};
case TypeCategory::Real:
case TypeCategory::Complex: return that;
default: CRASH_NO_CASE;
}
break;
case TypeCategory::Real:
switch (that.category) {
case TypeCategory::Integer: return *this;
case TypeCategory::Real:
return DynamicType{TypeCategory::Real, std::max(kind, that.kind)};
case TypeCategory::Complex:
return DynamicType{TypeCategory::Complex, std::max(kind, that.kind)};
default: CRASH_NO_CASE;
}
break;
case TypeCategory::Complex:
switch (that.category) {
case TypeCategory::Integer: return *this;
case TypeCategory::Real:
case TypeCategory::Complex:
return DynamicType{TypeCategory::Complex, std::max(kind, that.kind)};
default: CRASH_NO_CASE;
}
break;
case TypeCategory::Logical:
switch (that.category) {
case TypeCategory::Logical:
return DynamicType{TypeCategory::Logical, std::max(kind, that.kind)};
default: CRASH_NO_CASE;
}
break;
default: CRASH_NO_CASE;
}
return *this;
}
int IntrinsicTypeDefaultKinds::DefaultKind(TypeCategory category) const {
switch (category) {
case TypeCategory::Integer: return defaultIntegerKind;

View File

@ -53,6 +53,8 @@ struct DynamicType {
return EnumToString(category) + '(' + std::to_string(kind) + ')';
}
DynamicType ResultTypeForMultiply(const DynamicType &) const;
TypeCategory category;
int kind{0};
const semantics::DerivedTypeSpec *derived{nullptr};
@ -65,7 +67,9 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &);
template<TypeCategory CATEGORY, int KIND = 0> class Type;
template<TypeCategory CATEGORY, int KIND> struct TypeBase {
static constexpr bool isSpecificType{true};
// Only types that represent a known kind of one of the five intrinsic
// data types will have set this flag to true.
static constexpr bool isSpecificIntrinsicType{true};
static constexpr DynamicType dynamicType{CATEGORY, KIND};
static constexpr std::optional<DynamicType> GetType() {
return {dynamicType};
@ -190,33 +194,39 @@ using SubscriptInteger = Type<TypeCategory::Integer, 8>;
using LogicalResult = Type<TypeCategory::Logical, 1>;
using LargestReal = Type<TypeCategory::Real, 16>;
// A predicate that is true when a kind value is a kind that could possibly
// be supported for an intrinsic type category on some target instruction
// set architecture.
static constexpr bool IsValidKindOfIntrinsicType(
TypeCategory category, std::int64_t kind) {
switch (category) {
case TypeCategory::Integer:
return kind == 1 || kind == 2 || kind == 4 || kind == 8 || kind == 16;
case TypeCategory::Real:
case TypeCategory::Complex:
return kind == 2 || kind == 4 || kind == 8 || kind == 10 || kind == 16;
case TypeCategory::Character:
return kind == 1; // TODO: || kind == 2 || kind == 4;
case TypeCategory::Logical:
return kind == 1 || kind == 2 || kind == 4 || kind == 8;
default: return false;
}
}
// For each intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
// of std::tuple<Type<CAT, K>> that comprises every kind value K in that
// category that could possibly be supported on any target.
template<TypeCategory CATEGORY, int... KINDS>
using CategoryTypesTuple = std::tuple<Type<CATEGORY, KINDS>...>;
template<TypeCategory CATEGORY, int KIND>
using CategoryKindTuple =
std::conditional_t<IsValidKindOfIntrinsicType(CATEGORY, KIND),
std::tuple<Type<CATEGORY, KIND>>, std::tuple<>>;
template<TypeCategory CATEGORY, int... KINDS>
using CategoryTypesHelper =
common::CombineTuples<CategoryKindTuple<CATEGORY, KINDS>...>;
template<TypeCategory CATEGORY> struct CategoryTypesHelper;
template<> struct CategoryTypesHelper<TypeCategory::Integer> {
using type = CategoryTypesTuple<TypeCategory::Integer, 1, 2, 4, 8, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Real> {
using type = CategoryTypesTuple<TypeCategory::Real, 2, 4, 8, 10, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Complex> {
using type = CategoryTypesTuple<TypeCategory::Complex, 2, 4, 8, 10, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Character> {
using type = CategoryTypesTuple<TypeCategory::Character, 1>; // TODO: 2 & 4
};
template<> struct CategoryTypesHelper<TypeCategory::Logical> {
using type = CategoryTypesTuple<TypeCategory::Logical, 1, 2, 4, 8>;
};
template<> struct CategoryTypesHelper<TypeCategory::Derived> {
using type = std::tuple<>;
};
template<TypeCategory CATEGORY>
using CategoryTypes = typename CategoryTypesHelper<CATEGORY>::type;
using CategoryTypes = CategoryTypesHelper<CATEGORY, 1, 2, 4, 8, 10, 16, 32>;
using IntegerTypes = CategoryTypes<TypeCategory::Integer>;
using RealTypes = CategoryTypes<TypeCategory::Real>;
@ -312,14 +322,14 @@ using GenericScalar = SomeScalar<AllIntrinsicTypes>;
// Represents a type of any supported kind within a particular category.
template<TypeCategory CATEGORY> struct SomeKind {
static constexpr bool isSpecificType{false};
static constexpr bool isSpecificIntrinsicType{false};
static constexpr TypeCategory category{CATEGORY};
using Scalar = SomeKindScalar<category>;
};
template<> class SomeKind<TypeCategory::Derived> {
public:
static constexpr bool isSpecificType{true};
static constexpr bool isSpecificIntrinsicType{true};
static constexpr TypeCategory category{TypeCategory::Derived};
using Scalar = void;
@ -347,7 +357,7 @@ using SomeDerived = SomeKind<TypeCategory::Derived>;
using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex,
SomeCharacter, SomeLogical, SomeDerived>;
struct SomeType {
static constexpr bool isSpecificType{false};
static constexpr bool isSpecificIntrinsicType{false};
using Scalar = GenericScalar;
};

View File

@ -234,7 +234,8 @@ template<typename A> class Designator {
public:
using Result = A;
static_assert(Result::isSpecificType);
static_assert(Result::isSpecificIntrinsicType ||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
EVALUATE_UNION_CLASS_BOILERPLATE(Designator)
Designator(const DataRef &that) : u{common::MoveVariant<Variant>(that.u)} {}
Designator(DataRef &&that)
@ -315,7 +316,8 @@ protected:
template<typename A> struct FunctionRef : public UntypedFunctionRef {
using Result = A;
static_assert(Result::isSpecificType);
static_assert(Result::isSpecificIntrinsicType ||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
// Subtlety: There is a distinction that must be maintained here between an
// actual argument expression that *is* a variable and one that is not,
// e.g. between X and (X). The parser attempts to parse each argument
@ -339,7 +341,8 @@ template<typename A> struct FunctionRef : public UntypedFunctionRef {
template<typename A> struct Variable {
using Result = A;
static_assert(Result::isSpecificType);
static_assert(Result::isSpecificIntrinsicType ||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
EVALUATE_UNION_CLASS_BOILERPLATE(Variable)
std::optional<DynamicType> GetType() const {
return std::visit([](const auto &x) { return x.GetType(); }, u);

View File

@ -19,7 +19,7 @@
template<int KIND> void testKind() {
using Type =
Fortran::evaluate::Type<Fortran::common::TypeCategory::Logical, KIND>;
TEST(Type::isSpecificType);
TEST(Type::isSpecificIntrinsicType);
TEST(Type::category == Fortran::common::TypeCategory::Logical);
TEST(Type::kind == KIND);
using Value = Fortran::evaluate::Scalar<Type>;