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 //===----------------------------------------------------------------------===// 8 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> 22 23 // IsDescriptor() predicate: true when a symbol is implemented 24 // at runtime with a descriptor. 25 namespace Fortran::semantics { 26 27 static bool IsDescriptor(const DeclTypeSpec *type) { 28 if (type) { 29 if (auto dynamicType{evaluate::DynamicType::From(*type)}) { 30 return dynamicType->RequiresDescriptor(); 31 } 32 } 33 return false; 34 } 35 36 static bool IsDescriptor(const ObjectEntityDetails &details) { 37 if (IsDescriptor(details.type())) { 38 return true; 39 } 40 for (const ShapeSpec &shapeSpec : details.shape()) { 41 const auto &lb{shapeSpec.lbound().GetExplicit()}; 42 const auto &ub{shapeSpec.ubound().GetExplicit()}; 43 if (!lb || !ub || !IsConstantExpr(*lb) || !IsConstantExpr(*ub)) { 44 return true; 45 } 46 } 47 return false; 48 } 49 50 static bool IsDescriptor(const ProcEntityDetails &details) { 51 // A procedure pointer or dummy procedure must be & is a descriptor if 52 // and only if it requires a static link. 53 // TODO: refine this placeholder 54 return details.HasExplicitInterface(); 55 } 56 57 bool IsDescriptor(const Symbol &symbol) { 58 return common::visit( 59 common::visitors{ 60 [&](const ObjectEntityDetails &d) { 61 return IsAllocatableOrPointer(symbol) || IsDescriptor(d); 62 }, 63 [&](const ProcEntityDetails &d) { 64 return (symbol.attrs().test(Attr::POINTER) || 65 symbol.attrs().test(Attr::EXTERNAL)) && 66 IsDescriptor(d); 67 }, 68 [&](const EntityDetails &d) { return IsDescriptor(d.type()); }, 69 [](const AssocEntityDetails &d) { 70 if (const auto &expr{d.expr()}) { 71 if (expr->Rank() > 0) { 72 return true; 73 } 74 if (const auto dynamicType{expr->GetType()}) { 75 if (dynamicType->RequiresDescriptor()) { 76 return true; 77 } 78 } 79 } 80 return false; 81 }, 82 [](const SubprogramDetails &d) { 83 return d.isFunction() && IsDescriptor(d.result()); 84 }, 85 [](const UseDetails &d) { return IsDescriptor(d.symbol()); }, 86 [](const HostAssocDetails &d) { return IsDescriptor(d.symbol()); }, 87 [](const auto &) { return false; }, 88 }, 89 symbol.details()); 90 } 91 92 bool IsPassedViaDescriptor(const Symbol &symbol) { 93 if (!IsDescriptor(symbol)) { 94 return false; 95 } 96 if (const auto *object{ 97 symbol.GetUltimate().detailsIf<ObjectEntityDetails>()}) { 98 if (object->isDummy()) { 99 if (object->type() && 100 object->type()->category() == DeclTypeSpec::Character) { 101 return false; 102 } 103 if (object->IsAssumedSize()) { 104 return false; 105 } 106 bool isExplicitShape{true}; 107 for (const ShapeSpec &shapeSpec : object->shape()) { 108 if (!shapeSpec.lbound().GetExplicit() || 109 !shapeSpec.ubound().GetExplicit()) { 110 isExplicitShape = false; 111 break; 112 } 113 } 114 if (isExplicitShape) { 115 return false; // explicit shape but non-constant bounds 116 } 117 } 118 } 119 return true; 120 } 121 } // namespace Fortran::semantics 122 123 namespace Fortran::evaluate { 124 125 DynamicType::DynamicType(int k, const semantics::ParamValue &pv) 126 : category_{TypeCategory::Character}, kind_{k} { 127 CHECK(IsValidKindOfIntrinsicType(category_, kind_)); 128 if (auto n{ToInt64(pv.GetExplicit())}) { 129 knownLength_ = *n > 0 ? *n : 0; 130 } else { 131 charLengthParamValue_ = &pv; 132 } 133 } 134 135 template <typename A> inline bool PointeeComparison(const A *x, const A *y) { 136 return x == y || (x && y && *x == *y); 137 } 138 139 bool DynamicType::operator==(const DynamicType &that) const { 140 return category_ == that.category_ && kind_ == that.kind_ && 141 PointeeComparison(charLengthParamValue_, that.charLengthParamValue_) && 142 knownLength().has_value() == that.knownLength().has_value() && 143 (!knownLength() || *knownLength() == *that.knownLength()) && 144 PointeeComparison(derived_, that.derived_); 145 } 146 147 std::optional<Expr<SubscriptInteger>> DynamicType::GetCharLength() const { 148 if (category_ == TypeCategory::Character) { 149 if (knownLength()) { 150 return AsExpr(Constant<SubscriptInteger>(*knownLength())); 151 } else if (charLengthParamValue_) { 152 if (auto length{charLengthParamValue_->GetExplicit()}) { 153 return ConvertToType<SubscriptInteger>(std::move(*length)); 154 } 155 } 156 } 157 return std::nullopt; 158 } 159 160 std::size_t DynamicType::GetAlignment( 161 const TargetCharacteristics &targetCharacteristics) const { 162 if (category_ == TypeCategory::Derived) { 163 if (derived_ && derived_->scope()) { 164 return derived_->scope()->alignment().value_or(1); 165 } 166 } else { 167 return targetCharacteristics.GetAlignment(category_, kind_); 168 } 169 return 1; // needs to be after switch to dodge a bogus gcc warning 170 } 171 172 std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes( 173 FoldingContext &context, bool aligned, 174 std::optional<std::int64_t> charLength) const { 175 switch (category_) { 176 case TypeCategory::Integer: 177 case TypeCategory::Real: 178 case TypeCategory::Complex: 179 case TypeCategory::Logical: 180 return Expr<SubscriptInteger>{ 181 context.targetCharacteristics().GetByteSize(category_, kind_)}; 182 case TypeCategory::Character: 183 if (auto len{charLength ? Expr<SubscriptInteger>{Constant<SubscriptInteger>{ 184 *charLength}} 185 : GetCharLength()}) { 186 return Fold(context, 187 Expr<SubscriptInteger>{ 188 context.targetCharacteristics().GetByteSize(category_, kind_)} * 189 std::move(*len)); 190 } 191 break; 192 case TypeCategory::Derived: 193 if (!IsPolymorphic() && derived_ && derived_->scope()) { 194 auto size{derived_->scope()->size()}; 195 auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0}; 196 auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size}; 197 return Expr<SubscriptInteger>{ 198 static_cast<ConstantSubscript>(alignedSize)}; 199 } 200 break; 201 } 202 return std::nullopt; 203 } 204 205 bool DynamicType::IsAssumedLengthCharacter() const { 206 return category_ == TypeCategory::Character && charLengthParamValue_ && 207 charLengthParamValue_->isAssumed(); 208 } 209 210 bool DynamicType::IsNonConstantLengthCharacter() const { 211 if (category_ != TypeCategory::Character) { 212 return false; 213 } else if (knownLength()) { 214 return false; 215 } else if (!charLengthParamValue_) { 216 return true; 217 } else if (const auto &expr{charLengthParamValue_->GetExplicit()}) { 218 return !IsConstantExpr(*expr); 219 } else { 220 return true; 221 } 222 } 223 224 bool DynamicType::IsTypelessIntrinsicArgument() const { 225 return category_ == TypeCategory::Integer && kind_ == TypelessKind; 226 } 227 228 const semantics::DerivedTypeSpec *GetDerivedTypeSpec( 229 const std::optional<DynamicType> &type) { 230 return type ? GetDerivedTypeSpec(*type) : nullptr; 231 } 232 233 const semantics::DerivedTypeSpec *GetDerivedTypeSpec(const DynamicType &type) { 234 if (type.category() == TypeCategory::Derived && 235 !type.IsUnlimitedPolymorphic()) { 236 return &type.GetDerivedTypeSpec(); 237 } else { 238 return nullptr; 239 } 240 } 241 242 static const semantics::Symbol *FindParentComponent( 243 const semantics::DerivedTypeSpec &derived) { 244 const semantics::Symbol &typeSymbol{derived.typeSymbol()}; 245 const semantics::Scope *scope{derived.scope()}; 246 if (!scope) { 247 scope = typeSymbol.scope(); 248 } 249 if (scope) { 250 const auto &dtDetails{typeSymbol.get<semantics::DerivedTypeDetails>()}; 251 // TODO: Combine with semantics::DerivedTypeDetails::GetParentComponent 252 if (auto extends{dtDetails.GetParentComponentName()}) { 253 if (auto iter{scope->find(*extends)}; iter != scope->cend()) { 254 if (const semantics::Symbol & symbol{*iter->second}; 255 symbol.test(semantics::Symbol::Flag::ParentComp)) { 256 return &symbol; 257 } 258 } 259 } 260 } 261 return nullptr; 262 } 263 264 const semantics::DerivedTypeSpec *GetParentTypeSpec( 265 const semantics::DerivedTypeSpec &derived) { 266 if (const semantics::Symbol * parent{FindParentComponent(derived)}) { 267 return &parent->get<semantics::ObjectEntityDetails>() 268 .type() 269 ->derivedTypeSpec(); 270 } else { 271 return nullptr; 272 } 273 } 274 275 // Compares two derived type representations to see whether they both 276 // represent the "same type" in the sense of section 7.5.2.4. 277 using SetOfDerivedTypePairs = 278 std::set<std::pair<const semantics::DerivedTypeSpec *, 279 const semantics::DerivedTypeSpec *>>; 280 281 static bool AreSameComponent(const semantics::Symbol &x, 282 const semantics::Symbol &y, 283 SetOfDerivedTypePairs & /* inProgress - not yet used */) { 284 if (x.attrs() != y.attrs()) { 285 return false; 286 } 287 if (x.attrs().test(semantics::Attr::PRIVATE)) { 288 return false; 289 } 290 // TODO: compare types, parameters, bounds, &c. 291 return x.has<semantics::ObjectEntityDetails>() == 292 y.has<semantics::ObjectEntityDetails>(); 293 } 294 295 // TODO: These utilities were cloned out of Semantics to avoid a cyclic 296 // dependency and should be repackaged into then "namespace semantics" 297 // part of Evaluate/tools.cpp. 298 299 static const semantics::Symbol *GetParentComponent( 300 const semantics::DerivedTypeDetails &details, 301 const semantics::Scope &scope) { 302 if (auto extends{details.GetParentComponentName()}) { 303 if (auto iter{scope.find(*extends)}; iter != scope.cend()) { 304 if (const Symbol & symbol{*iter->second}; 305 symbol.test(semantics::Symbol::Flag::ParentComp)) { 306 return &symbol; 307 } 308 } 309 } 310 return nullptr; 311 } 312 313 static const semantics::Symbol *GetParentComponent( 314 const semantics::Symbol *symbol, const semantics::Scope &scope) { 315 if (symbol) { 316 if (const auto *dtDetails{ 317 symbol->detailsIf<semantics::DerivedTypeDetails>()}) { 318 return GetParentComponent(*dtDetails, scope); 319 } 320 } 321 return nullptr; 322 } 323 324 static const semantics::DerivedTypeSpec *GetParentTypeSpec( 325 const semantics::Symbol *symbol, const semantics::Scope &scope) { 326 if (const Symbol * parentComponent{GetParentComponent(symbol, scope)}) { 327 return &parentComponent->get<semantics::ObjectEntityDetails>() 328 .type() 329 ->derivedTypeSpec(); 330 } else { 331 return nullptr; 332 } 333 } 334 335 static const semantics::Scope *GetDerivedTypeParent( 336 const semantics::Scope *scope) { 337 if (scope) { 338 CHECK(scope->IsDerivedType()); 339 if (const auto *parent{GetParentTypeSpec(scope->GetSymbol(), *scope)}) { 340 return parent->scope(); 341 } 342 } 343 return nullptr; 344 } 345 346 static const semantics::Symbol *FindComponent( 347 const semantics::Scope *scope, parser::CharBlock name) { 348 if (!scope) { 349 return nullptr; 350 } 351 CHECK(scope->IsDerivedType()); 352 auto found{scope->find(name)}; 353 if (found != scope->end()) { 354 return &*found->second; 355 } else { 356 return FindComponent(GetDerivedTypeParent(scope), name); 357 } 358 } 359 360 static bool AreTypeParamCompatible(const semantics::DerivedTypeSpec &x, 361 const semantics::DerivedTypeSpec &y, bool ignoreLenParameters) { 362 const auto *xScope{x.typeSymbol().scope()}; 363 const auto *yScope{y.typeSymbol().scope()}; 364 for (const auto &[paramName, value] : x.parameters()) { 365 const auto *yValue{y.FindParameter(paramName)}; 366 if (!yValue) { 367 return false; 368 } 369 const auto *xParm{FindComponent(xScope, paramName)}; 370 const auto *yParm{FindComponent(yScope, paramName)}; 371 if (xParm && yParm) { 372 const auto *xTPD{xParm->detailsIf<semantics::TypeParamDetails>()}; 373 const auto *yTPD{yParm->detailsIf<semantics::TypeParamDetails>()}; 374 if (xTPD && yTPD) { 375 if (xTPD->attr() != yTPD->attr()) { 376 return false; 377 } 378 if (!ignoreLenParameters || 379 xTPD->attr() != common::TypeParamAttr::Len) { 380 auto xExpr{value.GetExplicit()}; 381 auto yExpr{yValue->GetExplicit()}; 382 if (xExpr && yExpr) { 383 auto xVal{ToInt64(*xExpr)}; 384 auto yVal{ToInt64(*yExpr)}; 385 if (xVal && yVal && *xVal != *yVal) { 386 return false; 387 } 388 } 389 } 390 } 391 } 392 } 393 for (const auto &[paramName, _] : y.parameters()) { 394 if (!x.FindParameter(paramName)) { 395 return false; // y has more parameters than x 396 } 397 } 398 return true; 399 } 400 401 static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x, 402 const semantics::DerivedTypeSpec &y, bool ignoreTypeParameterValues, 403 bool ignoreLenParameters, SetOfDerivedTypePairs &inProgress) { 404 if (&x == &y) { 405 return true; 406 } 407 if (!ignoreTypeParameterValues && 408 !AreTypeParamCompatible(x, y, ignoreLenParameters)) { 409 return false; 410 } 411 const auto &xSymbol{x.typeSymbol()}; 412 const auto &ySymbol{y.typeSymbol()}; 413 if (xSymbol == ySymbol) { 414 return true; 415 } 416 if (xSymbol.name() != ySymbol.name()) { 417 return false; 418 } 419 auto thisQuery{std::make_pair(&x, &y)}; 420 if (inProgress.find(thisQuery) != inProgress.end()) { 421 return true; // recursive use of types in components 422 } 423 inProgress.insert(thisQuery); 424 const auto &xDetails{xSymbol.get<semantics::DerivedTypeDetails>()}; 425 const auto &yDetails{ySymbol.get<semantics::DerivedTypeDetails>()}; 426 if (!(xDetails.sequence() && yDetails.sequence()) && 427 !(xSymbol.attrs().test(semantics::Attr::BIND_C) && 428 ySymbol.attrs().test(semantics::Attr::BIND_C))) { 429 // PGI does not enforce this requirement; all other Fortran 430 // processors do with a hard error when violations are caught. 431 return false; 432 } 433 // Compare the component lists in their orders of declaration. 434 auto xEnd{xDetails.componentNames().cend()}; 435 auto yComponentName{yDetails.componentNames().cbegin()}; 436 auto yEnd{yDetails.componentNames().cend()}; 437 for (auto xComponentName{xDetails.componentNames().cbegin()}; 438 xComponentName != xEnd; ++xComponentName, ++yComponentName) { 439 if (yComponentName == yEnd || *xComponentName != *yComponentName || 440 !xSymbol.scope() || !ySymbol.scope()) { 441 return false; 442 } 443 const auto xLookup{xSymbol.scope()->find(*xComponentName)}; 444 const auto yLookup{ySymbol.scope()->find(*yComponentName)}; 445 if (xLookup == xSymbol.scope()->end() || 446 yLookup == ySymbol.scope()->end() || 447 !AreSameComponent(*xLookup->second, *yLookup->second, inProgress)) { 448 return false; 449 } 450 } 451 return yComponentName == yEnd; 452 } 453 454 bool AreSameDerivedType( 455 const semantics::DerivedTypeSpec &x, const semantics::DerivedTypeSpec &y) { 456 SetOfDerivedTypePairs inProgress; 457 return AreSameDerivedType(x, y, false, false, inProgress); 458 } 459 460 static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x, 461 const semantics::DerivedTypeSpec *y, bool isPolymorphic, 462 bool ignoreTypeParameterValues, bool ignoreLenTypeParameters) { 463 if (!x || !y) { 464 return false; 465 } else { 466 SetOfDerivedTypePairs inProgress; 467 if (AreSameDerivedType(*x, *y, ignoreTypeParameterValues, 468 ignoreLenTypeParameters, inProgress)) { 469 return true; 470 } else { 471 return isPolymorphic && 472 AreCompatibleDerivedTypes(x, GetParentTypeSpec(*y), true, 473 ignoreTypeParameterValues, ignoreLenTypeParameters); 474 } 475 } 476 } 477 478 static bool AreCompatibleTypes(const DynamicType &x, const DynamicType &y, 479 bool ignoreTypeParameterValues, bool ignoreLengths) { 480 if (x.IsUnlimitedPolymorphic()) { 481 return true; 482 } else if (y.IsUnlimitedPolymorphic()) { 483 return false; 484 } else if (x.category() != y.category()) { 485 return false; 486 } else if (x.category() == TypeCategory::Character) { 487 const auto xLen{x.knownLength()}; 488 const auto yLen{y.knownLength()}; 489 return x.kind() == y.kind() && 490 (ignoreLengths || !xLen || !yLen || *xLen == *yLen); 491 } else if (x.category() != TypeCategory::Derived) { 492 return x.kind() == y.kind(); 493 } else { 494 const auto *xdt{GetDerivedTypeSpec(x)}; 495 const auto *ydt{GetDerivedTypeSpec(y)}; 496 return AreCompatibleDerivedTypes( 497 xdt, ydt, x.IsPolymorphic(), ignoreTypeParameterValues, false); 498 } 499 } 500 501 // See 7.3.2.3 (5) & 15.5.2.4 502 bool DynamicType::IsTkCompatibleWith(const DynamicType &that) const { 503 return AreCompatibleTypes(*this, that, false, true); 504 } 505 506 bool DynamicType::IsTkCompatibleWith( 507 const DynamicType &that, common::IgnoreTKRSet ignoreTKR) const { 508 if (ignoreTKR.test(common::IgnoreTKR::Type) && 509 (category() == TypeCategory::Derived || 510 that.category() == TypeCategory::Derived || 511 category() != that.category())) { 512 return true; 513 } else if (ignoreTKR.test(common::IgnoreTKR::Kind) && 514 category() == that.category()) { 515 return true; 516 } else { 517 return AreCompatibleTypes(*this, that, false, true); 518 } 519 } 520 521 bool DynamicType::IsTkLenCompatibleWith(const DynamicType &that) const { 522 return AreCompatibleTypes(*this, that, false, false); 523 } 524 525 // 16.9.165 526 std::optional<bool> DynamicType::SameTypeAs(const DynamicType &that) const { 527 bool x{AreCompatibleTypes(*this, that, true, true)}; 528 bool y{AreCompatibleTypes(that, *this, true, true)}; 529 if (!x && !y) { 530 return false; 531 } else if (x && y && !IsPolymorphic() && !that.IsPolymorphic()) { 532 return true; 533 } else { 534 return std::nullopt; 535 } 536 } 537 538 // 16.9.76 539 std::optional<bool> DynamicType::ExtendsTypeOf(const DynamicType &that) const { 540 if (IsUnlimitedPolymorphic() || that.IsUnlimitedPolymorphic()) { 541 return std::nullopt; // unknown 542 } 543 const auto *thisDts{evaluate::GetDerivedTypeSpec(*this)}; 544 const auto *thatDts{evaluate::GetDerivedTypeSpec(that)}; 545 if (!thisDts || !thatDts) { 546 return std::nullopt; 547 } else if (!AreCompatibleDerivedTypes(thatDts, thisDts, true, true, true)) { 548 // Note that I check *thisDts, not its parent, so that EXTENDS_TYPE_OF() 549 // is .true. when they are the same type. This is technically 550 // an implementation-defined case in the standard, but every other 551 // compiler works this way. 552 if (IsPolymorphic() && 553 AreCompatibleDerivedTypes(thisDts, thatDts, true, true, true)) { 554 // 'that' is *this or an extension of *this, and so runtime *this 555 // could be an extension of 'that' 556 return std::nullopt; 557 } else { 558 return false; 559 } 560 } else if (that.IsPolymorphic()) { 561 return std::nullopt; // unknown 562 } else { 563 return true; 564 } 565 } 566 567 std::optional<DynamicType> DynamicType::From( 568 const semantics::DeclTypeSpec &type) { 569 if (const auto *intrinsic{type.AsIntrinsic()}) { 570 if (auto kind{ToInt64(intrinsic->kind())}) { 571 TypeCategory category{intrinsic->category()}; 572 if (IsValidKindOfIntrinsicType(category, *kind)) { 573 if (category == TypeCategory::Character) { 574 const auto &charType{type.characterTypeSpec()}; 575 return DynamicType{static_cast<int>(*kind), charType.length()}; 576 } else { 577 return DynamicType{category, static_cast<int>(*kind)}; 578 } 579 } 580 } 581 } else if (const auto *derived{type.AsDerived()}) { 582 return DynamicType{ 583 *derived, type.category() == semantics::DeclTypeSpec::ClassDerived}; 584 } else if (type.category() == semantics::DeclTypeSpec::ClassStar) { 585 return DynamicType::UnlimitedPolymorphic(); 586 } else if (type.category() == semantics::DeclTypeSpec::TypeStar) { 587 return DynamicType::AssumedType(); 588 } else { 589 common::die("DynamicType::From(DeclTypeSpec): failed"); 590 } 591 return std::nullopt; 592 } 593 594 std::optional<DynamicType> DynamicType::From(const semantics::Symbol &symbol) { 595 return From(symbol.GetType()); // Symbol -> DeclTypeSpec -> DynamicType 596 } 597 598 DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const { 599 switch (category_) { 600 case TypeCategory::Integer: 601 switch (that.category_) { 602 case TypeCategory::Integer: 603 return DynamicType{TypeCategory::Integer, std::max(kind_, that.kind_)}; 604 case TypeCategory::Real: 605 case TypeCategory::Complex: 606 return that; 607 default: 608 CRASH_NO_CASE; 609 } 610 break; 611 case TypeCategory::Real: 612 switch (that.category_) { 613 case TypeCategory::Integer: 614 return *this; 615 case TypeCategory::Real: 616 return DynamicType{TypeCategory::Real, std::max(kind_, that.kind_)}; 617 case TypeCategory::Complex: 618 return DynamicType{TypeCategory::Complex, std::max(kind_, that.kind_)}; 619 default: 620 CRASH_NO_CASE; 621 } 622 break; 623 case TypeCategory::Complex: 624 switch (that.category_) { 625 case TypeCategory::Integer: 626 return *this; 627 case TypeCategory::Real: 628 case TypeCategory::Complex: 629 return DynamicType{TypeCategory::Complex, std::max(kind_, that.kind_)}; 630 default: 631 CRASH_NO_CASE; 632 } 633 break; 634 case TypeCategory::Logical: 635 switch (that.category_) { 636 case TypeCategory::Logical: 637 return DynamicType{TypeCategory::Logical, std::max(kind_, that.kind_)}; 638 default: 639 CRASH_NO_CASE; 640 } 641 break; 642 default: 643 CRASH_NO_CASE; 644 } 645 return *this; 646 } 647 648 bool DynamicType::RequiresDescriptor() const { 649 return IsPolymorphic() || IsNonConstantLengthCharacter() || 650 (derived_ && CountNonConstantLenParameters(*derived_) > 0); 651 } 652 653 bool DynamicType::HasDeferredTypeParameter() const { 654 if (derived_) { 655 for (const auto &pair : derived_->parameters()) { 656 if (pair.second.isDeferred()) { 657 return true; 658 } 659 } 660 } 661 return charLengthParamValue_ && charLengthParamValue_->isDeferred(); 662 } 663 664 bool SomeKind<TypeCategory::Derived>::operator==( 665 const SomeKind<TypeCategory::Derived> &that) const { 666 return PointeeComparison(derivedTypeSpec_, that.derivedTypeSpec_); 667 } 668 669 int SelectedCharKind(const std::string &s, int defaultKind) { // 16.9.168 670 auto lower{parser::ToLowerCaseLetters(s)}; 671 auto n{lower.size()}; 672 while (n > 0 && lower[0] == ' ') { 673 lower.erase(0, 1); 674 --n; 675 } 676 while (n > 0 && lower[n - 1] == ' ') { 677 lower.erase(--n, 1); 678 } 679 if (lower == "ascii") { 680 return 1; 681 } else if (lower == "ucs-2") { 682 return 2; 683 } else if (lower == "iso_10646" || lower == "ucs-4") { 684 return 4; 685 } else if (lower == "default") { 686 return defaultKind; 687 } else { 688 return -1; 689 } 690 } 691 692 std::optional<DynamicType> ComparisonType( 693 const DynamicType &t1, const DynamicType &t2) { 694 switch (t1.category()) { 695 case TypeCategory::Integer: 696 switch (t2.category()) { 697 case TypeCategory::Integer: 698 return DynamicType{TypeCategory::Integer, std::max(t1.kind(), t2.kind())}; 699 case TypeCategory::Real: 700 case TypeCategory::Complex: 701 return t2; 702 default: 703 return std::nullopt; 704 } 705 case TypeCategory::Real: 706 switch (t2.category()) { 707 case TypeCategory::Integer: 708 return t1; 709 case TypeCategory::Real: 710 case TypeCategory::Complex: 711 return DynamicType{t2.category(), std::max(t1.kind(), t2.kind())}; 712 default: 713 return std::nullopt; 714 } 715 case TypeCategory::Complex: 716 switch (t2.category()) { 717 case TypeCategory::Integer: 718 return t1; 719 case TypeCategory::Real: 720 case TypeCategory::Complex: 721 return DynamicType{TypeCategory::Complex, std::max(t1.kind(), t2.kind())}; 722 default: 723 return std::nullopt; 724 } 725 case TypeCategory::Character: 726 switch (t2.category()) { 727 case TypeCategory::Character: 728 return DynamicType{ 729 TypeCategory::Character, std::max(t1.kind(), t2.kind())}; 730 default: 731 return std::nullopt; 732 } 733 case TypeCategory::Logical: 734 switch (t2.category()) { 735 case TypeCategory::Logical: 736 return DynamicType{TypeCategory::Logical, LogicalResult::kind}; 737 default: 738 return std::nullopt; 739 } 740 default: 741 return std::nullopt; 742 } 743 } 744 745 bool IsInteroperableIntrinsicType(const DynamicType &type) { 746 switch (type.category()) { 747 case TypeCategory::Integer: 748 return true; 749 case TypeCategory::Real: 750 case TypeCategory::Complex: 751 return type.kind() >= 4; // no short or half floats 752 case TypeCategory::Logical: 753 return type.kind() == 1; // C_BOOL 754 case TypeCategory::Character: 755 return type.kind() == 1 /* C_CHAR */ && type.knownLength().value_or(0) == 1; 756 default: 757 // Derived types are tested in Semantics/check-declarations.cpp 758 return false; 759 } 760 } 761 762 } // namespace Fortran::evaluate 763