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