9#ifndef FORTRAN_EVALUATE_TYPE_H_
10#define FORTRAN_EVALUATE_TYPE_H_
19#include "character-value.h"
21#include "complex-value.h"
22#include "formatting.h"
23#include "integer-value.h"
24#include "logical-value.h"
25#include "real-value.h"
26#include "flang/Common/idioms.h"
27#include "flang/Common/real.h"
28#include "flang/Common/template.h"
29#include "flang/Common/type-kinds.h"
30#include "flang/Support/Fortran-features.h"
31#include "flang/Support/Fortran.h"
37namespace Fortran::semantics {
46bool IsDescriptor(
const Symbol &);
47bool IsPassedViaDescriptor(
const Symbol &);
52using common::TypeCategory;
61template <TypeCategory CATEGORY>
class Type;
66inline constexpr int SubscriptIntegerKind{8};
71inline constexpr int CIntegerKind{4};
75using LargestInt = Type<TypeCategory::Integer>;
76inline constexpr int LargestIntKind{16};
80using LogicalResult = Type<TypeCategory::Logical>;
81inline constexpr int LogicalResultKind{4};
86inline constexpr int LargestRealKind{16};
91inline constexpr int AsciiKind{1};
103 constexpr DynamicType(TypeCategory cat,
int k) : category_{cat}, kind_{k} {
104 CHECK(common::IsValidKindOfIntrinsicType(category_, kind_));
109 constexpr DynamicType(
int k, std::int64_t len)
110 : category_{TypeCategory::Character}, kind_{k}, knownLength_{
111 len >= 0 ? len : 0} {
112 CHECK(common::IsValidKindOfIntrinsicType(category_, kind_));
114 explicit constexpr DynamicType(
116 : category_{TypeCategory::Derived}, derived_{&dt} {
121 CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(DynamicType)
127 static constexpr DynamicType TypelessIntrinsicArgument() {
129 result.category_ = TypeCategory::Integer;
130 result.kind_ = TypelessKind;
134 static constexpr DynamicType UnlimitedPolymorphic() {
136 result.category_ = TypeCategory::Derived;
137 result.kind_ = ClassKind;
138 result.derived_ =
nullptr;
142 static constexpr DynamicType AssumedType() {
144 result.category_ = TypeCategory::Derived;
145 result.kind_ = AssumedTypeKind;
146 result.derived_ =
nullptr;
151 bool operator==(
const DynamicType &)
const;
152 bool operator!=(
const DynamicType &that)
const {
return !(*
this == that); }
154 constexpr TypeCategory category()
const {
return category_; }
155 constexpr int kind()
const {
160 return charLengthParamValue_;
162 constexpr std::optional<std::int64_t> knownLength()
const {
163#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 7
164 if (knownLength_ < 0) {
170 std::optional<Expr<SubscriptInteger>> GetCharLength()
const;
173 std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
FoldingContext &,
175 std::optional<std::int64_t> charLength = std::nullopt)
const;
177 std::string AsFortran()
const;
178 std::string AsFortran(std::string &&charLenExpr)
const;
179 DynamicType ResultTypeForMultiply(
const DynamicType &)
const;
181 bool IsAssumedLengthCharacter()
const;
182 bool IsNonConstantLengthCharacter()
const;
183 bool IsTypelessIntrinsicArgument()
const;
184 constexpr bool IsAssumedType()
const {
185 return kind_ == AssumedTypeKind;
187 constexpr bool IsPolymorphic()
const {
188 return kind_ == ClassKind || IsAssumedType();
190 constexpr bool IsUnlimitedPolymorphic()
const {
191 return IsPolymorphic() && !derived_;
193 bool IsLengthlessIntrinsicType()
const;
195 return DEREF(derived_);
198 bool RequiresDescriptor()
const;
199 bool HasDeferredTypeParameter()
const;
200 bool HasDeferredOrAssumedTypeParameter()
const;
207 bool IsTkCompatibleWith(
const DynamicType &)
const;
208 bool IsTkCompatibleWith(
const DynamicType &, common::IgnoreTKRSet)
const;
212 bool IsTkLenCompatibleWith(
const DynamicType &)
const;
215 std::optional<bool> ExtendsTypeOf(
const DynamicType &)
const;
217 std::optional<bool> SameTypeAs(
const DynamicType &)
const;
221 bool IsEquivalentTo(
const DynamicType &)
const;
228 template <
typename A>
static std::optional<DynamicType> From(
const A &x) {
231 template <
typename A>
static std::optional<DynamicType> From(
const A *p) {
238 template <
typename A>
239 static std::optional<DynamicType> From(
const std::optional<A> &x) {
251 DynamicType DropNonConstantCharacterLength()
const;
259 AssumedTypeKind = -3,
262 constexpr DynamicType() {}
264 TypeCategory category_{TypeCategory::Derived};
267#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 7
269 std::int64_t knownLength_{-1};
271 std::optional<std::int64_t> knownLength_;
279 const std::optional<DynamicType> &);
284 const std::optional<DynamicType> &);
288template <TypeCategory CATEGORY>
struct TypeBase {
289 constexpr int kind()
const {
return kind_; }
291 static constexpr TypeCategory category{CATEGORY};
292 explicit constexpr TypeBase(
int kind) : kind_{kind} {
293 CHECK(common::IsValidKindOfIntrinsicType(CATEGORY, kind));
295 constexpr bool operator==(
const TypeBase &that)
const {
296 return kind_ == that.kind_;
298 constexpr DynamicType GetType()
const {
return {category, kind_}; }
299 std::string AsFortran()
const {
return GetType().AsFortran(); }
306class Type<TypeCategory::Integer> :
public TypeBase<TypeCategory::Integer> {
308 using TypeBase::TypeBase;
313class Type<TypeCategory::Unsigned> :
public TypeBase<TypeCategory::Unsigned> {
315 using TypeBase::TypeBase;
316 using Scalar = value::IntegerValue;
324 constexpr bool isFromInexactLiteralConversion()
const {
325 return isFromInexactLiteralConversion_;
327 void set_isFromInexactLiteralConversion(
bool yes =
true) {
328 isFromInexactLiteralConversion_ = yes;
332 bool isFromInexactLiteralConversion_{
false};
336class Type<TypeCategory::Real> :
public TypeBase<TypeCategory::Real>,
339 using TypeBase::TypeBase;
345class Type<TypeCategory::Complex> :
public TypeBase<TypeCategory::Complex>,
346 public TrackInexactLiteralConversion {
348 using TypeBase::TypeBase;
349 using Part = Type<TypeCategory::Real>;
350 using Scalar = value::ComplexValue;
354class Type<TypeCategory::Character> :
public TypeBase<TypeCategory::Character> {
356 using TypeBase::TypeBase;
357 using Scalar = value::CharacterValue;
361class Type<TypeCategory::Logical> :
public TypeBase<TypeCategory::Logical> {
363 using TypeBase::TypeBase;
364 using Scalar = value::LogicalValue;
371using IndirectSubscriptIntegerExpr =
372 common::CopyableIndirection<Expr<SubscriptInteger>>;
376template <TypeCategory CATEGORY>
377using CategoryTypes = std::tuple<Type<CATEGORY>>;
379using IntegerTypes = CategoryTypes<TypeCategory::Integer>;
380using RealTypes = CategoryTypes<TypeCategory::Real>;
381using ComplexTypes = CategoryTypes<TypeCategory::Complex>;
382using CharacterTypes = CategoryTypes<TypeCategory::Character>;
383using LogicalTypes = CategoryTypes<TypeCategory::Logical>;
384using UnsignedTypes = CategoryTypes<TypeCategory::Unsigned>;
386using FloatingTypes = common::CombineTuples<RealTypes, ComplexTypes>;
388 common::CombineTuples<IntegerTypes, FloatingTypes, UnsignedTypes>;
389using RelationalTypes = common::CombineTuples<IntegerTypes, RealTypes,
390 CharacterTypes, UnsignedTypes>;
391using AllIntrinsicTypes =
392 common::CombineTuples<NumericTypes, CharacterTypes, LogicalTypes>;
393using LengthlessIntrinsicTypes =
394 common::CombineTuples<NumericTypes, LogicalTypes>;
398constexpr bool IsSpecificIntrinsicType{common::HasMember<T, AllIntrinsicTypes>};
404constexpr bool IsLengthlessIntrinsicType{
405 common::HasMember<T, LengthlessIntrinsicTypes>};
409 static constexpr TypeCategory category{CATEGORY};
410 constexpr bool operator==(
const SomeKind &)
const {
return true; }
411 static std::string AsFortran() {
412 return "Some"s + std::string{common::EnumToString(category)};
416using NumericCategoryTypes =
419using AllIntrinsicCategoryTypes =
427 static std::string AsFortran() {
return "SomeType"s; }
433template <>
class SomeKind<TypeCategory::Derived> {
435 static constexpr TypeCategory category{TypeCategory::Derived};
436 using Scalar = StructureConstructor;
440 constexpr explicit SomeKind(
int kind = 0) { CHECK(kind == 0); }
441 constexpr explicit SomeKind(
const semantics::DerivedTypeSpec &dts)
442 : derivedTypeSpec_{&dts} {}
443 constexpr explicit SomeKind(
const DynamicType &dt)
444 : SomeKind(dt.GetDerivedTypeSpec()) {}
445 CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(SomeKind)
447 bool IsUnlimitedPolymorphic()
const {
return !derivedTypeSpec_; }
448 constexpr DynamicType GetType()
const {
449 if (!derivedTypeSpec_) {
450 return DynamicType::UnlimitedPolymorphic();
452 return DynamicType{*derivedTypeSpec_};
455 const semantics::DerivedTypeSpec &derivedTypeSpec()
const {
456 CHECK(derivedTypeSpec_);
457 return *derivedTypeSpec_;
459 bool operator==(
const SomeKind &)
const;
460 std::string AsFortran()
const;
463 const semantics::DerivedTypeSpec *derivedTypeSpec_{
nullptr};
473using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex,
474 SomeCharacter, SomeLogical, SomeUnsigned, SomeDerived>;
477 common::CombineTuples<AllIntrinsicTypes, std::tuple<SomeDerived>>;
479template <
typename T>
using Scalar =
typename std::decay_t<T>::Scalar;
486 static constexpr bool value() {
487 return std::is_same_v<std::decay_t<CONST>,
488 std::decay_t<typename T::Scalar>>;
491 static constexpr int index{
492 common::SearchMembers<Predicate, AllIntrinsicTypes>};
493 using type = std::conditional_t<index >= 0,
494 std::tuple_element_t<index, AllIntrinsicTypes>,
void>;
497template <
typename CONST>
using TypeOf =
typename TypeOfHelper<CONST>::type;
499int SelectedCharKind(
const std::string &,
int defaultKind);
506std::optional<DynamicType> ComparisonType(
507 const DynamicType &,
const DynamicType &);
510std::optional<bool> IsInteroperableIntrinsicType(
const DynamicType &,
512 bool checkCharLength =
true);
513bool IsCUDAIntrinsicType(
const DynamicType &);
517bool AreSameDerivedType(
519bool AreSameDerivedTypeIgnoringTypeParameters(
523bool AreSameDerivedTypeIgnoringLengthParameters(
525bool AreSameDerivedTypeIgnoringSequence(
531#define CHECK_KIND(KIND, TY) \
533 if constexpr (std::is_same_v<TY, SomeDerived> || \
534 std::is_same_v<TY, SomeKind<TypeCategory::Derived>> || \
535 std::is_same_v<TY, SomeType>) { \
536 CHECK_MSG((KIND) == 0, "Type does not have a kind"); \
538 CHECK_MSG(common::IsValidKindOfIntrinsicType(TY::category, (KIND)), \
539 "Type must come with a kind valid for its type category"); \
543#define FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \
544 PREFIX<Type<TypeCategory::Integer>> SUFFIX; \
545 PREFIX<Type<TypeCategory::Real>> SUFFIX; \
546 PREFIX<Type<TypeCategory::Complex>> SUFFIX; \
547 PREFIX<Type<TypeCategory::Logical>> SUFFIX; \
548 PREFIX<Type<TypeCategory::Unsigned>> SUFFIX;
549#define FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
550 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \
551 PREFIX<Type<TypeCategory::Character>> SUFFIX;
552#define FOR_EACH_SPECIFIC_TYPE(PREFIX, SUFFIX) \
553 FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
554 PREFIX<SomeDerived> SUFFIX;
556#define FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX) \
557 PREFIX<SomeInteger> SUFFIX; \
558 PREFIX<SomeReal> SUFFIX; \
559 PREFIX<SomeComplex> SUFFIX; \
560 PREFIX<SomeCharacter> SUFFIX; \
561 PREFIX<SomeLogical> SUFFIX; \
562 PREFIX<SomeUnsigned> SUFFIX; \
563 PREFIX<SomeDerived> SUFFIX; \
564 PREFIX<SomeType> SUFFIX;
565#define FOR_EACH_TYPE_AND_KIND(PREFIX, SUFFIX) \
566 FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
567 FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX)
580template <std::
size_t J,
typename VISITOR>
581common::IfNoLvalue<typename VISITOR::Result, VISITOR> SearchTypesHelper(
582 VISITOR &&visitor,
typename VISITOR::Result &&defaultResult) {
583 using Tuple =
typename VISITOR::Types;
584 if constexpr (J < std::tuple_size_v<Tuple>) {
585 using TYPE = std::tuple_element_t<J, Tuple>;
587 if (
auto result{visitor.template Test<TYPE>(kind)}) {
591 return SearchTypesHelper<J + 1, VISITOR>(
592 std::move(visitor), std::move(defaultResult));
594 return std::move(defaultResult);
598template <
typename VISITOR>
599common::IfNoLvalue<typename VISITOR::Result, VISITOR> SearchTypes(
601 typename VISITOR::Result defaultResult =
typename VISITOR::Result{}) {
602 return SearchTypesHelper<0, VISITOR>(
603 std::move(visitor), std::move(defaultResult));
Definition Fortran-features.h:102
Definition expression.h:849
Definition integer-value.h:35
Definition real-value.h:32
Iterable lists of valid kinds for each TypeCategory.
Definition type-kinds.h:32