[Hexagon] Use llvm::children (NFC)
[llvm-project.git] / flang / lib / Evaluate / type.cpp
bloba369e07f94a1fbebbbb62d2cf032cbb528c6c61d
1 //===-- lib/Evaluate/type.cpp ---------------------------------------------===//
2 //
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
6 //
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"
19 #include <algorithm>
20 #include <optional>
21 #include <string>
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) {
28 if (type) {
29 if (auto dynamicType{evaluate::DynamicType::From(*type)}) {
30 return dynamicType->RequiresDescriptor();
33 return false;
36 static bool IsDescriptor(const ObjectEntityDetails &details) {
37 if (IsDescriptor(details.type()) || details.IsAssumedRank()) {
38 return true;
40 for (const ShapeSpec &shapeSpec : details.shape()) {
41 if (const auto &ub{shapeSpec.ubound().GetExplicit()}) {
42 if (!IsConstantExpr(*ub)) {
43 return true;
45 } else {
46 return shapeSpec.ubound().isColon();
49 return false;
52 bool IsDescriptor(const Symbol &symbol) {
53 return common::visit(
54 common::visitors{
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) {
63 return true;
65 if (const auto dynamicType{expr->GetType()}) {
66 if (dynamicType->RequiresDescriptor()) {
67 return true;
71 return false;
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; },
80 symbol.details());
83 bool IsPassedViaDescriptor(const Symbol &symbol) {
84 if (!IsDescriptor(symbol)) {
85 return false;
87 if (IsAllocatableOrPointer(symbol)) {
88 return true;
90 if (semantics::IsAssumedSizeArray(symbol)) {
91 return false;
93 if (const auto *object{
94 symbol.GetUltimate().detailsIf<ObjectEntityDetails>()}) {
95 if (object->isDummy()) {
96 if (object->type() &&
97 object->type()->category() == DeclTypeSpec::Character) {
98 return false;
100 bool isExplicitShape{true};
101 for (const ShapeSpec &shapeSpec : object->shape()) {
102 if (!shapeSpec.lbound().GetExplicit() ||
103 !shapeSpec.ubound().GetExplicit()) {
104 isExplicitShape = false;
105 break;
108 if (isExplicitShape) {
109 return false; // explicit shape but non-constant bounds
113 return true;
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;
124 } else {
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) {
143 if (knownLength()) {
144 return AsExpr(Constant<SubscriptInteger>(*knownLength()));
145 } else if (charLengthParamValue_) {
146 if (auto length{charLengthParamValue_->GetExplicit()}) {
147 return ConvertToType<SubscriptInteger>(std::move(*length));
151 return std::nullopt;
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);
163 break;
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();
169 } else {
170 common::die("Missing scope for Vector type.");
173 } else {
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 {
182 switch (category_) {
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>{
191 *charLength}}
192 : GetCharLength()}) {
193 return Fold(context,
194 Expr<SubscriptInteger>{
195 context.targetCharacteristics().GetByteSize(category_, kind())} *
196 std::move(*len));
198 break;
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)};
207 break;
209 return std::nullopt;
212 bool DynamicType::IsAssumedLengthCharacter() const {
213 return category_ == TypeCategory::Character && charLengthParamValue_ &&
214 charLengthParamValue_->isAssumed();
217 bool DynamicType::IsNonConstantLengthCharacter() const {
218 if (category_ != TypeCategory::Character) {
219 return false;
220 } else if (knownLength()) {
221 return false;
222 } else if (!charLengthParamValue_) {
223 return true;
224 } else if (const auto &expr{charLengthParamValue_->GetExplicit()}) {
225 return !IsConstantExpr(*expr);
226 } else {
227 return true;
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();
249 } else {
250 return nullptr;
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()};
258 if (!scope) {
259 scope = typeSymbol.scope();
261 if (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)) {
268 return &symbol;
273 return nullptr;
276 const semantics::DerivedTypeSpec *GetParentTypeSpec(
277 const semantics::DerivedTypeSpec &derived) {
278 if (const semantics::Symbol * parent{FindParentComponent(derived)}) {
279 return &parent->get<semantics::ObjectEntityDetails>()
280 .type()
281 ->derivedTypeSpec();
282 } else {
283 return nullptr;
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);
297 // F2023 7.5.3.2
298 static bool AreSameComponent(const semantics::Symbol &x,
299 const semantics::Symbol &y, SetOfDerivedTypePairs &inProgress) {
300 if (x.attrs() != y.attrs()) {
301 return false;
303 if (x.attrs().test(semantics::Attr::PRIVATE)) {
304 return false;
306 if (x.size() && y.size()) {
307 if (x.offset() != y.offset() || x.size() != y.size()) {
308 return false;
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) {
316 return false;
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))) {
328 return false;
330 } else if (!xType->IsTkLenCompatibleWith(*yType)) {
331 return false;
333 } else if (xType || yType || !(xProc && yProc)) {
334 return false;
336 if (xProc) {
337 // TODO: compare argument types, &c.
339 return true;
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)) {
353 return &symbol;
357 return nullptr;
360 static const semantics::Symbol *GetParentComponent(
361 const semantics::Symbol *symbol, const semantics::Scope &scope) {
362 if (symbol) {
363 if (const auto *dtDetails{
364 symbol->detailsIf<semantics::DerivedTypeDetails>()}) {
365 return GetParentComponent(*dtDetails, scope);
368 return nullptr;
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>()
375 .type()
376 ->derivedTypeSpec();
377 } else {
378 return nullptr;
382 static const semantics::Scope *GetDerivedTypeParent(
383 const semantics::Scope *scope) {
384 if (scope) {
385 CHECK(scope->IsDerivedType());
386 if (const auto *parent{GetParentTypeSpec(scope->GetSymbol(), *scope)}) {
387 return parent->scope();
390 return nullptr;
393 static const semantics::Symbol *FindComponent(
394 const semantics::Scope *scope, parser::CharBlock name) {
395 if (!scope) {
396 return nullptr;
398 CHECK(scope->IsDerivedType());
399 auto found{scope->find(name)};
400 if (found != scope->end()) {
401 return &*found->second;
402 } else {
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)};
413 if (!yValue) {
414 return false;
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>()};
421 if (xTPD && yTPD) {
422 if (xTPD->attr() != yTPD->attr()) {
423 return false;
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) {
433 return false;
440 for (const auto &[paramName, _] : y.parameters()) {
441 if (!x.FindParameter(paramName)) {
442 return false; // y has more parameters than x
445 return true;
448 // F2023 7.5.3.2
449 static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
450 const semantics::DerivedTypeSpec &y, bool ignoreTypeParameterValues,
451 bool ignoreLenParameters, SetOfDerivedTypePairs &inProgress) {
452 if (&x == &y) {
453 return true;
455 if (!ignoreTypeParameterValues &&
456 !AreTypeParamCompatible(x, y, ignoreLenParameters)) {
457 return false;
459 const auto &xSymbol{x.typeSymbol().GetUltimate()};
460 const auto &ySymbol{y.typeSymbol().GetUltimate()};
461 if (xSymbol == ySymbol) {
462 return true;
464 if (xSymbol.name() != ySymbol.name()) {
465 return false;
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.
479 return false;
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()) {
489 return false;
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)) {
496 return false;
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) {
524 if (!x || !y) {
525 return false;
526 } else {
527 SetOfDerivedTypePairs inProgress;
528 if (AreSameDerivedType(*x, *y, ignoreTypeParameterValues,
529 ignoreLenTypeParameters, inProgress)) {
530 return true;
531 } else {
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()) {
542 return true;
543 } else if (y.IsUnlimitedPolymorphic()) {
544 return false;
545 } else if (x.category() != y.category()) {
546 return false;
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();
555 } else {
556 return !y.IsTypelessIntrinsicArgument() && x.kind() == y.kind();
558 } else {
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())) {
577 return true;
578 } else if (ignoreTKR.test(common::IgnoreTKR::Kind) &&
579 category() == that.category()) {
580 return true;
581 } else {
582 return AreCompatibleTypes(*this, that, false, true);
586 bool DynamicType::IsTkLenCompatibleWith(const DynamicType &that) const {
587 return AreCompatibleTypes(*this, that, false, false);
590 // 16.9.165
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)};
594 if (!x && !y) {
595 return false;
596 } else if (x && y && !IsPolymorphic() && !that.IsPolymorphic()) {
597 return true;
598 } else {
599 return std::nullopt;
603 // 16.9.76
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) {
611 return std::nullopt;
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'
621 return std::nullopt;
622 } else {
623 return false;
625 } else if (that.IsPolymorphic()) {
626 return std::nullopt; // unknown
627 } else {
628 return true;
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()};
641 } else {
642 return DynamicType{category, static_cast<int>(*kind)};
646 } else if (const auto *derived{type.AsDerived()}) {
647 return DynamicType{
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();
653 } else {
654 common::die("DynamicType::From(DeclTypeSpec): failed");
656 return std::nullopt;
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 {
664 switch (category_) {
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:
671 return that;
672 default:
673 CRASH_NO_CASE;
675 break;
676 case TypeCategory::Real:
677 switch (that.category_) {
678 case TypeCategory::Integer:
679 return *this;
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())};
684 default:
685 CRASH_NO_CASE;
687 break;
688 case TypeCategory::Complex:
689 switch (that.category_) {
690 case TypeCategory::Integer:
691 return *this;
692 case TypeCategory::Real:
693 case TypeCategory::Complex:
694 return DynamicType{TypeCategory::Complex, std::max(kind(), that.kind())};
695 default:
696 CRASH_NO_CASE;
698 break;
699 case TypeCategory::Logical:
700 switch (that.category_) {
701 case TypeCategory::Logical:
702 return DynamicType{TypeCategory::Logical, std::max(kind(), that.kind())};
703 default:
704 CRASH_NO_CASE;
706 break;
707 default:
708 CRASH_NO_CASE;
710 return *this;
713 bool DynamicType::RequiresDescriptor() const {
714 return IsPolymorphic() || IsNonConstantLengthCharacter() ||
715 (derived_ && CountNonConstantLenParameters(*derived_) > 0);
718 bool DynamicType::HasDeferredTypeParameter() const {
719 if (derived_) {
720 for (const auto &pair : derived_->parameters()) {
721 if (pair.second.isDeferred()) {
722 return true;
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] == ' ') {
738 lower.erase(0, 1);
739 --n;
741 while (n > 0 && lower[n - 1] == ' ') {
742 lower.erase(--n, 1);
744 if (lower == "ascii") {
745 return 1;
746 } else if (lower == "ucs-2") {
747 return 2;
748 } else if (lower == "iso_10646" || lower == "ucs-4") {
749 return 4;
750 } else if (lower == "default") {
751 return defaultKind;
752 } else {
753 return -1;
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:
766 return t2;
767 default:
768 return std::nullopt;
770 case TypeCategory::Real:
771 switch (t2.category()) {
772 case TypeCategory::Integer:
773 return t1;
774 case TypeCategory::Real:
775 case TypeCategory::Complex:
776 return DynamicType{t2.category(), std::max(t1.kind(), t2.kind())};
777 default:
778 return std::nullopt;
780 case TypeCategory::Complex:
781 switch (t2.category()) {
782 case TypeCategory::Integer:
783 return t1;
784 case TypeCategory::Real:
785 case TypeCategory::Complex:
786 return DynamicType{TypeCategory::Complex, std::max(t1.kind(), t2.kind())};
787 default:
788 return std::nullopt;
790 case TypeCategory::Character:
791 switch (t2.category()) {
792 case TypeCategory::Character:
793 return DynamicType{
794 TypeCategory::Character, std::max(t1.kind(), t2.kind())};
795 default:
796 return std::nullopt;
798 case TypeCategory::Logical:
799 switch (t2.category()) {
800 case TypeCategory::Logical:
801 return DynamicType{TypeCategory::Logical, LogicalResult::kind};
802 default:
803 return std::nullopt;
805 default:
806 return std::nullopt;
810 bool IsInteroperableIntrinsicType(const DynamicType &type,
811 const common::LanguageFeatureControl *features, bool checkCharLength) {
812 switch (type.category()) {
813 case TypeCategory::Integer:
814 return true;
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) {
823 return false;
825 return type.kind() == 1 /* C_CHAR */;
826 default:
827 // Derived types are tested in Semantics/check-declarations.cpp
828 return false;
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;
843 default:
844 // Derived types are tested in Semantics/check-declarations.cpp
845 return false;
849 DynamicType DynamicType::DropNonConstantCharacterLength() const {
850 if (charLengthParamValue_ && charLengthParamValue_->isExplicit()) {
851 if (std::optional<std::int64_t> len{knownLength()}) {
852 return DynamicType(kind_, *len);
853 } else {
854 return DynamicType(category_, kind_);
857 return *this;
860 } // namespace Fortran::evaluate