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