FLANG

type.h
1 //===-- include/flang/Semantics/type.h --------------------------*- C++ -*-===//
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 #ifndef FORTRAN_SEMANTICS_TYPE_H_
10 #define FORTRAN_SEMANTICS_TYPE_H_
11
12 #include "flang/Common/Fortran.h"
13 #include "flang/Common/idioms.h"
14 #include "flang/Evaluate/expression.h"
15 #include "flang/Parser/char-block.h"
16 #include <algorithm>
17 #include <iosfwd>
18 #include <map>
19 #include <optional>
20 #include <string>
21 #include <variant>
22 #include <vector>
23
24 namespace llvm {
25 class raw_ostream;
26 }
27
28 namespace Fortran::parser {
29 struct Keyword;
30 }
31
32 namespace Fortran::semantics {
33
34 class Scope;
35 class SemanticsContext;
36 class Symbol;
37
40 using SourceName = parser::CharBlock;
41 using TypeCategory = common::TypeCategory;
42 using SomeExpr = evaluate::Expr<evaluate::SomeType>;
43 using MaybeExpr = std::optional<SomeExpr>;
44 using SomeIntExpr = evaluate::Expr<evaluate::SomeInteger>;
45 using MaybeIntExpr = std::optional<SomeIntExpr>;
46 using SubscriptIntExpr = evaluate::Expr<evaluate::SubscriptInteger>;
47 using MaybeSubscriptIntExpr = std::optional<SubscriptIntExpr>;
48 using KindExpr = SubscriptIntExpr;
49
50 // An array spec bound: an explicit integer expression or ASSUMED or DEFERRED
51 class Bound {
52 public:
53 static Bound Assumed() { return Bound(Category::Assumed); }
54 static Bound Deferred() { return Bound(Category::Deferred); }
55 explicit Bound(MaybeSubscriptIntExpr &&expr) : expr_{std::move(expr)} {}
56 explicit Bound(int bound);
57 Bound(const Bound &) = default;
58 Bound(Bound &&) = default;
59 Bound &operator=(const Bound &) = default;
60 Bound &operator=(Bound &&) = default;
61 bool isExplicit() const { return category_ == Category::Explicit; }
62 bool isAssumed() const { return category_ == Category::Assumed; }
63 bool isDeferred() const { return category_ == Category::Deferred; }
64 MaybeSubscriptIntExpr &GetExplicit() { return expr_; }
65 const MaybeSubscriptIntExpr &GetExplicit() const { return expr_; }
66 void SetExplicit(MaybeSubscriptIntExpr &&expr) {
67 CHECK(isExplicit());
68 expr_ = std::move(expr);
69 }
70
71 private:
72 enum class Category { Explicit, Deferred, Assumed };
73 Bound(Category category) : category_{category} {}
74 Bound(Category category, MaybeSubscriptIntExpr &&expr)
75 : category_{category}, expr_{std::move(expr)} {}
76 Category category_{Category::Explicit};
77 MaybeSubscriptIntExpr expr_;
78 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Bound &);
79 };
80
81 // A type parameter value: integer expression or assumed or deferred.
82 class ParamValue {
83 public:
84 static ParamValue Assumed(common::TypeParamAttr attr) {
85 return ParamValue{Category::Assumed, attr};
86 }
87 static ParamValue Deferred(common::TypeParamAttr attr) {
88 return ParamValue{Category::Deferred, attr};
89 }
90 ParamValue(const ParamValue &) = default;
91 explicit ParamValue(MaybeIntExpr &&, common::TypeParamAttr);
92 explicit ParamValue(SomeIntExpr &&, common::TypeParamAttr attr);
93 explicit ParamValue(common::ConstantSubscript, common::TypeParamAttr attr);
94 bool isExplicit() const { return category_ == Category::Explicit; }
95 bool isAssumed() const { return category_ == Category::Assumed; }
96 bool isDeferred() const { return category_ == Category::Deferred; }
97 const MaybeIntExpr &GetExplicit() const { return expr_; }
98 void SetExplicit(SomeIntExpr &&);
99 bool isKind() const { return attr_ == common::TypeParamAttr::Kind; }
100 bool isLen() const { return attr_ == common::TypeParamAttr::Len; }
101 void set_attr(common::TypeParamAttr attr) { attr_ = attr; }
102 bool operator==(const ParamValue &that) const {
103 return category_ == that.category_ && expr_ == that.expr_;
104 }
105 std::string AsFortran() const;
106
107 private:
108 enum class Category { Explicit, Deferred, Assumed };
109 ParamValue(Category category, common::TypeParamAttr attr)
110 : category_{category}, attr_{attr} {}
111 Category category_{Category::Explicit};
112 common::TypeParamAttr attr_{common::TypeParamAttr::Kind};
113 MaybeIntExpr expr_;
114 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ParamValue &);
115 };
116
117 class IntrinsicTypeSpec {
118 public:
119 TypeCategory category() const { return category_; }
120 const KindExpr &kind() const { return kind_; }
121 bool operator==(const IntrinsicTypeSpec &x) const {
122 return category_ == x.category_ && kind_ == x.kind_;
123 }
124 bool operator!=(const IntrinsicTypeSpec &x) const { return !operator==(x); }
125 std::string AsFortran() const;
126
127 protected:
128 IntrinsicTypeSpec(TypeCategory, KindExpr &&);
129
130 private:
131 TypeCategory category_;
132 KindExpr kind_;
133 friend llvm::raw_ostream &operator<<(
134 llvm::raw_ostream &os, const IntrinsicTypeSpec &x);
135 };
136
137 class NumericTypeSpec : public IntrinsicTypeSpec {
138 public:
139 NumericTypeSpec(TypeCategory category, KindExpr &&kind)
140 : IntrinsicTypeSpec(category, std::move(kind)) {
141 CHECK(common::IsNumericTypeCategory(category));
142 }
143 };
144
145 class LogicalTypeSpec : public IntrinsicTypeSpec {
146 public:
147 explicit LogicalTypeSpec(KindExpr &&kind)
148 : IntrinsicTypeSpec(TypeCategory::Logical, std::move(kind)) {}
149 };
150
151 class CharacterTypeSpec : public IntrinsicTypeSpec {
152 public:
153 CharacterTypeSpec(ParamValue &&length, KindExpr &&kind)
154 : IntrinsicTypeSpec(TypeCategory::Character, std::move(kind)),
155 length_{std::move(length)} {}
156 const ParamValue &length() const { return length_; }
157 std::string AsFortran() const;
158
159 private:
160 ParamValue length_;
161 friend llvm::raw_ostream &operator<<(
162 llvm::raw_ostream &os, const CharacterTypeSpec &x);
163 };
164
165 class ShapeSpec {
166 public:
167 // lb:ub
168 static ShapeSpec MakeExplicit(Bound &&lb, Bound &&ub) {
169 return ShapeSpec(std::move(lb), std::move(ub));
170 }
171 // 1:ub
172 static const ShapeSpec MakeExplicit(Bound &&ub) {
173 return MakeExplicit(Bound{1}, std::move(ub));
174 }
175 // 1:
176 static ShapeSpec MakeAssumed() {
177 return ShapeSpec(Bound{1}, Bound::Deferred());
178 }
179 // lb:
180 static ShapeSpec MakeAssumed(Bound &&lb) {
181 return ShapeSpec(std::move(lb), Bound::Deferred());
182 }
183 // :
184 static ShapeSpec MakeDeferred() {
185 return ShapeSpec(Bound::Deferred(), Bound::Deferred());
186 }
187 // 1:*
188 static ShapeSpec MakeImplied() {
189 return ShapeSpec(Bound{1}, Bound::Assumed());
190 }
191 // lb:*
192 static ShapeSpec MakeImplied(Bound &&lb) {
193 return ShapeSpec(std::move(lb), Bound::Assumed());
194 }
195 // ..
196 static ShapeSpec MakeAssumedRank() {
197 return ShapeSpec(Bound::Assumed(), Bound::Assumed());
198 }
199
200 ShapeSpec(const ShapeSpec &) = default;
201 ShapeSpec(ShapeSpec &&) = default;
202 ShapeSpec &operator=(const ShapeSpec &) = default;
203 ShapeSpec &operator=(ShapeSpec &&) = default;
204
205 Bound &lbound() { return lb_; }
206 const Bound &lbound() const { return lb_; }
207 Bound &ubound() { return ub_; }
208 const Bound &ubound() const { return ub_; }
209
210 private:
211 ShapeSpec(Bound &&lb, Bound &&ub) : lb_{std::move(lb)}, ub_{std::move(ub)} {}
212 Bound lb_;
213 Bound ub_;
214 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ShapeSpec &);
215 };
216
217 struct ArraySpec : public std::vector<ShapeSpec> {
218 ArraySpec() {}
219 int Rank() const { return size(); }
220 inline bool IsExplicitShape() const;
221 inline bool IsAssumedShape() const;
222 inline bool IsDeferredShape() const;
223 inline bool IsImpliedShape() const;
224 inline bool IsAssumedSize() const;
225 inline bool IsAssumedRank() const;
226
227 private:
228 // Check non-empty and predicate is true for each element.
229 template <typename P> bool CheckAll(P predicate) const {
230 return !empty() && std::all_of(begin(), end(), predicate);
231 }
232 };
233 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArraySpec &);
234
235 // Each DerivedTypeSpec has a typeSymbol that has DerivedTypeDetails.
236 // The name may not match the symbol's name in case of a USE rename.
237 class DerivedTypeSpec {
238 public:
239 using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
240 using RawParameters = std::vector<RawParameter>;
241 using ParameterMapType = std::map<SourceName, ParamValue>;
242 DerivedTypeSpec(SourceName, const Symbol &);
243 DerivedTypeSpec(const DerivedTypeSpec &);
244 DerivedTypeSpec(DerivedTypeSpec &&);
245
246 const SourceName &name() const { return name_; }
247 const Symbol &typeSymbol() const { return typeSymbol_; }
248 const Scope *scope() const { return scope_; }
249 void set_scope(const Scope &);
250 void ReplaceScope(const Scope &);
251 RawParameters &rawParameters() { return rawParameters_; }
252 const ParameterMapType &parameters() const { return parameters_; }
253
254 bool MightBeParameterized() const;
255 bool IsForwardReferenced() const;
256 bool HasDefaultInitialization() const;
257
258 // The "raw" type parameter list is a simple transcription from the
259 // parameter list in the parse tree, built by calling AddRawParamValue().
260 // It can be used with forward-referenced derived types.
261 void AddRawParamValue(const std::optional<parser::Keyword> &, ParamValue &&);
262 // Checks the raw parameter list against the definition of a derived type.
263 // Converts the raw parameter list to a map, naming each actual parameter.
264 void CookParameters(evaluate::FoldingContext &);
265 // Evaluates type parameter expressions.
266 void EvaluateParameters(evaluate::FoldingContext &);
267 void AddParamValue(SourceName, ParamValue &&);
268 // Creates a Scope for the type and populates it with component
269 // instantiations that have been specialized with actual type parameter
270 // values, which are cooked &/or evaluated if necessary.
271 void Instantiate(Scope &, SemanticsContext &);
272
273 ParamValue *FindParameter(SourceName);
274 const ParamValue *FindParameter(SourceName target) const {
275 auto iter{parameters_.find(target)};
276 if (iter != parameters_.end()) {
277 return &iter->second;
278 } else {
279 return nullptr;
280 }
281 }
282 bool operator==(const DerivedTypeSpec &that) const {
283 return &typeSymbol_ == &that.typeSymbol_ && cooked_ == that.cooked_ &&
284 parameters_ == that.parameters_ &&
285 rawParameters_ == that.rawParameters_;
286 }
287 std::string AsFortran() const;
288
289 private:
290 SourceName name_;
291 const Symbol &typeSymbol_;
292 const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
293 bool cooked_{false};
294 bool evaluated_{false};
295 bool instantiated_{false};
296 RawParameters rawParameters_;
297 ParameterMapType parameters_;
298 friend llvm::raw_ostream &operator<<(
299 llvm::raw_ostream &, const DerivedTypeSpec &);
300 };
301
302 class DeclTypeSpec {
303 public:
304 enum Category {
305 Numeric,
306 Logical,
307 Character,
308 TypeDerived,
309 ClassDerived,
310 TypeStar,
311 ClassStar
312 };
313
314 // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
315 DeclTypeSpec(NumericTypeSpec &&);
316 DeclTypeSpec(LogicalTypeSpec &&);
317 // character
318 DeclTypeSpec(const CharacterTypeSpec &);
319 DeclTypeSpec(CharacterTypeSpec &&);
320 // TYPE(derived-type-spec) or CLASS(derived-type-spec)
321 DeclTypeSpec(Category, const DerivedTypeSpec &);
322 DeclTypeSpec(Category, DerivedTypeSpec &&);
323 // TYPE(*) or CLASS(*)
324 DeclTypeSpec(Category);
325
326 bool operator==(const DeclTypeSpec &) const;
327 bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
328
329 Category category() const { return category_; }
330 void set_category(Category category) { category_ = category; }
331 bool IsPolymorphic() const {
332 return category_ == ClassDerived || IsUnlimitedPolymorphic();
333 }
334 bool IsUnlimitedPolymorphic() const {
335 return category_ == TypeStar || category_ == ClassStar;
336 }
337 bool IsAssumedType() const { return category_ == TypeStar; }
338 bool IsNumeric(TypeCategory) const;
339 bool IsSequenceType() const;
340 const NumericTypeSpec &numericTypeSpec() const;
341 const LogicalTypeSpec &logicalTypeSpec() const;
342 const CharacterTypeSpec &characterTypeSpec() const {
343 CHECK(category_ == Character);
344 return std::get<CharacterTypeSpec>(typeSpec_);
345 }
346 const DerivedTypeSpec &derivedTypeSpec() const {
347 CHECK(category_ == TypeDerived || category_ == ClassDerived);
348 return std::get<DerivedTypeSpec>(typeSpec_);
349 }
350 DerivedTypeSpec &derivedTypeSpec() {
351 CHECK(category_ == TypeDerived || category_ == ClassDerived);
352 return std::get<DerivedTypeSpec>(typeSpec_);
353 }
354
355 inline IntrinsicTypeSpec *AsIntrinsic();
356 inline const IntrinsicTypeSpec *AsIntrinsic() const;
357 inline DerivedTypeSpec *AsDerived();
358 inline const DerivedTypeSpec *AsDerived() const;
359
360 std::string AsFortran() const;
361
362 private:
363 Category category_;
364 std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
365 CharacterTypeSpec, DerivedTypeSpec>
366 typeSpec_;
367 };
368 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &);
369
370 // This represents a proc-interface in the declaration of a procedure or
371 // procedure component. It comprises a symbol that represents the specific
372 // interface or a decl-type-spec that represents the function return type.
373 class ProcInterface {
374 public:
375 const Symbol *symbol() const { return symbol_; }
376 const DeclTypeSpec *type() const { return type_; }
377 void set_symbol(const Symbol &symbol);
378 void set_type(const DeclTypeSpec &type);
379
380 private:
381 const Symbol *symbol_{nullptr};
382 const DeclTypeSpec *type_{nullptr};
383 };
384
385 // Define some member functions here in the header so that they can be used by
386 // lib/Evaluate without link-time dependency on Semantics.
387
388 inline bool ArraySpec::IsExplicitShape() const {
389 return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); });
390 }
391 inline bool ArraySpec::IsAssumedShape() const {
392 return CheckAll([](const ShapeSpec &x) { return x.ubound().isDeferred(); });
393 }
394 inline bool ArraySpec::IsDeferredShape() const {
395 return CheckAll([](const ShapeSpec &x) {
396 return x.lbound().isDeferred() && x.ubound().isDeferred();
397 });
398 }
399 inline bool ArraySpec::IsImpliedShape() const {
400 return !IsAssumedRank() &&
401 CheckAll([](const ShapeSpec &x) { return x.ubound().isAssumed(); });
402 }
403 inline bool ArraySpec::IsAssumedSize() const {
404 return !empty() && !IsAssumedRank() && back().ubound().isAssumed() &&
405 std::all_of(begin(), end() - 1,
406 [](const ShapeSpec &x) { return x.ubound().isExplicit(); });
407 }
408 inline bool ArraySpec::IsAssumedRank() const {
409 return Rank() == 1 && front().lbound().isAssumed();
410 }
411
412 inline IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
413 switch (category_) {
414 case Numeric:
415 return &std::get<NumericTypeSpec>(typeSpec_);
416 case Logical:
417 return &std::get<LogicalTypeSpec>(typeSpec_);
418 case Character:
419 return &std::get<CharacterTypeSpec>(typeSpec_);
420 default:
421 return nullptr;
422 }
423 }
424 inline const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
425 return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
426 }
427
428 inline DerivedTypeSpec *DeclTypeSpec::AsDerived() {
429 switch (category_) {
430 case TypeDerived:
431 case ClassDerived:
432 return &std::get<DerivedTypeSpec>(typeSpec_);
433 default:
434 return nullptr;
435 }
436 }
437 inline const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
438 return const_cast<DeclTypeSpec *>(this)->AsDerived();
439 }
440
441 } // namespace Fortran::semantics
442 #endif // FORTRAN_SEMANTICS_TYPE_H_
Fortran::semantics::NumericTypeSpec
Definition: type.h:137
Fortran::semantics::SemanticsContext
Definition: semantics.h:60
Fortran::semantics::Bound
Definition: type.h:51
Fortran::semantics::ProcInterface
Definition: type.h:373
Fortran::semantics::DeclTypeSpec
Definition: type.h:302
Fortran::semantics::Symbol
Definition: symbol.h:479
Fortran::semantics::DerivedTypeSpec
Definition: type.h:237
Fortran::semantics::LogicalTypeSpec
Definition: type.h:145
Fortran::evaluate::FoldingContext
Definition: common.h:209
Fortran::semantics::ArraySpec
Definition: type.h:217
Fortran::semantics::CharacterTypeSpec
Definition: type.h:151
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::semantics::ShapeSpec
Definition: type.h:165
Fortran::semantics::Scope
Definition: scope.h:56
Fortran::parser
Definition: check-expression.h:19
Fortran::evaluate::Expr
Definition: common.h:207
Fortran::semantics::IntrinsicTypeSpec
Definition: type.h:117
Fortran::semantics::ParamValue
Definition: type.h:82