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
253private:
254 // Check non-empty and predicate is true for each element.
255 template <typename P> bool CheckAll(P predicate) const {
256 return !empty() && std::all_of(begin(), end(), predicate);
257 }
258};
259llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArraySpec &);
260
261// Each DerivedTypeSpec has a typeSymbol that has DerivedTypeDetails.
262// The name may not match the symbol's name in case of a USE rename.
263class DerivedTypeSpec {
264public:
265 enum class Category {
266 DerivedType,
267 IntrinsicVector,
268 PairVector,
269 QuadVector,
270 EnumerationType
271 };
272
273 using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
274 using RawParameters = std::vector<RawParameter>;
275 using ParameterMapType = std::map<SourceName, ParamValue>;
276 DerivedTypeSpec(SourceName, const Symbol &);
277 DerivedTypeSpec(const DerivedTypeSpec &);
278 DerivedTypeSpec(DerivedTypeSpec &&);
279
280 const SourceName &name() const { return name_; }
281 const Symbol &originalTypeSymbol() const { return originalTypeSymbol_; }
282 const Symbol &typeSymbol() const { return typeSymbol_; }
283 const Scope *scope() const { return scope_; }
284 // Return scope_ if it is set, or the typeSymbol_ scope otherwise.
285 const Scope *GetScope() const;
286 void set_scope(const Scope &);
287 void ReplaceScope(const Scope &);
288 const RawParameters &rawParameters() const { return rawParameters_; }
289 const ParameterMapType &parameters() const { return parameters_; }
290
291 bool MightBeParameterized() const;
292 bool IsForwardReferenced() const;
293 bool HasDefaultInitialization(
294 bool ignoreAllocatable = false, bool ignorePointer = true) const;
295 std::optional<std::string> // component path suitable for error messages
296 ComponentWithDefaultInitialization(
297 bool ignoreAllocatable = false, bool ignorePointer = true) const;
298 bool HasDestruction() const;
299
300 // The "raw" type parameter list is a simple transcription from the
301 // parameter list in the parse tree, built by calling AddRawParamValue().
302 // It can be used with forward-referenced derived types.
303 void AddRawParamValue(const parser::Keyword *, ParamValue &&);
304 // Checks the raw parameter list against the definition of a derived type.
305 // Converts the raw parameter list to a map, naming each actual parameter.
306 void CookParameters(evaluate::FoldingContext &);
307 // Evaluates type parameter expressions.
308 void EvaluateParameters(SemanticsContext &);
309 void ReevaluateParameters(SemanticsContext &);
310 void AddParamValue(SourceName, ParamValue &&);
311 // Creates a Scope for the type and populates it with component
312 // instantiations that have been specialized with actual type parameter
313 // values, which are cooked &/or evaluated if necessary.
314 void Instantiate(Scope &containingScope);
315 // Reset instantiation state so a copy can receive a fresh component scope
316 // (e.g. OpenACC use_device with CUDA Fortran component paths).
317 void PrepareForScopeClone();
318
319 ParamValue *FindParameter(SourceName);
320 const ParamValue *FindParameter(SourceName target) const {
321 auto iter{parameters_.find(target)};
322 if (iter != parameters_.end()) {
323 return &iter->second;
324 } else {
325 return nullptr;
326 }
327 }
328 bool operator==(const DerivedTypeSpec &that) const {
329 return RawEquals(that) && parameters_ == that.parameters_;
330 }
331 bool operator!=(const DerivedTypeSpec &that) const {
332 return !(*this == that);
333 }
334 // For TYPE IS & CLASS IS: kind type parameters must be
335 // explicit and equal, len type parameters are ignored.
336 bool MatchesOrExtends(const DerivedTypeSpec &) const;
337 std::string AsFortran() const;
338 std::string VectorTypeAsFortran() const;
339
340 Category category() const { return category_; }
341 void set_category(Category category) { category_ = category; }
342 bool IsVectorType() const {
343 return category_ == Category::IntrinsicVector ||
344 category_ == Category::PairVector || category_ == Category::QuadVector;
345 }
346 bool IsEnumerationType() const {
347 return category_ == Category::EnumerationType;
348 }
349
350private:
351 SourceName name_;
352 const Symbol &originalTypeSymbol_;
353 const Symbol &typeSymbol_; // == originalTypeSymbol_.GetUltimate()
354 const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
355 bool cooked_{false};
356 bool evaluated_{false};
357 bool instantiated_{false};
358 RawParameters rawParameters_;
359 ParameterMapType parameters_;
360 Category category_{Category::DerivedType};
361 bool RawEquals(const DerivedTypeSpec &that) const {
362 return &typeSymbol_ == &that.typeSymbol_ &&
363 &originalTypeSymbol_ == &that.originalTypeSymbol_ &&
364 cooked_ == that.cooked_ && rawParameters_ == that.rawParameters_;
365 }
366 friend llvm::raw_ostream &operator<<(
367 llvm::raw_ostream &, const DerivedTypeSpec &);
368};
369
370class DeclTypeSpec {
371public:
372 enum Category {
373 Numeric,
374 Logical,
375 Character,
376 TypeDerived,
377 ClassDerived,
378 TypeStar,
379 ClassStar
380 };
381
382 // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
383 DeclTypeSpec(NumericTypeSpec &&);
384 DeclTypeSpec(LogicalTypeSpec &&);
385 // character
386 DeclTypeSpec(const CharacterTypeSpec &);
387 DeclTypeSpec(CharacterTypeSpec &&);
388 // TYPE(derived-type-spec) or CLASS(derived-type-spec)
389 DeclTypeSpec(Category, const DerivedTypeSpec &);
390 DeclTypeSpec(Category, DerivedTypeSpec &&);
391 // TYPE(*) or CLASS(*)
392 DeclTypeSpec(Category);
393
394 bool operator==(const DeclTypeSpec &) const;
395 bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
396
397 Category category() const { return category_; }
398 void set_category(Category category) { category_ = category; }
399 bool IsPolymorphic() const {
400 return category_ == ClassDerived || IsUnlimitedPolymorphic();
401 }
402 bool IsUnlimitedPolymorphic() const {
403 return category_ == TypeStar || category_ == ClassStar;
404 }
405 bool IsAssumedType() const { return category_ == TypeStar; }
406 bool IsNumeric(TypeCategory) const;
407 bool IsSequenceType() const;
408 const NumericTypeSpec &numericTypeSpec() const;
409 const LogicalTypeSpec &logicalTypeSpec() const;
410 const CharacterTypeSpec &characterTypeSpec() const {
411 CHECK(category_ == Character);
412 return std::get<CharacterTypeSpec>(typeSpec_);
413 }
414 const DerivedTypeSpec &derivedTypeSpec() const {
415 CHECK(category_ == TypeDerived || category_ == ClassDerived);
416 return std::get<DerivedTypeSpec>(typeSpec_);
417 }
418 DerivedTypeSpec &derivedTypeSpec() {
419 CHECK(category_ == TypeDerived || category_ == ClassDerived);
420 return std::get<DerivedTypeSpec>(typeSpec_);
421 }
422
423 inline IntrinsicTypeSpec *AsIntrinsic();
424 inline const IntrinsicTypeSpec *AsIntrinsic() const;
425 inline DerivedTypeSpec *AsDerived();
426 inline const DerivedTypeSpec *AsDerived() const;
427
428 std::string AsFortran() const;
429
430private:
431 Category category_;
432 std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
434 typeSpec_;
435};
436llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &);
437
438// Define some member functions here in the header so that they can be used by
439// lib/Evaluate without link-time dependency on Semantics.
440
441inline bool ArraySpec::IsExplicitShape() const {
442 return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); });
443}
444inline bool ArraySpec::CanBeAssumedShape() const {
445 return CheckAll([](const ShapeSpec &x) { return x.ubound().isColon(); });
446}
447inline bool ArraySpec::CanBeDeferredShape() const {
448 return CheckAll([](const ShapeSpec &x) {
449 return x.lbound().isColon() && x.ubound().isColon();
450 });
451}
452inline bool ArraySpec::CanBeImpliedShape() const {
453 return !IsAssumedRank() &&
454 CheckAll([](const ShapeSpec &x) { return x.ubound().isStar(); });
455}
456inline bool ArraySpec::CanBeAssumedSize() const {
457 return !empty() && !IsAssumedRank() && back().ubound().isStar() &&
458 std::all_of(begin(), end() - 1,
459 [](const ShapeSpec &x) { return x.ubound().isExplicit(); });
460}
461inline bool ArraySpec::IsAssumedRank() const {
462 return Rank() == 1 && front().lbound().isStar();
463}
464
465inline IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
466 switch (category_) {
467 case Numeric:
468 return &std::get<NumericTypeSpec>(typeSpec_);
469 case Logical:
470 return &std::get<LogicalTypeSpec>(typeSpec_);
471 case Character:
472 return &std::get<CharacterTypeSpec>(typeSpec_);
473 default:
474 return nullptr;
475 }
476}
477inline const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
478 return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
479}
480
481inline DerivedTypeSpec *DeclTypeSpec::AsDerived() {
482 switch (category_) {
483 case TypeDerived:
484 case ClassDerived:
485 return &std::get<DerivedTypeSpec>(typeSpec_);
486 default:
487 return nullptr;
488 }
489}
490inline const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
491 return const_cast<DeclTypeSpec *>(this)->AsDerived();
492}
493
494} // namespace Fortran::semantics
495#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:67
Definition type.h:189
Definition symbol.h:896
Definition call.h:34
Definition check-expression.h:19
Definition type.h:239