Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Semantics/type.h