xref: /llvm-project/flang/lib/Evaluate/call.cpp (revision 0a10e88915167c88443dd58883e01d543963e40e)
164ab3302SCarolineConcatto //===-- lib/Evaluate/call.cpp ---------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Evaluate/call.h"
10ae0d1d2eSPeter Steinfeld #include "flang/Common/Fortran.h"
1164ab3302SCarolineConcatto #include "flang/Common/idioms.h"
1264ab3302SCarolineConcatto #include "flang/Evaluate/characteristics.h"
13b70f507cSPeter Klausler #include "flang/Evaluate/check-expression.h"
1464ab3302SCarolineConcatto #include "flang/Evaluate/expression.h"
1564ab3302SCarolineConcatto #include "flang/Evaluate/tools.h"
1664ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto namespace Fortran::evaluate {
1964ab3302SCarolineConcatto 
DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)2064ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)
2164ab3302SCarolineConcatto ActualArgument::ActualArgument(Expr<SomeType> &&x) : u_{std::move(x)} {}
ActualArgument(common::CopyableIndirection<Expr<SomeType>> && v)2264ab3302SCarolineConcatto ActualArgument::ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v)
2364ab3302SCarolineConcatto     : u_{std::move(v)} {}
ActualArgument(AssumedType x)2464ab3302SCarolineConcatto ActualArgument::ActualArgument(AssumedType x) : u_{x} {}
ActualArgument(common::Label x)25ae0d1d2eSPeter Steinfeld ActualArgument::ActualArgument(common::Label x) : u_{x} {}
~ActualArgument()2664ab3302SCarolineConcatto ActualArgument::~ActualArgument() {}
2764ab3302SCarolineConcatto 
AssumedType(const Symbol & symbol)2864ab3302SCarolineConcatto ActualArgument::AssumedType::AssumedType(const Symbol &symbol)
2964ab3302SCarolineConcatto     : symbol_{symbol} {
3064ab3302SCarolineConcatto   const semantics::DeclTypeSpec *type{symbol.GetType()};
3164ab3302SCarolineConcatto   CHECK(type && type->category() == semantics::DeclTypeSpec::TypeStar);
3264ab3302SCarolineConcatto }
3364ab3302SCarolineConcatto 
Rank() const3464ab3302SCarolineConcatto int ActualArgument::AssumedType::Rank() const { return symbol_->Rank(); }
3564ab3302SCarolineConcatto 
operator =(Expr<SomeType> && expr)3664ab3302SCarolineConcatto ActualArgument &ActualArgument::operator=(Expr<SomeType> &&expr) {
3764ab3302SCarolineConcatto   u_ = std::move(expr);
3864ab3302SCarolineConcatto   return *this;
3964ab3302SCarolineConcatto }
4064ab3302SCarolineConcatto 
GetType() const4164ab3302SCarolineConcatto std::optional<DynamicType> ActualArgument::GetType() const {
4264ab3302SCarolineConcatto   if (const Expr<SomeType> *expr{UnwrapExpr()}) {
4364ab3302SCarolineConcatto     return expr->GetType();
4464ab3302SCarolineConcatto   } else if (std::holds_alternative<AssumedType>(u_)) {
4564ab3302SCarolineConcatto     return DynamicType::AssumedType();
4664ab3302SCarolineConcatto   } else {
4764ab3302SCarolineConcatto     return std::nullopt;
4864ab3302SCarolineConcatto   }
4964ab3302SCarolineConcatto }
5064ab3302SCarolineConcatto 
Rank() const5164ab3302SCarolineConcatto int ActualArgument::Rank() const {
5264ab3302SCarolineConcatto   if (const Expr<SomeType> *expr{UnwrapExpr()}) {
5364ab3302SCarolineConcatto     return expr->Rank();
5464ab3302SCarolineConcatto   } else {
5564ab3302SCarolineConcatto     return std::get<AssumedType>(u_).Rank();
5664ab3302SCarolineConcatto   }
5764ab3302SCarolineConcatto }
5864ab3302SCarolineConcatto 
operator ==(const ActualArgument & that) const5964ab3302SCarolineConcatto bool ActualArgument::operator==(const ActualArgument &that) const {
60*0a10e889SjeanPerier   return keyword_ == that.keyword_ && attrs_ == that.attrs_ && u_ == that.u_;
6164ab3302SCarolineConcatto }
6264ab3302SCarolineConcatto 
Parenthesize()6364ab3302SCarolineConcatto void ActualArgument::Parenthesize() {
6464ab3302SCarolineConcatto   u_ = evaluate::Parenthesize(std::move(DEREF(UnwrapExpr())));
6564ab3302SCarolineConcatto }
6664ab3302SCarolineConcatto 
SpecificIntrinsic(IntrinsicProcedure n,characteristics::Procedure && chars)6764ab3302SCarolineConcatto SpecificIntrinsic::SpecificIntrinsic(
6864ab3302SCarolineConcatto     IntrinsicProcedure n, characteristics::Procedure &&chars)
691f879005STim Keith     : name{n}, characteristics{
701f879005STim Keith                    new characteristics::Procedure{std::move(chars)}} {}
7164ab3302SCarolineConcatto 
DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)7264ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)
7364ab3302SCarolineConcatto 
7464ab3302SCarolineConcatto SpecificIntrinsic::~SpecificIntrinsic() {}
7564ab3302SCarolineConcatto 
operator ==(const SpecificIntrinsic & that) const7664ab3302SCarolineConcatto bool SpecificIntrinsic::operator==(const SpecificIntrinsic &that) const {
7764ab3302SCarolineConcatto   return name == that.name && characteristics == that.characteristics;
7864ab3302SCarolineConcatto }
7964ab3302SCarolineConcatto 
ProcedureDesignator(Component && c)8064ab3302SCarolineConcatto ProcedureDesignator::ProcedureDesignator(Component &&c)
8164ab3302SCarolineConcatto     : u{common::CopyableIndirection<Component>::Make(std::move(c))} {}
8264ab3302SCarolineConcatto 
operator ==(const ProcedureDesignator & that) const83e03b20e6Speter klausler bool ProcedureDesignator::operator==(const ProcedureDesignator &that) const {
84e03b20e6Speter klausler   return u == that.u;
85e03b20e6Speter klausler }
86e03b20e6Speter klausler 
GetType() const8764ab3302SCarolineConcatto std::optional<DynamicType> ProcedureDesignator::GetType() const {
8864ab3302SCarolineConcatto   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
8964ab3302SCarolineConcatto     if (const auto &result{intrinsic->characteristics.value().functionResult}) {
9064ab3302SCarolineConcatto       if (const auto *typeAndShape{result->GetTypeAndShape()}) {
9164ab3302SCarolineConcatto         return typeAndShape->type();
9264ab3302SCarolineConcatto       }
9364ab3302SCarolineConcatto     }
9464ab3302SCarolineConcatto   } else {
9564ab3302SCarolineConcatto     return DynamicType::From(GetSymbol());
9664ab3302SCarolineConcatto   }
9764ab3302SCarolineConcatto   return std::nullopt;
9864ab3302SCarolineConcatto }
9964ab3302SCarolineConcatto 
Rank() const10064ab3302SCarolineConcatto int ProcedureDesignator::Rank() const {
10164ab3302SCarolineConcatto   if (const Symbol * symbol{GetSymbol()}) {
1024171f80dSpeter klausler     // Subtle: will be zero for functions returning procedure pointers
10364ab3302SCarolineConcatto     return symbol->Rank();
10464ab3302SCarolineConcatto   }
10564ab3302SCarolineConcatto   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
10664ab3302SCarolineConcatto     if (const auto &result{intrinsic->characteristics.value().functionResult}) {
10764ab3302SCarolineConcatto       if (const auto *typeAndShape{result->GetTypeAndShape()}) {
10864ab3302SCarolineConcatto         CHECK(!typeAndShape->attrs().test(
10964ab3302SCarolineConcatto             characteristics::TypeAndShape::Attr::AssumedRank));
11064ab3302SCarolineConcatto         return typeAndShape->Rank();
11164ab3302SCarolineConcatto       }
1124171f80dSpeter klausler       // Otherwise, intrinsic returns a procedure pointer (e.g. NULL(MOLD=pptr))
11364ab3302SCarolineConcatto     }
11464ab3302SCarolineConcatto   }
11564ab3302SCarolineConcatto   return 0;
11664ab3302SCarolineConcatto }
11764ab3302SCarolineConcatto 
GetInterfaceSymbol() const11864ab3302SCarolineConcatto const Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
11964ab3302SCarolineConcatto   if (const Symbol * symbol{GetSymbol()}) {
1202de5ea3bSpeter klausler     const Symbol &ultimate{symbol->GetUltimate()};
1212de5ea3bSpeter klausler     if (const auto *proc{ultimate.detailsIf<semantics::ProcEntityDetails>()}) {
122635656f4SPeter Klausler       return proc->procInterface();
1232de5ea3bSpeter klausler     } else if (const auto *binding{
1242de5ea3bSpeter klausler                    ultimate.detailsIf<semantics::ProcBindingDetails>()}) {
1252de5ea3bSpeter klausler       return &binding->symbol();
126962e503cSJean Perier     } else if (ultimate.has<semantics::SubprogramDetails>()) {
127962e503cSJean Perier       return &ultimate;
12864ab3302SCarolineConcatto     }
12964ab3302SCarolineConcatto   }
13064ab3302SCarolineConcatto   return nullptr;
13164ab3302SCarolineConcatto }
13264ab3302SCarolineConcatto 
IsElemental() const13364ab3302SCarolineConcatto bool ProcedureDesignator::IsElemental() const {
13464ab3302SCarolineConcatto   if (const Symbol * interface{GetInterfaceSymbol()}) {
1356052025bSPeter Klausler     return IsElementalProcedure(*interface);
13664ab3302SCarolineConcatto   } else if (const Symbol * symbol{GetSymbol()}) {
1376052025bSPeter Klausler     return IsElementalProcedure(*symbol);
13864ab3302SCarolineConcatto   } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
13964ab3302SCarolineConcatto     return intrinsic->characteristics.value().attrs.test(
14064ab3302SCarolineConcatto         characteristics::Procedure::Attr::Elemental);
14164ab3302SCarolineConcatto   } else {
14264ab3302SCarolineConcatto     DIE("ProcedureDesignator::IsElemental(): no case");
14364ab3302SCarolineConcatto   }
14464ab3302SCarolineConcatto   return false;
14564ab3302SCarolineConcatto }
14664ab3302SCarolineConcatto 
IsPure() const1473f10091cSPeter Klausler bool ProcedureDesignator::IsPure() const {
1483f10091cSPeter Klausler   if (const Symbol * interface{GetInterfaceSymbol()}) {
1493f10091cSPeter Klausler     return IsPureProcedure(*interface);
1503f10091cSPeter Klausler   } else if (const Symbol * symbol{GetSymbol()}) {
1513f10091cSPeter Klausler     return IsPureProcedure(*symbol);
1523f10091cSPeter Klausler   } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
1533f10091cSPeter Klausler     return intrinsic->characteristics.value().attrs.test(
1543f10091cSPeter Klausler         characteristics::Procedure::Attr::Pure);
1553f10091cSPeter Klausler   } else {
1563f10091cSPeter Klausler     DIE("ProcedureDesignator::IsPure(): no case");
1573f10091cSPeter Klausler   }
1583f10091cSPeter Klausler   return false;
1593f10091cSPeter Klausler }
1603f10091cSPeter Klausler 
GetSpecificIntrinsic() const16164ab3302SCarolineConcatto const SpecificIntrinsic *ProcedureDesignator::GetSpecificIntrinsic() const {
16264ab3302SCarolineConcatto   return std::get_if<SpecificIntrinsic>(&u);
16364ab3302SCarolineConcatto }
16464ab3302SCarolineConcatto 
GetComponent() const16564ab3302SCarolineConcatto const Component *ProcedureDesignator::GetComponent() const {
16664ab3302SCarolineConcatto   if (auto *c{std::get_if<common::CopyableIndirection<Component>>(&u)}) {
16764ab3302SCarolineConcatto     return &c->value();
16864ab3302SCarolineConcatto   } else {
16964ab3302SCarolineConcatto     return nullptr;
17064ab3302SCarolineConcatto   }
17164ab3302SCarolineConcatto }
17264ab3302SCarolineConcatto 
GetSymbol() const17364ab3302SCarolineConcatto const Symbol *ProcedureDesignator::GetSymbol() const {
174cd03e96fSPeter Klausler   return common::visit(
175cd03e96fSPeter Klausler       common::visitors{
17664ab3302SCarolineConcatto           [](SymbolRef symbol) { return &*symbol; },
17764ab3302SCarolineConcatto           [](const common::CopyableIndirection<Component> &c) {
17864ab3302SCarolineConcatto             return &c.value().GetLastSymbol();
17964ab3302SCarolineConcatto           },
18064ab3302SCarolineConcatto           [](const auto &) -> const Symbol * { return nullptr; },
18164ab3302SCarolineConcatto       },
18264ab3302SCarolineConcatto       u);
18364ab3302SCarolineConcatto }
18464ab3302SCarolineConcatto 
UnwrapSymbolRef() const1859e855a6cSPeter Klausler const SymbolRef *ProcedureDesignator::UnwrapSymbolRef() const {
1869e855a6cSPeter Klausler   return std::get_if<SymbolRef>(&u);
1879e855a6cSPeter Klausler }
1889e855a6cSPeter Klausler 
GetName() const18964ab3302SCarolineConcatto std::string ProcedureDesignator::GetName() const {
190cd03e96fSPeter Klausler   return common::visit(
19164ab3302SCarolineConcatto       common::visitors{
19264ab3302SCarolineConcatto           [](const SpecificIntrinsic &i) { return i.name; },
19364ab3302SCarolineConcatto           [](const Symbol &symbol) { return symbol.name().ToString(); },
19464ab3302SCarolineConcatto           [](const common::CopyableIndirection<Component> &c) {
19564ab3302SCarolineConcatto             return c.value().GetLastSymbol().name().ToString();
19664ab3302SCarolineConcatto           },
19764ab3302SCarolineConcatto       },
19864ab3302SCarolineConcatto       u);
19964ab3302SCarolineConcatto }
20064ab3302SCarolineConcatto 
LEN() const20164ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> ProcedureRef::LEN() const {
20264ab3302SCarolineConcatto   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc_.u)}) {
20364ab3302SCarolineConcatto     if (intrinsic->name == "repeat") {
20464ab3302SCarolineConcatto       // LEN(REPEAT(ch,n)) == LEN(ch) * n
20564ab3302SCarolineConcatto       CHECK(arguments_.size() == 2);
20664ab3302SCarolineConcatto       const auto *stringArg{
20764ab3302SCarolineConcatto           UnwrapExpr<Expr<SomeCharacter>>(arguments_[0].value())};
20864ab3302SCarolineConcatto       const auto *nCopiesArg{
20964ab3302SCarolineConcatto           UnwrapExpr<Expr<SomeInteger>>(arguments_[1].value())};
21064ab3302SCarolineConcatto       CHECK(stringArg && nCopiesArg);
21164ab3302SCarolineConcatto       if (auto stringLen{stringArg->LEN()}) {
21264ab3302SCarolineConcatto         auto converted{ConvertTo(*stringLen, common::Clone(*nCopiesArg))};
21364ab3302SCarolineConcatto         return *std::move(stringLen) * std::move(converted);
21464ab3302SCarolineConcatto       }
21564ab3302SCarolineConcatto     }
21664ab3302SCarolineConcatto     // Some other cases (e.g., LEN(CHAR(...))) are handled in
21764ab3302SCarolineConcatto     // ProcedureDesignator::LEN() because they're independent of the
21864ab3302SCarolineConcatto     // lengths of the actual arguments.
21964ab3302SCarolineConcatto   }
220b70f507cSPeter Klausler   if (auto len{proc_.LEN()}) {
221b70f507cSPeter Klausler     if (IsActuallyConstant(*len)) {
222b70f507cSPeter Klausler       return len;
223b70f507cSPeter Klausler     }
224b70f507cSPeter Klausler     // TODO: Handle cases where the length of a function result is a
225b70f507cSPeter Klausler     // safe expression in terms of actual argument values, after substituting
226b70f507cSPeter Klausler     // actual argument expressions for INTENT(IN)/VALUE dummy arguments.
227b70f507cSPeter Klausler   }
228b70f507cSPeter Klausler   return std::nullopt;
22964ab3302SCarolineConcatto }
23064ab3302SCarolineConcatto 
Rank() const23164ab3302SCarolineConcatto int ProcedureRef::Rank() const {
23264ab3302SCarolineConcatto   if (IsElemental()) {
23364ab3302SCarolineConcatto     for (const auto &arg : arguments_) {
23464ab3302SCarolineConcatto       if (arg) {
23564ab3302SCarolineConcatto         if (int rank{arg->Rank()}; rank > 0) {
23664ab3302SCarolineConcatto           return rank;
23764ab3302SCarolineConcatto         }
23864ab3302SCarolineConcatto       }
23964ab3302SCarolineConcatto     }
24064ab3302SCarolineConcatto     return 0;
24164ab3302SCarolineConcatto   } else {
24264ab3302SCarolineConcatto     return proc_.Rank();
24364ab3302SCarolineConcatto   }
24464ab3302SCarolineConcatto }
24564ab3302SCarolineConcatto 
~ProcedureRef()24664ab3302SCarolineConcatto ProcedureRef::~ProcedureRef() {}
24764ab3302SCarolineConcatto 
Deleter(ProcedureRef * p)2488a8bb078Speter klausler void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
2498a8bb078Speter klausler 
2501f879005STim Keith } // namespace Fortran::evaluate
251