1 //===-- lib/Evaluate/type.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "flang/Evaluate/type.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Evaluate/expression.h"
12 #include "flang/Evaluate/fold.h"
13 #include "flang/Evaluate/target.h"
14 #include "flang/Parser/characters.h"
15 #include "flang/Semantics/scope.h"
16 #include "flang/Semantics/symbol.h"
17 #include "flang/Semantics/tools.h"
18 #include "flang/Semantics/type.h"
23 // IsDescriptor() predicate: true when a symbol is implemented
24 // at runtime with a descriptor.
25 namespace Fortran::semantics
{
27 static bool IsDescriptor(const DeclTypeSpec
*type
) {
29 if (auto dynamicType
{evaluate::DynamicType::From(*type
)}) {
30 return dynamicType
->RequiresDescriptor();
36 static bool IsDescriptor(const ObjectEntityDetails
&details
) {
37 if (IsDescriptor(details
.type()) || details
.IsAssumedRank()) {
40 for (const ShapeSpec
&shapeSpec
: details
.shape()) {
41 if (const auto &ub
{shapeSpec
.ubound().GetExplicit()}) {
42 if (!IsConstantExpr(*ub
)) {
46 return shapeSpec
.ubound().isColon();
52 bool IsDescriptor(const Symbol
&symbol
) {
55 [&](const ObjectEntityDetails
&d
) {
56 return IsAllocatableOrPointer(symbol
) || IsDescriptor(d
);
58 [&](const ProcEntityDetails
&d
) { return false; },
59 [&](const EntityDetails
&d
) { return IsDescriptor(d
.type()); },
60 [](const AssocEntityDetails
&d
) {
61 if (const auto &expr
{d
.expr()}) {
62 if (expr
->Rank() > 0) {
65 if (const auto dynamicType
{expr
->GetType()}) {
66 if (dynamicType
->RequiresDescriptor()) {
73 [](const SubprogramDetails
&d
) {
74 return d
.isFunction() && IsDescriptor(d
.result());
76 [](const UseDetails
&d
) { return IsDescriptor(d
.symbol()); },
77 [](const HostAssocDetails
&d
) { return IsDescriptor(d
.symbol()); },
78 [](const auto &) { return false; },
83 bool IsPassedViaDescriptor(const Symbol
&symbol
) {
84 if (!IsDescriptor(symbol
)) {
87 if (IsAllocatableOrPointer(symbol
)) {
90 if (semantics::IsAssumedSizeArray(symbol
)) {
93 if (const auto *object
{
94 symbol
.GetUltimate().detailsIf
<ObjectEntityDetails
>()}) {
95 if (object
->isDummy()) {
97 object
->type()->category() == DeclTypeSpec::Character
) {
100 bool isExplicitShape
{true};
101 for (const ShapeSpec
&shapeSpec
: object
->shape()) {
102 if (!shapeSpec
.lbound().GetExplicit() ||
103 !shapeSpec
.ubound().GetExplicit()) {
104 isExplicitShape
= false;
108 if (isExplicitShape
) {
109 return false; // explicit shape but non-constant bounds
115 } // namespace Fortran::semantics
117 namespace Fortran::evaluate
{
119 DynamicType::DynamicType(int k
, const semantics::ParamValue
&pv
)
120 : category_
{TypeCategory::Character
}, kind_
{k
} {
121 CHECK(IsValidKindOfIntrinsicType(category_
, kind_
));
122 if (auto n
{ToInt64(pv
.GetExplicit())}) {
123 knownLength_
= *n
> 0 ? *n
: 0;
125 charLengthParamValue_
= &pv
;
129 template <typename A
> inline bool PointeeComparison(const A
*x
, const A
*y
) {
130 return x
== y
|| (x
&& y
&& *x
== *y
);
133 bool DynamicType::operator==(const DynamicType
&that
) const {
134 return category_
== that
.category_
&& kind_
== that
.kind_
&&
135 PointeeComparison(charLengthParamValue_
, that
.charLengthParamValue_
) &&
136 knownLength().has_value() == that
.knownLength().has_value() &&
137 (!knownLength() || *knownLength() == *that
.knownLength()) &&
138 PointeeComparison(derived_
, that
.derived_
);
141 std::optional
<Expr
<SubscriptInteger
>> DynamicType::GetCharLength() const {
142 if (category_
== TypeCategory::Character
) {
144 return AsExpr(Constant
<SubscriptInteger
>(*knownLength()));
145 } else if (charLengthParamValue_
) {
146 if (auto length
{charLengthParamValue_
->GetExplicit()}) {
147 return ConvertToType
<SubscriptInteger
>(std::move(*length
));
154 std::size_t DynamicType::GetAlignment(
155 const TargetCharacteristics
&targetCharacteristics
) const {
156 if (category_
== TypeCategory::Derived
) {
157 switch (GetDerivedTypeSpec().category()) {
158 SWITCH_COVERS_ALL_CASES
159 case semantics::DerivedTypeSpec::Category::DerivedType
:
160 if (derived_
&& derived_
->scope()) {
161 return derived_
->scope()->alignment().value_or(1);
164 case semantics::DerivedTypeSpec::Category::IntrinsicVector
:
165 case semantics::DerivedTypeSpec::Category::PairVector
:
166 case semantics::DerivedTypeSpec::Category::QuadVector
:
167 if (derived_
&& derived_
->scope()) {
168 return derived_
->scope()->size();
170 common::die("Missing scope for Vector type.");
174 return targetCharacteristics
.GetAlignment(category_
, kind());
176 return 1; // needs to be after switch to dodge a bogus gcc warning
179 std::optional
<Expr
<SubscriptInteger
>> DynamicType::MeasureSizeInBytes(
180 FoldingContext
&context
, bool aligned
,
181 std::optional
<std::int64_t> charLength
) const {
183 case TypeCategory::Integer
:
184 case TypeCategory::Real
:
185 case TypeCategory::Complex
:
186 case TypeCategory::Logical
:
187 return Expr
<SubscriptInteger
>{
188 context
.targetCharacteristics().GetByteSize(category_
, kind())};
189 case TypeCategory::Character
:
190 if (auto len
{charLength
? Expr
<SubscriptInteger
>{Constant
<SubscriptInteger
>{
192 : GetCharLength()}) {
194 Expr
<SubscriptInteger
>{
195 context
.targetCharacteristics().GetByteSize(category_
, kind())} *
199 case TypeCategory::Derived
:
200 if (!IsPolymorphic() && derived_
&& derived_
->scope()) {
201 auto size
{derived_
->scope()->size()};
202 auto align
{aligned
? derived_
->scope()->alignment().value_or(0) : 0};
203 auto alignedSize
{align
> 0 ? ((size
+ align
- 1) / align
) * align
: size
};
204 return Expr
<SubscriptInteger
>{
205 static_cast<ConstantSubscript
>(alignedSize
)};
212 bool DynamicType::IsAssumedLengthCharacter() const {
213 return category_
== TypeCategory::Character
&& charLengthParamValue_
&&
214 charLengthParamValue_
->isAssumed();
217 bool DynamicType::IsNonConstantLengthCharacter() const {
218 if (category_
!= TypeCategory::Character
) {
220 } else if (knownLength()) {
222 } else if (!charLengthParamValue_
) {
224 } else if (const auto &expr
{charLengthParamValue_
->GetExplicit()}) {
225 return !IsConstantExpr(*expr
);
231 bool DynamicType::IsTypelessIntrinsicArgument() const {
232 return category_
== TypeCategory::Integer
&& kind_
== TypelessKind
;
235 bool DynamicType::IsLengthlessIntrinsicType() const {
236 return common::IsNumericTypeCategory(category_
) ||
237 category_
== TypeCategory::Logical
;
240 const semantics::DerivedTypeSpec
*GetDerivedTypeSpec(
241 const std::optional
<DynamicType
> &type
) {
242 return type
? GetDerivedTypeSpec(*type
) : nullptr;
245 const semantics::DerivedTypeSpec
*GetDerivedTypeSpec(const DynamicType
&type
) {
246 if (type
.category() == TypeCategory::Derived
&&
247 !type
.IsUnlimitedPolymorphic()) {
248 return &type
.GetDerivedTypeSpec();
254 static const semantics::Symbol
*FindParentComponent(
255 const semantics::DerivedTypeSpec
&derived
) {
256 const semantics::Symbol
&typeSymbol
{derived
.typeSymbol()};
257 const semantics::Scope
*scope
{derived
.scope()};
259 scope
= typeSymbol
.scope();
262 const auto &dtDetails
{typeSymbol
.get
<semantics::DerivedTypeDetails
>()};
263 // TODO: Combine with semantics::DerivedTypeDetails::GetParentComponent
264 if (auto extends
{dtDetails
.GetParentComponentName()}) {
265 if (auto iter
{scope
->find(*extends
)}; iter
!= scope
->cend()) {
266 if (const semantics::Symbol
& symbol
{*iter
->second
};
267 symbol
.test(semantics::Symbol::Flag::ParentComp
)) {
276 const semantics::DerivedTypeSpec
*GetParentTypeSpec(
277 const semantics::DerivedTypeSpec
&derived
) {
278 if (const semantics::Symbol
* parent
{FindParentComponent(derived
)}) {
279 return &parent
->get
<semantics::ObjectEntityDetails
>()
287 // Compares two derived type representations to see whether they both
288 // represent the "same type" in the sense of section F'2023 7.5.2.4.
289 using SetOfDerivedTypePairs
=
290 std::set
<std::pair
<const semantics::DerivedTypeSpec
*,
291 const semantics::DerivedTypeSpec
*>>;
293 static bool AreSameDerivedType(const semantics::DerivedTypeSpec
&,
294 const semantics::DerivedTypeSpec
&, bool ignoreTypeParameterValues
,
295 bool ignoreLenParameters
, SetOfDerivedTypePairs
&inProgress
);
298 static bool AreSameComponent(const semantics::Symbol
&x
,
299 const semantics::Symbol
&y
, SetOfDerivedTypePairs
&inProgress
) {
300 if (x
.attrs() != y
.attrs()) {
303 if (x
.attrs().test(semantics::Attr::PRIVATE
)) {
306 if (x
.size() && y
.size()) {
307 if (x
.offset() != y
.offset() || x
.size() != y
.size()) {
311 const auto *xObj
{x
.detailsIf
<semantics::ObjectEntityDetails
>()};
312 const auto *yObj
{y
.detailsIf
<semantics::ObjectEntityDetails
>()};
313 const auto *xProc
{x
.detailsIf
<semantics::ProcEntityDetails
>()};
314 const auto *yProc
{y
.detailsIf
<semantics::ProcEntityDetails
>()};
315 if (!xObj
!= !yObj
|| !xProc
!= !yProc
) {
318 auto xType
{DynamicType::From(x
)};
319 auto yType
{DynamicType::From(y
)};
320 if (xType
&& yType
) {
321 if (xType
->category() == TypeCategory::Derived
) {
322 if (yType
->category() != TypeCategory::Derived
||
323 !xType
->IsUnlimitedPolymorphic() !=
324 !yType
->IsUnlimitedPolymorphic() ||
325 (!xType
->IsUnlimitedPolymorphic() &&
326 !AreSameDerivedType(xType
->GetDerivedTypeSpec(),
327 yType
->GetDerivedTypeSpec(), false, false, inProgress
))) {
330 } else if (!xType
->IsTkLenCompatibleWith(*yType
)) {
333 } else if (xType
|| yType
|| !(xProc
&& yProc
)) {
337 // TODO: compare argument types, &c.
342 // TODO: These utilities were cloned out of Semantics to avoid a cyclic
343 // dependency and should be repackaged into then "namespace semantics"
344 // part of Evaluate/tools.cpp.
346 static const semantics::Symbol
*GetParentComponent(
347 const semantics::DerivedTypeDetails
&details
,
348 const semantics::Scope
&scope
) {
349 if (auto extends
{details
.GetParentComponentName()}) {
350 if (auto iter
{scope
.find(*extends
)}; iter
!= scope
.cend()) {
351 if (const Symbol
& symbol
{*iter
->second
};
352 symbol
.test(semantics::Symbol::Flag::ParentComp
)) {
360 static const semantics::Symbol
*GetParentComponent(
361 const semantics::Symbol
*symbol
, const semantics::Scope
&scope
) {
363 if (const auto *dtDetails
{
364 symbol
->detailsIf
<semantics::DerivedTypeDetails
>()}) {
365 return GetParentComponent(*dtDetails
, scope
);
371 static const semantics::DerivedTypeSpec
*GetParentTypeSpec(
372 const semantics::Symbol
*symbol
, const semantics::Scope
&scope
) {
373 if (const Symbol
* parentComponent
{GetParentComponent(symbol
, scope
)}) {
374 return &parentComponent
->get
<semantics::ObjectEntityDetails
>()
382 static const semantics::Scope
*GetDerivedTypeParent(
383 const semantics::Scope
*scope
) {
385 CHECK(scope
->IsDerivedType());
386 if (const auto *parent
{GetParentTypeSpec(scope
->GetSymbol(), *scope
)}) {
387 return parent
->scope();
393 static const semantics::Symbol
*FindComponent(
394 const semantics::Scope
*scope
, parser::CharBlock name
) {
398 CHECK(scope
->IsDerivedType());
399 auto found
{scope
->find(name
)};
400 if (found
!= scope
->end()) {
401 return &*found
->second
;
403 return FindComponent(GetDerivedTypeParent(scope
), name
);
407 static bool AreTypeParamCompatible(const semantics::DerivedTypeSpec
&x
,
408 const semantics::DerivedTypeSpec
&y
, bool ignoreLenParameters
) {
409 const auto *xScope
{x
.typeSymbol().scope()};
410 const auto *yScope
{y
.typeSymbol().scope()};
411 for (const auto &[paramName
, value
] : x
.parameters()) {
412 const auto *yValue
{y
.FindParameter(paramName
)};
416 const auto *xParm
{FindComponent(xScope
, paramName
)};
417 const auto *yParm
{FindComponent(yScope
, paramName
)};
418 if (xParm
&& yParm
) {
419 const auto *xTPD
{xParm
->detailsIf
<semantics::TypeParamDetails
>()};
420 const auto *yTPD
{yParm
->detailsIf
<semantics::TypeParamDetails
>()};
422 if (xTPD
->attr() != yTPD
->attr()) {
425 if (!ignoreLenParameters
||
426 xTPD
->attr() != common::TypeParamAttr::Len
) {
427 auto xExpr
{value
.GetExplicit()};
428 auto yExpr
{yValue
->GetExplicit()};
429 if (xExpr
&& yExpr
) {
430 auto xVal
{ToInt64(*xExpr
)};
431 auto yVal
{ToInt64(*yExpr
)};
432 if (xVal
&& yVal
&& *xVal
!= *yVal
) {
440 for (const auto &[paramName
, _
] : y
.parameters()) {
441 if (!x
.FindParameter(paramName
)) {
442 return false; // y has more parameters than x
449 static bool AreSameDerivedType(const semantics::DerivedTypeSpec
&x
,
450 const semantics::DerivedTypeSpec
&y
, bool ignoreTypeParameterValues
,
451 bool ignoreLenParameters
, SetOfDerivedTypePairs
&inProgress
) {
455 if (!ignoreTypeParameterValues
&&
456 !AreTypeParamCompatible(x
, y
, ignoreLenParameters
)) {
459 const auto &xSymbol
{x
.typeSymbol().GetUltimate()};
460 const auto &ySymbol
{y
.typeSymbol().GetUltimate()};
461 if (xSymbol
== ySymbol
) {
464 if (xSymbol
.name() != ySymbol
.name()) {
467 auto thisQuery
{std::make_pair(&x
, &y
)};
468 if (inProgress
.find(thisQuery
) != inProgress
.end()) {
469 return true; // recursive use of types in components
471 inProgress
.insert(thisQuery
);
472 const auto &xDetails
{xSymbol
.get
<semantics::DerivedTypeDetails
>()};
473 const auto &yDetails
{ySymbol
.get
<semantics::DerivedTypeDetails
>()};
474 if (!(xDetails
.sequence() && yDetails
.sequence()) &&
475 !(xSymbol
.attrs().test(semantics::Attr::BIND_C
) &&
476 ySymbol
.attrs().test(semantics::Attr::BIND_C
))) {
477 // PGI does not enforce this requirement; all other Fortran
478 // compilers do with a hard error when violations are caught.
481 // Compare the component lists in their orders of declaration.
482 auto xEnd
{xDetails
.componentNames().cend()};
483 auto yComponentName
{yDetails
.componentNames().cbegin()};
484 auto yEnd
{yDetails
.componentNames().cend()};
485 for (auto xComponentName
{xDetails
.componentNames().cbegin()};
486 xComponentName
!= xEnd
; ++xComponentName
, ++yComponentName
) {
487 if (yComponentName
== yEnd
|| *xComponentName
!= *yComponentName
||
488 !xSymbol
.scope() || !ySymbol
.scope()) {
491 const auto xLookup
{xSymbol
.scope()->find(*xComponentName
)};
492 const auto yLookup
{ySymbol
.scope()->find(*yComponentName
)};
493 if (xLookup
== xSymbol
.scope()->end() ||
494 yLookup
== ySymbol
.scope()->end() ||
495 !AreSameComponent(*xLookup
->second
, *yLookup
->second
, inProgress
)) {
499 return yComponentName
== yEnd
;
502 bool AreSameDerivedType(
503 const semantics::DerivedTypeSpec
&x
, const semantics::DerivedTypeSpec
&y
) {
504 SetOfDerivedTypePairs inProgress
;
505 return AreSameDerivedType(x
, y
, false, false, inProgress
);
508 bool AreSameDerivedType(
509 const semantics::DerivedTypeSpec
*x
, const semantics::DerivedTypeSpec
*y
) {
510 return x
== y
|| (x
&& y
&& AreSameDerivedType(*x
, *y
));
513 bool DynamicType::IsEquivalentTo(const DynamicType
&that
) const {
514 return category_
== that
.category_
&& kind_
== that
.kind_
&&
515 PointeeComparison(charLengthParamValue_
, that
.charLengthParamValue_
) &&
516 knownLength().has_value() == that
.knownLength().has_value() &&
517 (!knownLength() || *knownLength() == *that
.knownLength()) &&
518 AreSameDerivedType(derived_
, that
.derived_
);
521 static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec
*x
,
522 const semantics::DerivedTypeSpec
*y
, bool isPolymorphic
,
523 bool ignoreTypeParameterValues
, bool ignoreLenTypeParameters
) {
527 SetOfDerivedTypePairs inProgress
;
528 if (AreSameDerivedType(*x
, *y
, ignoreTypeParameterValues
,
529 ignoreLenTypeParameters
, inProgress
)) {
532 return isPolymorphic
&&
533 AreCompatibleDerivedTypes(x
, GetParentTypeSpec(*y
), true,
534 ignoreTypeParameterValues
, ignoreLenTypeParameters
);
539 static bool AreCompatibleTypes(const DynamicType
&x
, const DynamicType
&y
,
540 bool ignoreTypeParameterValues
, bool ignoreLengths
) {
541 if (x
.IsUnlimitedPolymorphic()) {
543 } else if (y
.IsUnlimitedPolymorphic()) {
545 } else if (x
.category() != y
.category()) {
547 } else if (x
.category() == TypeCategory::Character
) {
548 const auto xLen
{x
.knownLength()};
549 const auto yLen
{y
.knownLength()};
550 return x
.kind() == y
.kind() &&
551 (ignoreLengths
|| !xLen
|| !yLen
|| *xLen
== *yLen
);
552 } else if (x
.category() != TypeCategory::Derived
) {
553 if (x
.IsTypelessIntrinsicArgument()) {
554 return y
.IsTypelessIntrinsicArgument();
556 return !y
.IsTypelessIntrinsicArgument() && x
.kind() == y
.kind();
559 const auto *xdt
{GetDerivedTypeSpec(x
)};
560 const auto *ydt
{GetDerivedTypeSpec(y
)};
561 return AreCompatibleDerivedTypes(
562 xdt
, ydt
, x
.IsPolymorphic(), ignoreTypeParameterValues
, false);
566 // See 7.3.2.3 (5) & 15.5.2.4
567 bool DynamicType::IsTkCompatibleWith(const DynamicType
&that
) const {
568 return AreCompatibleTypes(*this, that
, false, true);
571 bool DynamicType::IsTkCompatibleWith(
572 const DynamicType
&that
, common::IgnoreTKRSet ignoreTKR
) const {
573 if (ignoreTKR
.test(common::IgnoreTKR::Type
) &&
574 (category() == TypeCategory::Derived
||
575 that
.category() == TypeCategory::Derived
||
576 category() != that
.category())) {
578 } else if (ignoreTKR
.test(common::IgnoreTKR::Kind
) &&
579 category() == that
.category()) {
582 return AreCompatibleTypes(*this, that
, false, true);
586 bool DynamicType::IsTkLenCompatibleWith(const DynamicType
&that
) const {
587 return AreCompatibleTypes(*this, that
, false, false);
591 std::optional
<bool> DynamicType::SameTypeAs(const DynamicType
&that
) const {
592 bool x
{AreCompatibleTypes(*this, that
, true, true)};
593 bool y
{AreCompatibleTypes(that
, *this, true, true)};
596 } else if (x
&& y
&& !IsPolymorphic() && !that
.IsPolymorphic()) {
604 std::optional
<bool> DynamicType::ExtendsTypeOf(const DynamicType
&that
) const {
605 if (IsUnlimitedPolymorphic() || that
.IsUnlimitedPolymorphic()) {
606 return std::nullopt
; // unknown
608 const auto *thisDts
{evaluate::GetDerivedTypeSpec(*this)};
609 const auto *thatDts
{evaluate::GetDerivedTypeSpec(that
)};
610 if (!thisDts
|| !thatDts
) {
612 } else if (!AreCompatibleDerivedTypes(thatDts
, thisDts
, true, true, true)) {
613 // Note that I check *thisDts, not its parent, so that EXTENDS_TYPE_OF()
614 // is .true. when they are the same type. This is technically
615 // an implementation-defined case in the standard, but every other
616 // compiler works this way.
617 if (IsPolymorphic() &&
618 AreCompatibleDerivedTypes(thisDts
, thatDts
, true, true, true)) {
619 // 'that' is *this or an extension of *this, and so runtime *this
620 // could be an extension of 'that'
625 } else if (that
.IsPolymorphic()) {
626 return std::nullopt
; // unknown
632 std::optional
<DynamicType
> DynamicType::From(
633 const semantics::DeclTypeSpec
&type
) {
634 if (const auto *intrinsic
{type
.AsIntrinsic()}) {
635 if (auto kind
{ToInt64(intrinsic
->kind())}) {
636 TypeCategory category
{intrinsic
->category()};
637 if (IsValidKindOfIntrinsicType(category
, *kind
)) {
638 if (category
== TypeCategory::Character
) {
639 const auto &charType
{type
.characterTypeSpec()};
640 return DynamicType
{static_cast<int>(*kind
), charType
.length()};
642 return DynamicType
{category
, static_cast<int>(*kind
)};
646 } else if (const auto *derived
{type
.AsDerived()}) {
648 *derived
, type
.category() == semantics::DeclTypeSpec::ClassDerived
};
649 } else if (type
.category() == semantics::DeclTypeSpec::ClassStar
) {
650 return DynamicType::UnlimitedPolymorphic();
651 } else if (type
.category() == semantics::DeclTypeSpec::TypeStar
) {
652 return DynamicType::AssumedType();
654 common::die("DynamicType::From(DeclTypeSpec): failed");
659 std::optional
<DynamicType
> DynamicType::From(const semantics::Symbol
&symbol
) {
660 return From(symbol
.GetType()); // Symbol -> DeclTypeSpec -> DynamicType
663 DynamicType
DynamicType::ResultTypeForMultiply(const DynamicType
&that
) const {
665 case TypeCategory::Integer
:
666 switch (that
.category_
) {
667 case TypeCategory::Integer
:
668 return DynamicType
{TypeCategory::Integer
, std::max(kind(), that
.kind())};
669 case TypeCategory::Real
:
670 case TypeCategory::Complex
:
676 case TypeCategory::Real
:
677 switch (that
.category_
) {
678 case TypeCategory::Integer
:
680 case TypeCategory::Real
:
681 return DynamicType
{TypeCategory::Real
, std::max(kind(), that
.kind())};
682 case TypeCategory::Complex
:
683 return DynamicType
{TypeCategory::Complex
, std::max(kind(), that
.kind())};
688 case TypeCategory::Complex
:
689 switch (that
.category_
) {
690 case TypeCategory::Integer
:
692 case TypeCategory::Real
:
693 case TypeCategory::Complex
:
694 return DynamicType
{TypeCategory::Complex
, std::max(kind(), that
.kind())};
699 case TypeCategory::Logical
:
700 switch (that
.category_
) {
701 case TypeCategory::Logical
:
702 return DynamicType
{TypeCategory::Logical
, std::max(kind(), that
.kind())};
713 bool DynamicType::RequiresDescriptor() const {
714 return IsPolymorphic() || IsNonConstantLengthCharacter() ||
715 (derived_
&& CountNonConstantLenParameters(*derived_
) > 0);
718 bool DynamicType::HasDeferredTypeParameter() const {
720 for (const auto &pair
: derived_
->parameters()) {
721 if (pair
.second
.isDeferred()) {
726 return charLengthParamValue_
&& charLengthParamValue_
->isDeferred();
729 bool SomeKind
<TypeCategory::Derived
>::operator==(
730 const SomeKind
<TypeCategory::Derived
> &that
) const {
731 return PointeeComparison(derivedTypeSpec_
, that
.derivedTypeSpec_
);
734 int SelectedCharKind(const std::string
&s
, int defaultKind
) { // 16.9.168
735 auto lower
{parser::ToLowerCaseLetters(s
)};
736 auto n
{lower
.size()};
737 while (n
> 0 && lower
[0] == ' ') {
741 while (n
> 0 && lower
[n
- 1] == ' ') {
744 if (lower
== "ascii") {
746 } else if (lower
== "ucs-2") {
748 } else if (lower
== "iso_10646" || lower
== "ucs-4") {
750 } else if (lower
== "default") {
757 std::optional
<DynamicType
> ComparisonType(
758 const DynamicType
&t1
, const DynamicType
&t2
) {
759 switch (t1
.category()) {
760 case TypeCategory::Integer
:
761 switch (t2
.category()) {
762 case TypeCategory::Integer
:
763 return DynamicType
{TypeCategory::Integer
, std::max(t1
.kind(), t2
.kind())};
764 case TypeCategory::Real
:
765 case TypeCategory::Complex
:
770 case TypeCategory::Real
:
771 switch (t2
.category()) {
772 case TypeCategory::Integer
:
774 case TypeCategory::Real
:
775 case TypeCategory::Complex
:
776 return DynamicType
{t2
.category(), std::max(t1
.kind(), t2
.kind())};
780 case TypeCategory::Complex
:
781 switch (t2
.category()) {
782 case TypeCategory::Integer
:
784 case TypeCategory::Real
:
785 case TypeCategory::Complex
:
786 return DynamicType
{TypeCategory::Complex
, std::max(t1
.kind(), t2
.kind())};
790 case TypeCategory::Character
:
791 switch (t2
.category()) {
792 case TypeCategory::Character
:
794 TypeCategory::Character
, std::max(t1
.kind(), t2
.kind())};
798 case TypeCategory::Logical
:
799 switch (t2
.category()) {
800 case TypeCategory::Logical
:
801 return DynamicType
{TypeCategory::Logical
, LogicalResult::kind
};
810 bool IsInteroperableIntrinsicType(const DynamicType
&type
,
811 const common::LanguageFeatureControl
*features
, bool checkCharLength
) {
812 switch (type
.category()) {
813 case TypeCategory::Integer
:
815 case TypeCategory::Real
:
816 case TypeCategory::Complex
:
817 return (features
&& features
->IsEnabled(common::LanguageFeature::CUDA
)) ||
818 type
.kind() >= 4; // no short or half floats
819 case TypeCategory::Logical
:
820 return type
.kind() == 1; // C_BOOL
821 case TypeCategory::Character
:
822 if (checkCharLength
&& type
.knownLength().value_or(0) != 1) {
825 return type
.kind() == 1 /* C_CHAR */;
827 // Derived types are tested in Semantics/check-declarations.cpp
832 bool IsCUDAIntrinsicType(const DynamicType
&type
) {
833 switch (type
.category()) {
834 case TypeCategory::Integer
:
835 case TypeCategory::Logical
:
836 return type
.kind() <= 8;
837 case TypeCategory::Real
:
838 return type
.kind() >= 2 && type
.kind() <= 8;
839 case TypeCategory::Complex
:
840 return type
.kind() == 2 || type
.kind() == 4 || type
.kind() == 8;
841 case TypeCategory::Character
:
842 return type
.kind() == 1;
844 // Derived types are tested in Semantics/check-declarations.cpp
849 DynamicType
DynamicType::DropNonConstantCharacterLength() const {
850 if (charLengthParamValue_
&& charLengthParamValue_
->isExplicit()) {
851 if (std::optional
<std::int64_t> len
{knownLength()}) {
852 return DynamicType(kind_
, *len
);
854 return DynamicType(category_
, kind_
);
860 } // namespace Fortran::evaluate