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/idioms.h"
13#include "flang/Evaluate/expression.h"
14#include "flang/Parser/char-block.h"
15#include "flang/Support/Fortran.h"
16#include <algorithm>
17#include <map>
18#include <optional>
19#include <string>
20#include <variant>
21#include <vector>
22
23namespace llvm {
24class raw_ostream;
25}
26
27namespace Fortran::parser {
28struct Keyword;
29}
30
31namespace Fortran::evaluate { // avoid including all of Evaluate/tools.h
32template <typename T>
33std::optional<bool> AreEquivalentInInterface(const Expr<T> &, const Expr<T> &);
34extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
35 const Expr<SomeInteger> &, const Expr<SomeInteger> &);
36} // namespace Fortran::evaluate
37
38namespace Fortran::semantics {
39
40class Scope;
41class SemanticsContext;
42class Symbol;
43
46using SourceName = parser::CharBlock;
47using TypeCategory = common::TypeCategory;
48using SomeExpr = evaluate::Expr<evaluate::SomeType>;
49using MaybeExpr = std::optional<SomeExpr>;
50using SomeIntExpr = evaluate::Expr<evaluate::SomeInteger>;
51using MaybeIntExpr = std::optional<SomeIntExpr>;
52using SubscriptIntExpr = evaluate::Expr<evaluate::SubscriptInteger>;
53using MaybeSubscriptIntExpr = std::optional<SubscriptIntExpr>;
54using KindExpr = SubscriptIntExpr;
55
56// An array spec bound: an explicit integer expression, assumed size
57// or implied shape(*), or assumed or deferred shape(:). In the absence
58// of explicit lower bounds it is not possible to distinguish assumed
59// shape bounds from deferred shape bounds without knowing whether the
60// particular symbol is an allocatable/pointer or a non-allocatable
61// non-pointer dummy; use the symbol-based predicates for those
62// determinations.
63class Bound {
64public:
65 static Bound Star() { return Bound(Category::Star); }
66 static Bound Colon() { return Bound(Category::Colon); }
67 explicit Bound(MaybeSubscriptIntExpr &&expr) : expr_{std::move(expr)} {}
68 explicit Bound(common::ConstantSubscript bound);
69 Bound(const Bound &) = default;
70 Bound(Bound &&) = default;
71 Bound &operator=(const Bound &) = default;
72 Bound &operator=(Bound &&) = default;
73 bool isExplicit() const { return category_ == Category::Explicit; }
74 bool isStar() const { return category_ == Category::Star; }
75 bool isColon() const { return category_ == Category::Colon; }
76 MaybeSubscriptIntExpr &GetExplicit() { return expr_; }
77 const MaybeSubscriptIntExpr &GetExplicit() const { return expr_; }
78 void SetExplicit(MaybeSubscriptIntExpr &&expr) {
79 CHECK(isExplicit());
80 expr_ = std::move(expr);
81 }
82
83private:
84 enum class Category { Explicit, Star, Colon };
85 Bound(Category category) : category_{category} {}
86 Bound(Category category, MaybeSubscriptIntExpr &&expr)
87 : category_{category}, expr_{std::move(expr)} {}
88 Category category_{Category::Explicit};
89 MaybeSubscriptIntExpr expr_;
90 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Bound &);
91};
92
93// A type parameter value: integer expression, assumed/implied(*),
94// or deferred(:).
95class ParamValue {
96public:
97 static ParamValue Assumed(common::TypeParamAttr attr) {
98 return ParamValue{Category::Assumed, attr};
99 }
100 static ParamValue Deferred(common::TypeParamAttr attr) {
101 return ParamValue{Category::Deferred, attr};
102 }
103 ParamValue(const ParamValue &) = default;
104 explicit ParamValue(MaybeIntExpr &&, common::TypeParamAttr);
105 explicit ParamValue(SomeIntExpr &&, common::TypeParamAttr attr);
106 explicit ParamValue(common::ConstantSubscript, common::TypeParamAttr attr);
107 bool isExplicit() const { return category_ == Category::Explicit; }
108 bool isAssumed() const { return category_ == Category::Assumed; }
109 bool isDeferred() const { return category_ == Category::Deferred; }
110 const MaybeIntExpr &GetExplicit() const { return expr_; }
111 void SetExplicit(SomeIntExpr &&);
112 bool isKind() const { return attr_ == common::TypeParamAttr::Kind; }
113 bool isLen() const { return attr_ == common::TypeParamAttr::Len; }
114 void set_attr(common::TypeParamAttr attr) { attr_ = attr; }
115 bool operator==(const ParamValue &that) const {
116 return category_ == that.category_ && expr_ == that.expr_;
117 }
118 bool operator!=(const ParamValue &that) const { return !(*this == that); }
119 bool IsEquivalentInInterface(const ParamValue &that) const {
120 return (category_ == that.category_ &&
121 expr_.has_value() == that.expr_.has_value() &&
122 (!expr_ ||
123 evaluate::AreEquivalentInInterface(*expr_, *that.expr_)
124 .value_or(false)));
125 }
126 std::string AsFortran() const;
127
128private:
129 enum class Category { Explicit, Deferred, Assumed };
130 ParamValue(Category category, common::TypeParamAttr attr)
131 : category_{category}, attr_{attr} {}
132 Category category_{Category::Explicit};
133 common::TypeParamAttr attr_{common::TypeParamAttr::Kind};
134 MaybeIntExpr expr_;
135 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ParamValue &);
136};
137
138class IntrinsicTypeSpec {
139public:
140 TypeCategory category() const { return category_; }
141 const KindExpr &kind() const { return kind_; }
142 bool operator==(const IntrinsicTypeSpec &x) const {
143 return category_ == x.category_ && kind_ == x.kind_;
144 }
145 bool operator!=(const IntrinsicTypeSpec &x) const { return !operator==(x); }
146 std::string AsFortran() const;
147
148protected:
149 IntrinsicTypeSpec(TypeCategory, KindExpr &&);
150
151private:
152 TypeCategory category_;
153 KindExpr kind_;
154 friend llvm::raw_ostream &operator<<(
155 llvm::raw_ostream &os, const IntrinsicTypeSpec &x);
156};
157
158class NumericTypeSpec : public IntrinsicTypeSpec {
159public:
160 NumericTypeSpec(TypeCategory category, KindExpr &&kind)
161 : IntrinsicTypeSpec(category, std::move(kind)) {
162 CHECK(common::IsNumericTypeCategory(category));
163 }
164};
165
166class LogicalTypeSpec : public IntrinsicTypeSpec {
167public:
168 explicit LogicalTypeSpec(KindExpr &&kind)
169 : IntrinsicTypeSpec(TypeCategory::Logical, std::move(kind)) {}
170};
171
172class CharacterTypeSpec : public IntrinsicTypeSpec {
173public:
174 CharacterTypeSpec(ParamValue &&length, KindExpr &&kind)
175 : IntrinsicTypeSpec(TypeCategory::Character, std::move(kind)),
176 length_{std::move(length)} {}
177 const ParamValue &length() const { return length_; }
178 bool operator==(const CharacterTypeSpec &that) const {
179 return kind() == that.kind() && length_ == that.length_;
180 }
181 std::string AsFortran() const;
182
183private:
184 ParamValue length_;
185 friend llvm::raw_ostream &operator<<(
186 llvm::raw_ostream &os, const CharacterTypeSpec &x);
187};
188
189class ShapeSpec {
190public:
191 // lb:ub
192 static ShapeSpec MakeExplicit(Bound &&lb, Bound &&ub) {
193 return ShapeSpec(std::move(lb), std::move(ub));
194 }
195 // 1:ub
196 static const ShapeSpec MakeExplicit(Bound &&ub) {
197 return MakeExplicit(Bound{1}, std::move(ub));
198 }
199 // 1:
200 static ShapeSpec MakeAssumedShape() {
201 return ShapeSpec(Bound{1}, Bound::Colon());
202 }
203 // lb:
204 static ShapeSpec MakeAssumedShape(Bound &&lb) {
205 return ShapeSpec(std::move(lb), Bound::Colon());
206 }
207 // :
208 static ShapeSpec MakeDeferred() {
209 return ShapeSpec(Bound::Colon(), Bound::Colon());
210 }
211 // 1:*
212 static ShapeSpec MakeImplied() { return ShapeSpec(Bound{1}, Bound::Star()); }
213 // lb:*
214 static ShapeSpec MakeImplied(Bound &&lb) {
215 return ShapeSpec(std::move(lb), Bound::Star());
216 }
217 // ..
218 static ShapeSpec MakeAssumedRank() {
219 return ShapeSpec(Bound::Star(), Bound::Star());
220 }
221
222 ShapeSpec(const ShapeSpec &) = default;
223 ShapeSpec(ShapeSpec &&) = default;
224 ShapeSpec &operator=(const ShapeSpec &) = default;
225 ShapeSpec &operator=(ShapeSpec &&) = default;
226
227 Bound &lbound() { return lb_; }
228 const Bound &lbound() const { return lb_; }
229 Bound &ubound() { return ub_; }
230 const Bound &ubound() const { return ub_; }
231
232private:
233 ShapeSpec(Bound &&lb, Bound &&ub) : lb_{std::move(lb)}, ub_{std::move(ub)} {}
234 Bound lb_;
235 Bound ub_;
236 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ShapeSpec &);
237};
238
239struct ArraySpec : public std::vector<ShapeSpec> {
240 ArraySpec() {}
241 int Rank() const { return size(); }
242 // These names are not exclusive, as some categories cannot be
243 // distinguished without knowing whether the particular symbol
244 // is allocatable, pointer, or a non-allocatable non-pointer dummy.
245 // Use the symbol-based predicates for exact results.
246 inline bool IsExplicitShape() const;
247 inline bool CanBeAssumedShape() const;
248 inline bool CanBeDeferredShape() const;
249 inline bool CanBeImpliedShape() const;
250 inline bool CanBeAssumedSize() const;
251 inline bool IsAssumedRank() const;
252 // Which bounds of this shape were declared with a rank-1 integer array
253 // (F2023 R818 explicit-shape-bounds-spec)? A constant bounds array is
254 // folded into ordinary per-dimension bounds, so the spec itself no longer
255 // shows it; the module file writer uses this to write the declared
256 // whole-array form back out.
257 bool isFromRankOneBounds() const {
258 return lboundIsRankOne_ || uboundIsRankOne_;
259 }
260 bool lboundIsRankOne() const { return lboundIsRankOne_; }
261 bool uboundIsRankOne() const { return uboundIsRankOne_; }
262 void set_rankOneBounds(bool lower, bool upper) {
263 lboundIsRankOne_ = lower;
264 uboundIsRankOne_ = upper;
265 }
266 void clear() {
267 std::vector<ShapeSpec>::clear();
268 lboundIsRankOne_ = uboundIsRankOne_ = false;
269 }
270
271private:
272 bool lboundIsRankOne_{false};
273 bool uboundIsRankOne_{false};
274 // Check non-empty and predicate is true for each element.
275 template <typename P> bool CheckAll(P predicate) const {
276 return !empty() && std::all_of(begin(), end(), predicate);
277 }
278};
279llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArraySpec &);
280
281// Each DerivedTypeSpec has a typeSymbol that has DerivedTypeDetails.
282// The name may not match the symbol's name in case of a USE rename.
283class DerivedTypeSpec {
284public:
285 enum class Category {
286 DerivedType,
287 IntrinsicVector,
288 PairVector,
289 QuadVector,
290 EnumerationType
291 };
292
293 using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
294 using RawParameters = std::vector<RawParameter>;
295 using ParameterMapType = std::map<SourceName, ParamValue>;
296 DerivedTypeSpec(SourceName, const Symbol &);
297 DerivedTypeSpec(const DerivedTypeSpec &);
298 DerivedTypeSpec(DerivedTypeSpec &&);
299
300 const SourceName &name() const { return name_; }
301 const Symbol &originalTypeSymbol() const { return originalTypeSymbol_; }
302 const Symbol &typeSymbol() const { return typeSymbol_; }
303 const Scope *scope() const { return scope_; }
304 // Return scope_ if it is set, or the typeSymbol_ scope otherwise.
305 const Scope *GetScope() const;
306 void set_scope(const Scope &);
307 void ReplaceScope(const Scope &);
308 const RawParameters &rawParameters() const { return rawParameters_; }
309 const ParameterMapType &parameters() const { return parameters_; }
310
311 bool MightBeParameterized() const;
312 bool IsForwardReferenced() const;
313 bool HasDefaultInitialization(
314 bool ignoreAllocatable = false, bool ignorePointer = true) const;
315 std::optional<std::string> // component path suitable for error messages
316 ComponentWithDefaultInitialization(
317 bool ignoreAllocatable = false, bool ignorePointer = true) const;
318 bool HasDestruction() const;
319
320 // The "raw" type parameter list is a simple transcription from the
321 // parameter list in the parse tree, built by calling AddRawParamValue().
322 // It can be used with forward-referenced derived types.
323 void AddRawParamValue(const parser::Keyword *, ParamValue &&);
324 // Checks the raw parameter list against the definition of a derived type.
325 // Converts the raw parameter list to a map, naming each actual parameter.
326 void CookParameters(evaluate::FoldingContext &);
327 // Evaluates type parameter expressions.
328 void EvaluateParameters(SemanticsContext &);
329 void ReevaluateParameters(SemanticsContext &);
330 void AddParamValue(SourceName, ParamValue &&);
331 // Creates a Scope for the type and populates it with component
332 // instantiations that have been specialized with actual type parameter
333 // values, which are cooked &/or evaluated if necessary.
334 void Instantiate(Scope &containingScope);
335 // Reset instantiation state so a copy can receive a fresh component scope
336 // (e.g. OpenACC use_device with CUDA Fortran component paths).
337 void PrepareForScopeClone();
338
339 ParamValue *FindParameter(SourceName);
340 const ParamValue *FindParameter(SourceName target) const {
341 auto iter{parameters_.find(target)};
342 if (iter != parameters_.end()) {
343 return &iter->second;
344 } else {
345 return nullptr;
346 }
347 }
348 bool operator==(const DerivedTypeSpec &that) const {
349 return RawEquals(that) && parameters_ == that.parameters_;
350 }
351 bool operator!=(const DerivedTypeSpec &that) const {
352 return !(*this == that);
353 }
354 // For TYPE IS & CLASS IS: kind type parameters must be
355 // explicit and equal, len type parameters are ignored.
356 bool MatchesOrExtends(const DerivedTypeSpec &) const;
357 std::string AsFortran() const;
358 std::string VectorTypeAsFortran() const;
359
360 Category category() const { return category_; }
361 void set_category(Category category) { category_ = category; }
362 bool IsVectorType() const {
363 return category_ == Category::IntrinsicVector ||
364 category_ == Category::PairVector || category_ == Category::QuadVector;
365 }
366 bool IsEnumerationType() const {
367 return category_ == Category::EnumerationType;
368 }
369
370private:
371 SourceName name_;
372 const Symbol &originalTypeSymbol_;
373 const Symbol &typeSymbol_; // == originalTypeSymbol_.GetUltimate()
374 const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
375 bool cooked_{false};
376 bool evaluated_{false};
377 bool instantiated_{false};
378 RawParameters rawParameters_;
379 ParameterMapType parameters_;
380 Category category_{Category::DerivedType};
381 bool RawEquals(const DerivedTypeSpec &that) const {
382 return &typeSymbol_ == &that.typeSymbol_ &&
383 &originalTypeSymbol_ == &that.originalTypeSymbol_ &&
384 cooked_ == that.cooked_ && rawParameters_ == that.rawParameters_;
385 }
386 friend llvm::raw_ostream &operator<<(
387 llvm::raw_ostream &, const DerivedTypeSpec &);
388};
389
390class DeclTypeSpec {
391public:
392 enum Category {
393 Numeric,
394 Logical,
395 Character,
396 TypeDerived,
397 ClassDerived,
398 TypeStar,
399 ClassStar
400 };
401
402 // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
403 DeclTypeSpec(NumericTypeSpec &&);
404 DeclTypeSpec(LogicalTypeSpec &&);
405 // character
406 DeclTypeSpec(const CharacterTypeSpec &);
407 DeclTypeSpec(CharacterTypeSpec &&);
408 // TYPE(derived-type-spec) or CLASS(derived-type-spec)
409 DeclTypeSpec(Category, const DerivedTypeSpec &);
410 DeclTypeSpec(Category, DerivedTypeSpec &&);
411 // TYPE(*) or CLASS(*)
412 DeclTypeSpec(Category);
413
414 bool operator==(const DeclTypeSpec &) const;
415 bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
416
417 Category category() const { return category_; }
418 void set_category(Category category) { category_ = category; }
419 bool IsPolymorphic() const {
420 return category_ == ClassDerived || IsUnlimitedPolymorphic();
421 }
422 bool IsUnlimitedPolymorphic() const {
423 return category_ == TypeStar || category_ == ClassStar;
424 }
425 bool IsAssumedType() const { return category_ == TypeStar; }
426 bool IsNumeric(TypeCategory) const;
427 bool IsSequenceType() const;
428 const NumericTypeSpec &numericTypeSpec() const;
429 const LogicalTypeSpec &logicalTypeSpec() const;
430 const CharacterTypeSpec &characterTypeSpec() const {
431 CHECK(category_ == Character);
432 return std::get<CharacterTypeSpec>(typeSpec_);
433 }
434 const DerivedTypeSpec &derivedTypeSpec() const {
435 CHECK(category_ == TypeDerived || category_ == ClassDerived);
436 return std::get<DerivedTypeSpec>(typeSpec_);
437 }
438 DerivedTypeSpec &derivedTypeSpec() {
439 CHECK(category_ == TypeDerived || category_ == ClassDerived);
440 return std::get<DerivedTypeSpec>(typeSpec_);
441 }
442
443 inline IntrinsicTypeSpec *AsIntrinsic();
444 inline const IntrinsicTypeSpec *AsIntrinsic() const;
445 inline DerivedTypeSpec *AsDerived();
446 inline const DerivedTypeSpec *AsDerived() const;
447
448 std::string AsFortran() const;
449
450private:
451 Category category_;
452 std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
454 typeSpec_;
455};
456llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &);
457
458// Define some member functions here in the header so that they can be used by
459// lib/Evaluate without link-time dependency on Semantics.
460
461inline bool ArraySpec::IsExplicitShape() const {
462 return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); });
463}
464inline bool ArraySpec::CanBeAssumedShape() const {
465 return CheckAll([](const ShapeSpec &x) { return x.ubound().isColon(); });
466}
467inline bool ArraySpec::CanBeDeferredShape() const {
468 return CheckAll([](const ShapeSpec &x) {
469 return x.lbound().isColon() && x.ubound().isColon();
470 });
471}
472inline bool ArraySpec::CanBeImpliedShape() const {
473 return !IsAssumedRank() &&
474 CheckAll([](const ShapeSpec &x) { return x.ubound().isStar(); });
475}
476inline bool ArraySpec::CanBeAssumedSize() const {
477 return !empty() && !IsAssumedRank() && back().ubound().isStar() &&
478 std::all_of(begin(), end() - 1,
479 [](const ShapeSpec &x) { return x.ubound().isExplicit(); });
480}
481inline bool ArraySpec::IsAssumedRank() const {
482 return Rank() == 1 && front().lbound().isStar();
483}
484
485inline IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
486 switch (category_) {
487 case Numeric:
488 return &std::get<NumericTypeSpec>(typeSpec_);
489 case Logical:
490 return &std::get<LogicalTypeSpec>(typeSpec_);
491 case Character:
492 return &std::get<CharacterTypeSpec>(typeSpec_);
493 default:
494 return nullptr;
495 }
496}
497inline const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
498 return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
499}
500
501inline DerivedTypeSpec *DeclTypeSpec::AsDerived() {
502 switch (category_) {
503 case TypeDerived:
504 case ClassDerived:
505 return &std::get<DerivedTypeSpec>(typeSpec_);
506 default:
507 return nullptr;
508 }
509}
510inline const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
511 return const_cast<DeclTypeSpec *>(this)->AsDerived();
512}
513
514} // namespace Fortran::semantics
515#endif // FORTRAN_SEMANTICS_TYPE_H_
Definition common.h:215
Definition common.h:217
Definition type.h:63
Definition type.h:95
Definition scope.h:68
Definition semantics.h:71
Definition type.h:189
Definition symbol.h:916
Definition call.h:34
Definition ParserActions.h:24
Definition check-expression.h:19
Definition type.h:239