xref: /llvm-project/flang/lib/Evaluate/call.cpp (revision ae0d1d2e5cd3a99da0b2eefc27c8f94b95f03cc6)
1 //===-- lib/Evaluate/call.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/call.h"
10 #include "flang/Common/Fortran.h"
11 #include "flang/Common/idioms.h"
12 #include "flang/Evaluate/characteristics.h"
13 #include "flang/Evaluate/expression.h"
14 #include "flang/Evaluate/tools.h"
15 #include "flang/Semantics/symbol.h"
16 
17 namespace Fortran::evaluate {
18 
19 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)
20 ActualArgument::ActualArgument(Expr<SomeType> &&x) : u_{std::move(x)} {}
21 ActualArgument::ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v)
22     : u_{std::move(v)} {}
23 ActualArgument::ActualArgument(AssumedType x) : u_{x} {}
24 ActualArgument::ActualArgument(common::Label x) : u_{x} {}
25 ActualArgument::~ActualArgument() {}
26 
27 ActualArgument::AssumedType::AssumedType(const Symbol &symbol)
28     : symbol_{symbol} {
29   const semantics::DeclTypeSpec *type{symbol.GetType()};
30   CHECK(type && type->category() == semantics::DeclTypeSpec::TypeStar);
31 }
32 
33 int ActualArgument::AssumedType::Rank() const { return symbol_->Rank(); }
34 
35 ActualArgument &ActualArgument::operator=(Expr<SomeType> &&expr) {
36   u_ = std::move(expr);
37   return *this;
38 }
39 
40 std::optional<DynamicType> ActualArgument::GetType() const {
41   if (const Expr<SomeType> *expr{UnwrapExpr()}) {
42     return expr->GetType();
43   } else if (std::holds_alternative<AssumedType>(u_)) {
44     return DynamicType::AssumedType();
45   } else {
46     return std::nullopt;
47   }
48 }
49 
50 int ActualArgument::Rank() const {
51   if (const Expr<SomeType> *expr{UnwrapExpr()}) {
52     return expr->Rank();
53   } else {
54     return std::get<AssumedType>(u_).Rank();
55   }
56 }
57 
58 bool ActualArgument::operator==(const ActualArgument &that) const {
59   return keyword_ == that.keyword_ && isPassedObject_ == that.isPassedObject_ &&
60       u_ == that.u_;
61 }
62 
63 void ActualArgument::Parenthesize() {
64   u_ = evaluate::Parenthesize(std::move(DEREF(UnwrapExpr())));
65 }
66 
67 SpecificIntrinsic::SpecificIntrinsic(
68     IntrinsicProcedure n, characteristics::Procedure &&chars)
69     : name{n}, characteristics{
70                    new characteristics::Procedure{std::move(chars)}} {}
71 
72 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)
73 
74 SpecificIntrinsic::~SpecificIntrinsic() {}
75 
76 bool SpecificIntrinsic::operator==(const SpecificIntrinsic &that) const {
77   return name == that.name && characteristics == that.characteristics;
78 }
79 
80 ProcedureDesignator::ProcedureDesignator(Component &&c)
81     : u{common::CopyableIndirection<Component>::Make(std::move(c))} {}
82 
83 bool ProcedureDesignator::operator==(const ProcedureDesignator &that) const {
84   return u == that.u;
85 }
86 
87 std::optional<DynamicType> ProcedureDesignator::GetType() const {
88   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
89     if (const auto &result{intrinsic->characteristics.value().functionResult}) {
90       if (const auto *typeAndShape{result->GetTypeAndShape()}) {
91         return typeAndShape->type();
92       }
93     }
94   } else {
95     return DynamicType::From(GetSymbol());
96   }
97   return std::nullopt;
98 }
99 
100 int ProcedureDesignator::Rank() const {
101   if (const Symbol * symbol{GetSymbol()}) {
102     // Subtle: will be zero for functions returning procedure pointers
103     return symbol->Rank();
104   }
105   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
106     if (const auto &result{intrinsic->characteristics.value().functionResult}) {
107       if (const auto *typeAndShape{result->GetTypeAndShape()}) {
108         CHECK(!typeAndShape->attrs().test(
109             characteristics::TypeAndShape::Attr::AssumedRank));
110         return typeAndShape->Rank();
111       }
112       // Otherwise, intrinsic returns a procedure pointer (e.g. NULL(MOLD=pptr))
113     }
114   }
115   return 0;
116 }
117 
118 const Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
119   if (const Symbol * symbol{GetSymbol()}) {
120     if (const auto *details{
121             symbol->detailsIf<semantics::ProcEntityDetails>()}) {
122       return details->interface().symbol();
123     }
124   }
125   return nullptr;
126 }
127 
128 bool ProcedureDesignator::IsElemental() const {
129   if (const Symbol * interface{GetInterfaceSymbol()}) {
130     return interface->attrs().test(semantics::Attr::ELEMENTAL);
131   } else if (const Symbol * symbol{GetSymbol()}) {
132     return symbol->attrs().test(semantics::Attr::ELEMENTAL);
133   } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
134     return intrinsic->characteristics.value().attrs.test(
135         characteristics::Procedure::Attr::Elemental);
136   } else {
137     DIE("ProcedureDesignator::IsElemental(): no case");
138   }
139   return false;
140 }
141 
142 const SpecificIntrinsic *ProcedureDesignator::GetSpecificIntrinsic() const {
143   return std::get_if<SpecificIntrinsic>(&u);
144 }
145 
146 const Component *ProcedureDesignator::GetComponent() const {
147   if (auto *c{std::get_if<common::CopyableIndirection<Component>>(&u)}) {
148     return &c->value();
149   } else {
150     return nullptr;
151   }
152 }
153 
154 const Symbol *ProcedureDesignator::GetSymbol() const {
155   return std::visit(common::visitors{
156                         [](SymbolRef symbol) { return &*symbol; },
157                         [](const common::CopyableIndirection<Component> &c) {
158                           return &c.value().GetLastSymbol();
159                         },
160                         [](const auto &) -> const Symbol * { return nullptr; },
161                     },
162       u);
163 }
164 
165 std::string ProcedureDesignator::GetName() const {
166   return std::visit(
167       common::visitors{
168           [](const SpecificIntrinsic &i) { return i.name; },
169           [](const Symbol &symbol) { return symbol.name().ToString(); },
170           [](const common::CopyableIndirection<Component> &c) {
171             return c.value().GetLastSymbol().name().ToString();
172           },
173       },
174       u);
175 }
176 
177 std::optional<Expr<SubscriptInteger>> ProcedureRef::LEN() const {
178   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc_.u)}) {
179     if (intrinsic->name == "repeat") {
180       // LEN(REPEAT(ch,n)) == LEN(ch) * n
181       CHECK(arguments_.size() == 2);
182       const auto *stringArg{
183           UnwrapExpr<Expr<SomeCharacter>>(arguments_[0].value())};
184       const auto *nCopiesArg{
185           UnwrapExpr<Expr<SomeInteger>>(arguments_[1].value())};
186       CHECK(stringArg && nCopiesArg);
187       if (auto stringLen{stringArg->LEN()}) {
188         auto converted{ConvertTo(*stringLen, common::Clone(*nCopiesArg))};
189         return *std::move(stringLen) * std::move(converted);
190       }
191     }
192     // Some other cases (e.g., LEN(CHAR(...))) are handled in
193     // ProcedureDesignator::LEN() because they're independent of the
194     // lengths of the actual arguments.
195   }
196   return proc_.LEN();
197 }
198 
199 int ProcedureRef::Rank() const {
200   if (IsElemental()) {
201     for (const auto &arg : arguments_) {
202       if (arg) {
203         if (int rank{arg->Rank()}; rank > 0) {
204           return rank;
205         }
206       }
207     }
208     return 0;
209   } else {
210     return proc_.Rank();
211   }
212 }
213 
214 ProcedureRef::~ProcedureRef() {}
215 
216 void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
217 
218 FOR_EACH_SPECIFIC_TYPE(template class FunctionRef, )
219 } // namespace Fortran::evaluate
220