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