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