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
38 /// A SourceName is a name in the cooked character stream,
39 /// i.e. a range of lower-case characters with provenance.
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, 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.
57 class Bound {
58 public:
Star()59 static Bound Star() { return Bound(Category::Star); }
Colon()60 static Bound Colon() { return Bound(Category::Colon); }
Bound(MaybeSubscriptIntExpr && expr)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;
isExplicit()67 bool isExplicit() const { return category_ == Category::Explicit; }
isStar()68 bool isStar() const { return category_ == Category::Star; }
isColon()69 bool isColon() const { return category_ == Category::Colon; }
GetExplicit()70 MaybeSubscriptIntExpr &GetExplicit() { return expr_; }
GetExplicit()71 const MaybeSubscriptIntExpr &GetExplicit() const { return expr_; }
SetExplicit(MaybeSubscriptIntExpr && expr)72 void SetExplicit(MaybeSubscriptIntExpr &&expr) {
73 CHECK(isExplicit());
74 expr_ = std::move(expr);
75 }
76
77 private:
78 enum class Category { Explicit, Star, Colon };
Bound(Category category)79 Bound(Category category) : category_{category} {}
Bound(Category category,MaybeSubscriptIntExpr && expr)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(:).
89 class ParamValue {
90 public:
Assumed(common::TypeParamAttr attr)91 static ParamValue Assumed(common::TypeParamAttr attr) {
92 return ParamValue{Category::Assumed, attr};
93 }
Deferred(common::TypeParamAttr attr)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);
isExplicit()101 bool isExplicit() const { return category_ == Category::Explicit; }
isAssumed()102 bool isAssumed() const { return category_ == Category::Assumed; }
isDeferred()103 bool isDeferred() const { return category_ == Category::Deferred; }
GetExplicit()104 const MaybeIntExpr &GetExplicit() const { return expr_; }
105 void SetExplicit(SomeIntExpr &&);
isKind()106 bool isKind() const { return attr_ == common::TypeParamAttr::Kind; }
isLen()107 bool isLen() const { return attr_ == common::TypeParamAttr::Len; }
set_attr(common::TypeParamAttr attr)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
115 private:
116 enum class Category { Explicit, Deferred, Assumed };
ParamValue(Category category,common::TypeParamAttr attr)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
125 class IntrinsicTypeSpec {
126 public:
category()127 TypeCategory category() const { return category_; }
kind()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
135 protected:
136 IntrinsicTypeSpec(TypeCategory, KindExpr &&);
137
138 private:
139 TypeCategory category_;
140 KindExpr kind_;
141 friend llvm::raw_ostream &operator<<(
142 llvm::raw_ostream &os, const IntrinsicTypeSpec &x);
143 };
144
145 class NumericTypeSpec : public IntrinsicTypeSpec {
146 public:
NumericTypeSpec(TypeCategory category,KindExpr && kind)147 NumericTypeSpec(TypeCategory category, KindExpr &&kind)
148 : IntrinsicTypeSpec(category, std::move(kind)) {
149 CHECK(common::IsNumericTypeCategory(category));
150 }
151 };
152
153 class LogicalTypeSpec : public IntrinsicTypeSpec {
154 public:
LogicalTypeSpec(KindExpr && kind)155 explicit LogicalTypeSpec(KindExpr &&kind)
156 : IntrinsicTypeSpec(TypeCategory::Logical, std::move(kind)) {}
157 };
158
159 class CharacterTypeSpec : public IntrinsicTypeSpec {
160 public:
CharacterTypeSpec(ParamValue && length,KindExpr && kind)161 CharacterTypeSpec(ParamValue &&length, KindExpr &&kind)
162 : IntrinsicTypeSpec(TypeCategory::Character, std::move(kind)),
163 length_{std::move(length)} {}
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
170 private:
171 ParamValue length_;
172 friend llvm::raw_ostream &operator<<(
173 llvm::raw_ostream &os, const CharacterTypeSpec &x);
174 };
175
176 class ShapeSpec {
177 public:
178 // lb:ub
MakeExplicit(Bound && lb,Bound && ub)179 static ShapeSpec MakeExplicit(Bound &&lb, Bound &&ub) {
180 return ShapeSpec(std::move(lb), std::move(ub));
181 }
182 // 1:ub
MakeExplicit(Bound && ub)183 static const ShapeSpec MakeExplicit(Bound &&ub) {
184 return MakeExplicit(Bound{1}, std::move(ub));
185 }
186 // 1:
MakeAssumedShape()187 static ShapeSpec MakeAssumedShape() {
188 return ShapeSpec(Bound{1}, Bound::Colon());
189 }
190 // lb:
MakeAssumedShape(Bound && lb)191 static ShapeSpec MakeAssumedShape(Bound &&lb) {
192 return ShapeSpec(std::move(lb), Bound::Colon());
193 }
194 // :
MakeDeferred()195 static ShapeSpec MakeDeferred() {
196 return ShapeSpec(Bound::Colon(), Bound::Colon());
197 }
198 // 1:*
MakeImplied()199 static ShapeSpec MakeImplied() { return ShapeSpec(Bound{1}, Bound::Star()); }
200 // lb:*
MakeImplied(Bound && lb)201 static ShapeSpec MakeImplied(Bound &&lb) {
202 return ShapeSpec(std::move(lb), Bound::Star());
203 }
204 // ..
MakeAssumedRank()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
lbound()214 Bound &lbound() { return lb_; }
lbound()215 const Bound &lbound() const { return lb_; }
ubound()216 Bound &ubound() { return ub_; }
ubound()217 const Bound &ubound() const { return ub_; }
218
219 private:
ShapeSpec(Bound && lb,Bound && ub)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
226 struct ArraySpec : public std::vector<ShapeSpec> {
ArraySpecArraySpec227 ArraySpec() {}
RankArraySpec228 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
240 private:
241 // Check non-empty and predicate is true for each element.
CheckAllArraySpec242 template <typename P> bool CheckAll(P predicate) const {
243 return !empty() && std::all_of(begin(), end(), predicate);
244 }
245 };
246 llvm::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.
250 class DerivedTypeSpec {
251 public:
252 using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
253 using RawParameters = std::vector<RawParameter>;
254 using ParameterMapType = std::map<SourceName, ParamValue>;
255 DerivedTypeSpec(SourceName, const Symbol &);
256 DerivedTypeSpec(const DerivedTypeSpec &);
257 DerivedTypeSpec(DerivedTypeSpec &&);
258
name()259 const SourceName &name() const { return name_; }
typeSymbol()260 const Symbol &typeSymbol() const { return typeSymbol_; }
scope()261 const Scope *scope() const { return scope_; }
262 void set_scope(const Scope &);
263 void ReplaceScope(const Scope &);
rawParameters()264 RawParameters &rawParameters() { return rawParameters_; }
parameters()265 const ParameterMapType ¶meters() const { return parameters_; }
266
267 bool MightBeParameterized() const;
268 bool IsForwardReferenced() const;
269 bool HasDefaultInitialization(bool ignoreAllocatable = false) const;
270 bool HasDestruction() const;
271 bool HasFinalization() const;
272
273 // The "raw" type parameter list is a simple transcription from the
274 // parameter list in the parse tree, built by calling AddRawParamValue().
275 // It can be used with forward-referenced derived types.
276 void AddRawParamValue(const std::optional<parser::Keyword> &, ParamValue &&);
277 // Checks the raw parameter list against the definition of a derived type.
278 // Converts the raw parameter list to a map, naming each actual parameter.
279 void CookParameters(evaluate::FoldingContext &);
280 // Evaluates type parameter expressions.
281 void EvaluateParameters(SemanticsContext &);
282 void AddParamValue(SourceName, ParamValue &&);
283 // Creates a Scope for the type and populates it with component
284 // instantiations that have been specialized with actual type parameter
285 // values, which are cooked &/or evaluated if necessary.
286 void Instantiate(Scope &containingScope);
287
288 ParamValue *FindParameter(SourceName);
FindParameter(SourceName target)289 const ParamValue *FindParameter(SourceName target) const {
290 auto iter{parameters_.find(target)};
291 if (iter != parameters_.end()) {
292 return &iter->second;
293 } else {
294 return nullptr;
295 }
296 }
297 bool operator==(const DerivedTypeSpec &that) const {
298 return RawEquals(that) && parameters_ == that.parameters_;
299 }
300 bool operator!=(const DerivedTypeSpec &that) const {
301 return !(*this == that);
302 }
303 // For TYPE IS & CLASS IS: kind type parameters must be
304 // explicit and equal, len type parameters are ignored.
305 bool Match(const DerivedTypeSpec &) const;
306 std::string AsFortran() const;
307
308 private:
309 SourceName name_;
310 const Symbol &typeSymbol_;
311 const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
312 bool cooked_{false};
313 bool evaluated_{false};
314 bool instantiated_{false};
315 RawParameters rawParameters_;
316 ParameterMapType parameters_;
RawEquals(const DerivedTypeSpec & that)317 bool RawEquals(const DerivedTypeSpec &that) const {
318 return &typeSymbol_ == &that.typeSymbol_ && cooked_ == that.cooked_ &&
319 rawParameters_ == that.rawParameters_;
320 }
321 friend llvm::raw_ostream &operator<<(
322 llvm::raw_ostream &, const DerivedTypeSpec &);
323 };
324
325 class DeclTypeSpec {
326 public:
327 enum Category {
328 Numeric,
329 Logical,
330 Character,
331 TypeDerived,
332 ClassDerived,
333 TypeStar,
334 ClassStar
335 };
336
337 // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
338 DeclTypeSpec(NumericTypeSpec &&);
339 DeclTypeSpec(LogicalTypeSpec &&);
340 // character
341 DeclTypeSpec(const CharacterTypeSpec &);
342 DeclTypeSpec(CharacterTypeSpec &&);
343 // TYPE(derived-type-spec) or CLASS(derived-type-spec)
344 DeclTypeSpec(Category, const DerivedTypeSpec &);
345 DeclTypeSpec(Category, DerivedTypeSpec &&);
346 // TYPE(*) or CLASS(*)
347 DeclTypeSpec(Category);
348
349 bool operator==(const DeclTypeSpec &) const;
350 bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
351
category()352 Category category() const { return category_; }
set_category(Category category)353 void set_category(Category category) { category_ = category; }
IsPolymorphic()354 bool IsPolymorphic() const {
355 return category_ == ClassDerived || IsUnlimitedPolymorphic();
356 }
IsUnlimitedPolymorphic()357 bool IsUnlimitedPolymorphic() const {
358 return category_ == TypeStar || category_ == ClassStar;
359 }
IsAssumedType()360 bool IsAssumedType() const { return category_ == TypeStar; }
361 bool IsNumeric(TypeCategory) const;
362 bool IsSequenceType() const;
363 const NumericTypeSpec &numericTypeSpec() const;
364 const LogicalTypeSpec &logicalTypeSpec() const;
characterTypeSpec()365 const CharacterTypeSpec &characterTypeSpec() const {
366 CHECK(category_ == Character);
367 return std::get<CharacterTypeSpec>(typeSpec_);
368 }
derivedTypeSpec()369 const DerivedTypeSpec &derivedTypeSpec() const {
370 CHECK(category_ == TypeDerived || category_ == ClassDerived);
371 return std::get<DerivedTypeSpec>(typeSpec_);
372 }
derivedTypeSpec()373 DerivedTypeSpec &derivedTypeSpec() {
374 CHECK(category_ == TypeDerived || category_ == ClassDerived);
375 return std::get<DerivedTypeSpec>(typeSpec_);
376 }
377
378 inline IntrinsicTypeSpec *AsIntrinsic();
379 inline const IntrinsicTypeSpec *AsIntrinsic() const;
380 inline DerivedTypeSpec *AsDerived();
381 inline const DerivedTypeSpec *AsDerived() const;
382
383 std::string AsFortran() const;
384
385 private:
386 Category category_;
387 std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
388 CharacterTypeSpec, DerivedTypeSpec>
389 typeSpec_;
390 };
391 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &);
392
393 // This represents a proc-interface in the declaration of a procedure or
394 // procedure component. It comprises a symbol that represents the specific
395 // interface or a decl-type-spec that represents the function return type.
396 class ProcInterface {
397 public:
symbol()398 const Symbol *symbol() const { return symbol_; }
type()399 const DeclTypeSpec *type() const { return type_; }
400 void set_symbol(const Symbol &symbol);
401 void set_type(const DeclTypeSpec &type);
402
403 private:
404 const Symbol *symbol_{nullptr};
405 const DeclTypeSpec *type_{nullptr};
406 };
407
408 // Define some member functions here in the header so that they can be used by
409 // lib/Evaluate without link-time dependency on Semantics.
410
IsExplicitShape()411 inline bool ArraySpec::IsExplicitShape() const {
412 return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); });
413 }
CanBeAssumedShape()414 inline bool ArraySpec::CanBeAssumedShape() const {
415 return CheckAll([](const ShapeSpec &x) { return x.ubound().isColon(); });
416 }
CanBeDeferredShape()417 inline bool ArraySpec::CanBeDeferredShape() const {
418 return CheckAll([](const ShapeSpec &x) {
419 return x.lbound().isColon() && x.ubound().isColon();
420 });
421 }
CanBeImpliedShape()422 inline bool ArraySpec::CanBeImpliedShape() const {
423 return !IsAssumedRank() &&
424 CheckAll([](const ShapeSpec &x) { return x.ubound().isStar(); });
425 }
CanBeAssumedSize()426 inline bool ArraySpec::CanBeAssumedSize() const {
427 return !empty() && !IsAssumedRank() && back().ubound().isStar() &&
428 std::all_of(begin(), end() - 1,
429 [](const ShapeSpec &x) { return x.ubound().isExplicit(); });
430 }
IsAssumedRank()431 inline bool ArraySpec::IsAssumedRank() const {
432 return Rank() == 1 && front().lbound().isStar();
433 }
434
AsIntrinsic()435 inline IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
436 switch (category_) {
437 case Numeric:
438 return &std::get<NumericTypeSpec>(typeSpec_);
439 case Logical:
440 return &std::get<LogicalTypeSpec>(typeSpec_);
441 case Character:
442 return &std::get<CharacterTypeSpec>(typeSpec_);
443 default:
444 return nullptr;
445 }
446 }
AsIntrinsic()447 inline const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
448 return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
449 }
450
AsDerived()451 inline DerivedTypeSpec *DeclTypeSpec::AsDerived() {
452 switch (category_) {
453 case TypeDerived:
454 case ClassDerived:
455 return &std::get<DerivedTypeSpec>(typeSpec_);
456 default:
457 return nullptr;
458 }
459 }
AsDerived()460 inline const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
461 return const_cast<DeclTypeSpec *>(this)->AsDerived();
462 }
463
464 } // namespace Fortran::semantics
465 #endif // FORTRAN_SEMANTICS_TYPE_H_
466