xref: /llvm-project/flang/lib/Lower/ConvertType.cpp (revision f023da12d12635f5fba436e825cbfc999e28e623)
1baa12ddbSEric Schweitz //===-- ConvertType.cpp ---------------------------------------------------===//
2baa12ddbSEric Schweitz //
3baa12ddbSEric Schweitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4baa12ddbSEric Schweitz // See https://llvm.org/LICENSE.txt for license information.
5baa12ddbSEric Schweitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6baa12ddbSEric Schweitz //
7baa12ddbSEric Schweitz //===----------------------------------------------------------------------===//
8baa12ddbSEric Schweitz 
9baa12ddbSEric Schweitz #include "flang/Lower/ConvertType.h"
102c2e5a5dSValentin Clement #include "flang/Lower/AbstractConverter.h"
119aeb7f03SValentin Clement #include "flang/Lower/CallInterface.h"
129aeb7f03SValentin Clement #include "flang/Lower/ConvertVariable.h"
13589d51eaSValentin Clement #include "flang/Lower/Mangler.h"
14baa12ddbSEric Schweitz #include "flang/Lower/PFTBuilder.h"
15e641c29fSValentin Clement #include "flang/Lower/Support/Utils.h"
165b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
17baa12ddbSEric Schweitz #include "flang/Optimizer/Dialect/FIRType.h"
18baa12ddbSEric Schweitz #include "flang/Semantics/tools.h"
19baa12ddbSEric Schweitz #include "flang/Semantics/type.h"
20baa12ddbSEric Schweitz #include "mlir/IR/Builders.h"
2109f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
22589d51eaSValentin Clement #include "llvm/Support/Debug.h"
2379e788d0SKelvin Li #include "llvm/TargetParser/Host.h"
2479e788d0SKelvin Li #include "llvm/TargetParser/Triple.h"
25baa12ddbSEric Schweitz 
26ad40cc14SValentin Clement #define DEBUG_TYPE "flang-lower-type"
27ad40cc14SValentin Clement 
28ef934174SKelvin Li using Fortran::common::VectorElementCategory;
29ef934174SKelvin Li 
30ad40cc14SValentin Clement //===--------------------------------------------------------------------===//
31ad40cc14SValentin Clement // Intrinsic type translation helpers
32ad40cc14SValentin Clement //===--------------------------------------------------------------------===//
33ad40cc14SValentin Clement 
340a0b3029SValentin Clement static mlir::Type genRealType(mlir::MLIRContext *context, int kind) {
350a0b3029SValentin Clement   if (Fortran::evaluate::IsValidKindOfIntrinsicType(
360a0b3029SValentin Clement           Fortran::common::TypeCategory::Real, kind)) {
370a0b3029SValentin Clement     switch (kind) {
380a0b3029SValentin Clement     case 2:
39*f023da12SMatthias Springer       return mlir::Float16Type::get(context);
400a0b3029SValentin Clement     case 3:
41*f023da12SMatthias Springer       return mlir::BFloat16Type::get(context);
420a0b3029SValentin Clement     case 4:
43*f023da12SMatthias Springer       return mlir::Float32Type::get(context);
440a0b3029SValentin Clement     case 8:
45*f023da12SMatthias Springer       return mlir::Float64Type::get(context);
460a0b3029SValentin Clement     case 10:
47*f023da12SMatthias Springer       return mlir::Float80Type::get(context);
480a0b3029SValentin Clement     case 16:
49*f023da12SMatthias Springer       return mlir::Float128Type::get(context);
500a0b3029SValentin Clement     }
510a0b3029SValentin Clement   }
520a0b3029SValentin Clement   llvm_unreachable("REAL type translation not implemented");
530a0b3029SValentin Clement }
540a0b3029SValentin Clement 
55ad40cc14SValentin Clement template <int KIND>
56ad40cc14SValentin Clement int getIntegerBits() {
57ad40cc14SValentin Clement   return Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer,
58ad40cc14SValentin Clement                                  KIND>::Scalar::bits;
59ad40cc14SValentin Clement }
60ef934174SKelvin Li static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind,
61ef934174SKelvin Li                                  bool isUnsigned = false) {
62ad40cc14SValentin Clement   if (Fortran::evaluate::IsValidKindOfIntrinsicType(
63ad40cc14SValentin Clement           Fortran::common::TypeCategory::Integer, kind)) {
64ef934174SKelvin Li     mlir::IntegerType::SignednessSemantics signedness =
65ef934174SKelvin Li         (isUnsigned ? mlir::IntegerType::SignednessSemantics::Unsigned
66ef934174SKelvin Li                     : mlir::IntegerType::SignednessSemantics::Signless);
67ef934174SKelvin Li 
68ad40cc14SValentin Clement     switch (kind) {
69ad40cc14SValentin Clement     case 1:
70ef934174SKelvin Li       return mlir::IntegerType::get(context, getIntegerBits<1>(), signedness);
71ad40cc14SValentin Clement     case 2:
72ef934174SKelvin Li       return mlir::IntegerType::get(context, getIntegerBits<2>(), signedness);
73ad40cc14SValentin Clement     case 4:
74ef934174SKelvin Li       return mlir::IntegerType::get(context, getIntegerBits<4>(), signedness);
75ad40cc14SValentin Clement     case 8:
76ef934174SKelvin Li       return mlir::IntegerType::get(context, getIntegerBits<8>(), signedness);
77ad40cc14SValentin Clement     case 16:
78ef934174SKelvin Li       return mlir::IntegerType::get(context, getIntegerBits<16>(), signedness);
79ad40cc14SValentin Clement     }
80ad40cc14SValentin Clement   }
81fc97d2e6SPeter Klausler   llvm_unreachable("INTEGER or UNSIGNED kind not translated");
82ad40cc14SValentin Clement }
83ad40cc14SValentin Clement 
84ad40cc14SValentin Clement static mlir::Type genLogicalType(mlir::MLIRContext *context, int KIND) {
85ad40cc14SValentin Clement   if (Fortran::evaluate::IsValidKindOfIntrinsicType(
86ad40cc14SValentin Clement           Fortran::common::TypeCategory::Logical, KIND))
87ad40cc14SValentin Clement     return fir::LogicalType::get(context, KIND);
88ad40cc14SValentin Clement   return {};
89ad40cc14SValentin Clement }
90ad40cc14SValentin Clement 
918c22cb84SValentin Clement static mlir::Type genCharacterType(
928c22cb84SValentin Clement     mlir::MLIRContext *context, int KIND,
938c22cb84SValentin Clement     Fortran::lower::LenParameterTy len = fir::CharacterType::unknownLen()) {
948c22cb84SValentin Clement   if (Fortran::evaluate::IsValidKindOfIntrinsicType(
958c22cb84SValentin Clement           Fortran::common::TypeCategory::Character, KIND))
968c22cb84SValentin Clement     return fir::CharacterType::get(context, KIND, len);
978c22cb84SValentin Clement   return {};
988c22cb84SValentin Clement }
998c22cb84SValentin Clement 
1001ceb1d9bSValentin Clement static mlir::Type genComplexType(mlir::MLIRContext *context, int KIND) {
101c4204c0bSjeanPerier   return mlir::ComplexType::get(genRealType(context, KIND));
1021ceb1d9bSValentin Clement }
1031ceb1d9bSValentin Clement 
1048c22cb84SValentin Clement static mlir::Type
1058c22cb84SValentin Clement genFIRType(mlir::MLIRContext *context, Fortran::common::TypeCategory tc,
1068c22cb84SValentin Clement            int kind,
1078c22cb84SValentin Clement            llvm::ArrayRef<Fortran::lower::LenParameterTy> lenParameters) {
108ad40cc14SValentin Clement   switch (tc) {
109ad40cc14SValentin Clement   case Fortran::common::TypeCategory::Real:
1100a0b3029SValentin Clement     return genRealType(context, kind);
111ad40cc14SValentin Clement   case Fortran::common::TypeCategory::Integer:
112fc97d2e6SPeter Klausler     return genIntegerType(context, kind, false);
113fc97d2e6SPeter Klausler   case Fortran::common::TypeCategory::Unsigned:
114fc97d2e6SPeter Klausler     return genIntegerType(context, kind, true);
115ad40cc14SValentin Clement   case Fortran::common::TypeCategory::Complex:
1161ceb1d9bSValentin Clement     return genComplexType(context, kind);
117ad40cc14SValentin Clement   case Fortran::common::TypeCategory::Logical:
118ad40cc14SValentin Clement     return genLogicalType(context, kind);
119ad40cc14SValentin Clement   case Fortran::common::TypeCategory::Character:
1208c22cb84SValentin Clement     if (!lenParameters.empty())
1218c22cb84SValentin Clement       return genCharacterType(context, kind, lenParameters[0]);
1228c22cb84SValentin Clement     return genCharacterType(context, kind);
123ad40cc14SValentin Clement   default:
124ad40cc14SValentin Clement     break;
125ad40cc14SValentin Clement   }
126ad40cc14SValentin Clement   llvm_unreachable("unhandled type category");
127baa12ddbSEric Schweitz }
128baa12ddbSEric Schweitz 
129307ccf4cSValentin Clement //===--------------------------------------------------------------------===//
130307ccf4cSValentin Clement // Symbol and expression type translation
131307ccf4cSValentin Clement //===--------------------------------------------------------------------===//
132baa12ddbSEric Schweitz 
133d71c1de0SJean Perier /// TypeBuilderImpl translates expression and symbol type taking into account
134307ccf4cSValentin Clement /// their shape and length parameters. For symbols, attributes such as
135307ccf4cSValentin Clement /// ALLOCATABLE or POINTER are reflected in the fir type.
136307ccf4cSValentin Clement /// It uses evaluate::DynamicType and evaluate::Shape when possible to
137307ccf4cSValentin Clement /// avoid re-implementing type/shape analysis here.
138307ccf4cSValentin Clement /// Do not use the FirOpBuilder from the AbstractConverter to get fir/mlir types
139307ccf4cSValentin Clement /// since it is not guaranteed to exist yet when we lower types.
140baa12ddbSEric Schweitz namespace {
141d71c1de0SJean Perier struct TypeBuilderImpl {
1429aeb7f03SValentin Clement 
143d71c1de0SJean Perier   TypeBuilderImpl(Fortran::lower::AbstractConverter &converter)
144c373f581SjeanPerier       : derivedTypeInConstruction{converter.getTypeConstructionStack()},
145c373f581SjeanPerier         converter{converter}, context{&converter.getMLIRContext()} {}
146ad40cc14SValentin Clement 
147d71c1de0SJean Perier   template <typename A>
148d71c1de0SJean Perier   mlir::Type genExprType(const A &expr) {
149e641c29fSValentin Clement     std::optional<Fortran::evaluate::DynamicType> dynamicType = expr.GetType();
150e641c29fSValentin Clement     if (!dynamicType)
151e641c29fSValentin Clement       return genTypelessExprType(expr);
152e641c29fSValentin Clement     Fortran::common::TypeCategory category = dynamicType->category();
153e641c29fSValentin Clement 
154e641c29fSValentin Clement     mlir::Type baseType;
1551e413b90SValentin Clement     bool isPolymorphic = (dynamicType->IsPolymorphic() ||
1561e413b90SValentin Clement                           dynamicType->IsUnlimitedPolymorphic()) &&
1571e413b90SValentin Clement                          !dynamicType->IsAssumedType();
158c1b7e9c9SValentin Clement     if (dynamicType->IsUnlimitedPolymorphic()) {
159c1b7e9c9SValentin Clement       baseType = mlir::NoneType::get(context);
160c1b7e9c9SValentin Clement     } else if (category == Fortran::common::TypeCategory::Derived) {
161589d51eaSValentin Clement       baseType = genDerivedType(dynamicType->GetDerivedTypeSpec());
162e641c29fSValentin Clement     } else {
163fc97d2e6SPeter Klausler       // INTEGER, UNSIGNED, REAL, COMPLEX, CHARACTER, LOGICAL
1648c22cb84SValentin Clement       llvm::SmallVector<Fortran::lower::LenParameterTy> params;
1658c22cb84SValentin Clement       translateLenParameters(params, category, expr);
1668c22cb84SValentin Clement       baseType = genFIRType(context, category, dynamicType->kind(), params);
167e641c29fSValentin Clement     }
168e641c29fSValentin Clement     std::optional<Fortran::evaluate::Shape> shapeExpr =
169e641c29fSValentin Clement         Fortran::evaluate::GetShape(converter.getFoldingContext(), expr);
170e641c29fSValentin Clement     fir::SequenceType::Shape shape;
171e641c29fSValentin Clement     if (shapeExpr) {
172e641c29fSValentin Clement       translateShape(shape, std::move(*shapeExpr));
173e641c29fSValentin Clement     } else {
174e641c29fSValentin Clement       // Shape static analysis cannot return something useful for the shape.
175e641c29fSValentin Clement       // Use unknown extents.
176e641c29fSValentin Clement       int rank = expr.Rank();
177e641c29fSValentin Clement       if (rank < 0)
17839377d52SValentin Clement         TODO(converter.getCurrentLocation(), "assumed rank expression types");
179e641c29fSValentin Clement       for (int dim = 0; dim < rank; ++dim)
180e641c29fSValentin Clement         shape.emplace_back(fir::SequenceType::getUnknownExtent());
181e641c29fSValentin Clement     }
1821e413b90SValentin Clement 
1831e413b90SValentin Clement     if (!shape.empty()) {
1841e413b90SValentin Clement       if (isPolymorphic)
1851e413b90SValentin Clement         return fir::ClassType::get(fir::SequenceType::get(shape, baseType));
186e641c29fSValentin Clement       return fir::SequenceType::get(shape, baseType);
1871e413b90SValentin Clement     }
1881e413b90SValentin Clement     if (isPolymorphic)
1891e413b90SValentin Clement       return fir::ClassType::get(baseType);
190e641c29fSValentin Clement     return baseType;
191e641c29fSValentin Clement   }
192e641c29fSValentin Clement 
193ad40cc14SValentin Clement   template <typename A>
194c807aa53SValentin Clement   void translateShape(A &shape, Fortran::evaluate::Shape &&shapeExpr) {
195c807aa53SValentin Clement     for (Fortran::evaluate::MaybeExtentExpr extentExpr : shapeExpr) {
196c807aa53SValentin Clement       fir::SequenceType::Extent extent = fir::SequenceType::getUnknownExtent();
197c807aa53SValentin Clement       if (std::optional<std::int64_t> constantExtent =
198c807aa53SValentin Clement               toInt64(std::move(extentExpr)))
199c807aa53SValentin Clement         extent = *constantExtent;
200c807aa53SValentin Clement       shape.push_back(extent);
201c807aa53SValentin Clement     }
202c807aa53SValentin Clement   }
203c807aa53SValentin Clement 
204c807aa53SValentin Clement   template <typename A>
205ad40cc14SValentin Clement   std::optional<std::int64_t> toInt64(A &&expr) {
206ad40cc14SValentin Clement     return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
207ad40cc14SValentin Clement         converter.getFoldingContext(), std::move(expr)));
208ad40cc14SValentin Clement   }
209ad40cc14SValentin Clement 
210d71c1de0SJean Perier   template <typename A>
211d71c1de0SJean Perier   mlir::Type genTypelessExprType(const A &expr) {
212d71c1de0SJean Perier     fir::emitFatalError(converter.getCurrentLocation(), "not a typeless expr");
213d71c1de0SJean Perier   }
214d71c1de0SJean Perier 
215e641c29fSValentin Clement   mlir::Type genTypelessExprType(const Fortran::lower::SomeExpr &expr) {
21677d8cfb3SAlexander Shaposhnikov     return Fortran::common::visit(
217e641c29fSValentin Clement         Fortran::common::visitors{
218e641c29fSValentin Clement             [&](const Fortran::evaluate::BOZLiteralConstant &) -> mlir::Type {
219e641c29fSValentin Clement               return mlir::NoneType::get(context);
220e641c29fSValentin Clement             },
221e641c29fSValentin Clement             [&](const Fortran::evaluate::NullPointer &) -> mlir::Type {
222e641c29fSValentin Clement               return fir::ReferenceType::get(mlir::NoneType::get(context));
223e641c29fSValentin Clement             },
224e641c29fSValentin Clement             [&](const Fortran::evaluate::ProcedureDesignator &proc)
225e641c29fSValentin Clement                 -> mlir::Type {
2269aeb7f03SValentin Clement               return Fortran::lower::translateSignature(proc, converter);
227e641c29fSValentin Clement             },
228e641c29fSValentin Clement             [&](const Fortran::evaluate::ProcedureRef &) -> mlir::Type {
229e641c29fSValentin Clement               return mlir::NoneType::get(context);
230e641c29fSValentin Clement             },
231e641c29fSValentin Clement             [](const auto &x) -> mlir::Type {
232e641c29fSValentin Clement               using T = std::decay_t<decltype(x)>;
233e641c29fSValentin Clement               static_assert(!Fortran::common::HasMember<
234e641c29fSValentin Clement                                 T, Fortran::evaluate::TypelessExpression>,
23539377d52SValentin Clement                             "missing typeless expr handling");
236e641c29fSValentin Clement               llvm::report_fatal_error("not a typeless expression");
237e641c29fSValentin Clement             },
238e641c29fSValentin Clement         },
239e641c29fSValentin Clement         expr.u);
240e641c29fSValentin Clement   }
241e641c29fSValentin Clement 
242ad40cc14SValentin Clement   mlir::Type genSymbolType(const Fortran::semantics::Symbol &symbol,
243ad40cc14SValentin Clement                            bool isAlloc = false, bool isPtr = false) {
244ad40cc14SValentin Clement     mlir::Location loc = converter.genLocation(symbol.name());
245ad40cc14SValentin Clement     mlir::Type ty;
246ad40cc14SValentin Clement     // If the symbol is not the same as the ultimate one (i.e, it is host or use
247ad40cc14SValentin Clement     // associated), all the symbol properties are the ones of the ultimate
248ad40cc14SValentin Clement     // symbol but the volatile and asynchronous attributes that may differ. To
249ad40cc14SValentin Clement     // avoid issues with helper functions that would not follow association
250ad40cc14SValentin Clement     // links, the fir type is built based on the ultimate symbol. This relies
251ad40cc14SValentin Clement     // on the fact volatile and asynchronous are not reflected in fir types.
252ad40cc14SValentin Clement     const Fortran::semantics::Symbol &ultimate = symbol.GetUltimate();
253af09219eSDaniel Chen 
254af09219eSDaniel Chen     if (Fortran::semantics::IsProcedurePointer(ultimate)) {
255af09219eSDaniel Chen       Fortran::evaluate::ProcedureDesignator proc(ultimate);
256af09219eSDaniel Chen       auto procTy{Fortran::lower::translateSignature(proc, converter)};
257af09219eSDaniel Chen       return fir::BoxProcType::get(context, procTy);
258af09219eSDaniel Chen     }
259af09219eSDaniel Chen 
260ad40cc14SValentin Clement     if (const Fortran::semantics::DeclTypeSpec *type = ultimate.GetType()) {
261ad40cc14SValentin Clement       if (const Fortran::semantics::IntrinsicTypeSpec *tySpec =
262ad40cc14SValentin Clement               type->AsIntrinsic()) {
263ad40cc14SValentin Clement         int kind = toInt64(Fortran::common::Clone(tySpec->kind())).value();
2648c22cb84SValentin Clement         llvm::SmallVector<Fortran::lower::LenParameterTy> params;
2658c22cb84SValentin Clement         translateLenParameters(params, tySpec->category(), ultimate);
2668c22cb84SValentin Clement         ty = genFIRType(context, tySpec->category(), kind, params);
2679d99b482SValentin Clement       } else if (type->IsUnlimitedPolymorphic()) {
2689d99b482SValentin Clement         ty = mlir::NoneType::get(context);
269589d51eaSValentin Clement       } else if (const Fortran::semantics::DerivedTypeSpec *tySpec =
270589d51eaSValentin Clement                      type->AsDerived()) {
271589d51eaSValentin Clement         ty = genDerivedType(*tySpec);
272ad40cc14SValentin Clement       } else {
273ad40cc14SValentin Clement         fir::emitFatalError(loc, "symbol's type must have a type spec");
274ad40cc14SValentin Clement       }
275ad40cc14SValentin Clement     } else {
276ad40cc14SValentin Clement       fir::emitFatalError(loc, "symbol must have a type");
277ad40cc14SValentin Clement     }
2781e413b90SValentin Clement     bool isPolymorphic = (Fortran::semantics::IsPolymorphic(symbol) ||
2791e413b90SValentin Clement                           Fortran::semantics::IsUnlimitedPolymorphic(symbol)) &&
2801e413b90SValentin Clement                          !Fortran::semantics::IsAssumedType(symbol);
281c807aa53SValentin Clement     if (ultimate.IsObjectArray()) {
2820c0b2ea9SPeter Klausler       auto shapeExpr =
2830c0b2ea9SPeter Klausler           Fortran::evaluate::GetShape(converter.getFoldingContext(), ultimate);
284c807aa53SValentin Clement       fir::SequenceType::Shape shape;
2854abbf995SjeanPerier       // If there is no shapExpr, this is an assumed-rank, and the empty shape
2864abbf995SjeanPerier       // will build the desired fir.array<*:T> type.
2874abbf995SjeanPerier       if (shapeExpr)
288c807aa53SValentin Clement         translateShape(shape, std::move(*shapeExpr));
289c807aa53SValentin Clement       ty = fir::SequenceType::get(shape, ty);
290c807aa53SValentin Clement     }
291ad40cc14SValentin Clement     if (Fortran::semantics::IsPointer(symbol))
2921e413b90SValentin Clement       return fir::wrapInClassOrBoxType(fir::PointerType::get(ty),
2931e413b90SValentin Clement                                        isPolymorphic);
294ad40cc14SValentin Clement     if (Fortran::semantics::IsAllocatable(symbol))
2951e413b90SValentin Clement       return fir::wrapInClassOrBoxType(fir::HeapType::get(ty), isPolymorphic);
296ad40cc14SValentin Clement     // isPtr and isAlloc are variable that were promoted to be on the
297ad40cc14SValentin Clement     // heap or to be pointers, but they do not have Fortran allocatable
298ad40cc14SValentin Clement     // or pointer semantics, so do not use box for them.
299ad40cc14SValentin Clement     if (isPtr)
300ad40cc14SValentin Clement       return fir::PointerType::get(ty);
301ad40cc14SValentin Clement     if (isAlloc)
302ad40cc14SValentin Clement       return fir::HeapType::get(ty);
3031e413b90SValentin Clement     if (isPolymorphic)
3041e413b90SValentin Clement       return fir::ClassType::get(ty);
305ad40cc14SValentin Clement     return ty;
306ad40cc14SValentin Clement   }
307baa12ddbSEric Schweitz 
308589d51eaSValentin Clement   /// Does \p component has non deferred lower bounds that are not compile time
309589d51eaSValentin Clement   /// constant 1.
310589d51eaSValentin Clement   static bool componentHasNonDefaultLowerBounds(
311589d51eaSValentin Clement       const Fortran::semantics::Symbol &component) {
312589d51eaSValentin Clement     if (const auto *objDetails =
313589d51eaSValentin Clement             component.detailsIf<Fortran::semantics::ObjectEntityDetails>())
314589d51eaSValentin Clement       for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape())
315589d51eaSValentin Clement         if (auto lb = bounds.lbound().GetExplicit())
316589d51eaSValentin Clement           if (auto constant = Fortran::evaluate::ToInt64(*lb))
317589d51eaSValentin Clement             if (!constant || *constant != 1)
318589d51eaSValentin Clement               return true;
319589d51eaSValentin Clement     return false;
320589d51eaSValentin Clement   }
321589d51eaSValentin Clement 
322ef934174SKelvin Li   mlir::Type genVectorType(const Fortran::semantics::DerivedTypeSpec &tySpec) {
323ef934174SKelvin Li     assert(tySpec.scope() && "Missing scope for Vector type");
324ef934174SKelvin Li     auto vectorSize{tySpec.scope()->size()};
325ef934174SKelvin Li     switch (tySpec.category()) {
326ef934174SKelvin Li       SWITCH_COVERS_ALL_CASES
327ef934174SKelvin Li     case (Fortran::semantics::DerivedTypeSpec::Category::IntrinsicVector): {
328ef934174SKelvin Li       int64_t vecElemKind;
329ef934174SKelvin Li       int64_t vecElemCategory;
330ef934174SKelvin Li 
331ef934174SKelvin Li       for (const auto &pair : tySpec.parameters()) {
332ef934174SKelvin Li         if (pair.first == "element_category") {
333ef934174SKelvin Li           vecElemCategory =
334ef934174SKelvin Li               Fortran::evaluate::ToInt64(pair.second.GetExplicit())
335ef934174SKelvin Li                   .value_or(-1);
336ef934174SKelvin Li         } else if (pair.first == "element_kind") {
337ef934174SKelvin Li           vecElemKind =
338ef934174SKelvin Li               Fortran::evaluate::ToInt64(pair.second.GetExplicit()).value_or(0);
339ef934174SKelvin Li         }
340ef934174SKelvin Li       }
341ef934174SKelvin Li 
342ef934174SKelvin Li       assert((vecElemCategory >= 0 &&
343ef934174SKelvin Li               static_cast<size_t>(vecElemCategory) <
344ef934174SKelvin Li                   Fortran::common::VectorElementCategory_enumSize) &&
345ef934174SKelvin Li              "Vector element type is not specified");
346ef934174SKelvin Li       assert(vecElemKind && "Vector element kind is not specified");
347ef934174SKelvin Li 
348ef934174SKelvin Li       int64_t numOfElements = vectorSize / vecElemKind;
349ef934174SKelvin Li       switch (static_cast<VectorElementCategory>(vecElemCategory)) {
350ef934174SKelvin Li         SWITCH_COVERS_ALL_CASES
351ef934174SKelvin Li       case VectorElementCategory::Integer:
352ef934174SKelvin Li         return fir::VectorType::get(numOfElements,
353ef934174SKelvin Li                                     genIntegerType(context, vecElemKind));
354ef934174SKelvin Li       case VectorElementCategory::Unsigned:
355ef934174SKelvin Li         return fir::VectorType::get(numOfElements,
356ef934174SKelvin Li                                     genIntegerType(context, vecElemKind, true));
357ef934174SKelvin Li       case VectorElementCategory::Real:
358ef934174SKelvin Li         return fir::VectorType::get(numOfElements,
359ef934174SKelvin Li                                     genRealType(context, vecElemKind));
360ef934174SKelvin Li       }
361ef934174SKelvin Li       break;
362ef934174SKelvin Li     }
363ef934174SKelvin Li     case (Fortran::semantics::DerivedTypeSpec::Category::PairVector):
364ef934174SKelvin Li     case (Fortran::semantics::DerivedTypeSpec::Category::QuadVector):
365ef934174SKelvin Li       return fir::VectorType::get(vectorSize * 8,
366ef934174SKelvin Li                                   mlir::IntegerType::get(context, 1));
367ef934174SKelvin Li     case (Fortran::semantics::DerivedTypeSpec::Category::DerivedType):
368ef934174SKelvin Li       Fortran::common::die("Vector element type not implemented");
369ef934174SKelvin Li     }
370ef934174SKelvin Li   }
371ef934174SKelvin Li 
372589d51eaSValentin Clement   mlir::Type genDerivedType(const Fortran::semantics::DerivedTypeSpec &tySpec) {
373589d51eaSValentin Clement     std::vector<std::pair<std::string, mlir::Type>> ps;
374589d51eaSValentin Clement     std::vector<std::pair<std::string, mlir::Type>> cs;
375ef934174SKelvin Li     if (tySpec.IsVectorType()) {
376ef934174SKelvin Li       return genVectorType(tySpec);
377ef934174SKelvin Li     }
378ef934174SKelvin Li 
37984564e10SjeanPerier     const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
380e45f6e93SjeanPerier     const Fortran::semantics::Scope &derivedScope = DEREF(tySpec.GetScope());
38184564e10SjeanPerier     if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(derivedScope))
38284564e10SjeanPerier       return ty;
383e45f6e93SjeanPerier 
3842c143345SV Donaldson     auto rec = fir::RecordType::get(context, converter.mangleName(tySpec));
38584564e10SjeanPerier     // Maintain the stack of types for recursive references and to speed-up
38684564e10SjeanPerier     // the derived type constructions that can be expensive for derived type
38784564e10SjeanPerier     // with dozens of components/parents (modern Fortran).
38884564e10SjeanPerier     derivedTypeInConstruction.try_emplace(&derivedScope, rec);
389589d51eaSValentin Clement 
39079e788d0SKelvin Li     auto targetTriple{llvm::Triple(
39179e788d0SKelvin Li         llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
39279e788d0SKelvin Li     // Always generate packed FIR struct type for bind(c) derived type for AIX
39379e788d0SKelvin Li     if (targetTriple.getOS() == llvm::Triple::OSType::AIX &&
39479e788d0SKelvin Li         tySpec.typeSymbol().attrs().test(Fortran::semantics::Attr::BIND_C) &&
395d305fd0bSKelvin Li         !IsIsoCType(&tySpec) && !fir::isa_builtin_cdevptr_type(rec)) {
39679e788d0SKelvin Li       rec.pack(true);
39779e788d0SKelvin Li     }
39879e788d0SKelvin Li 
399589d51eaSValentin Clement     // Gather the record type fields.
400589d51eaSValentin Clement     // (1) The data components.
401e45f6e93SjeanPerier     if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
40279e788d0SKelvin Li       size_t prev_offset{0};
40379e788d0SKelvin Li       unsigned padCounter{0};
404e45f6e93SjeanPerier       // In HLFIR the parent component is the first fir.type component.
405e45f6e93SjeanPerier       for (const auto &componentName :
406e45f6e93SjeanPerier            typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
407e45f6e93SjeanPerier                .componentNames()) {
408e45f6e93SjeanPerier         auto scopeIter = derivedScope.find(componentName);
409e45f6e93SjeanPerier         assert(scopeIter != derivedScope.cend() &&
410e45f6e93SjeanPerier                "failed to find derived type component symbol");
411e45f6e93SjeanPerier         const Fortran::semantics::Symbol &component = scopeIter->second.get();
412e45f6e93SjeanPerier         mlir::Type ty = genSymbolType(component);
41379e788d0SKelvin Li         if (rec.isPacked()) {
41479e788d0SKelvin Li           auto compSize{component.size()};
41579e788d0SKelvin Li           auto compOffset{component.offset()};
41679e788d0SKelvin Li 
41779e788d0SKelvin Li           if (prev_offset < compOffset) {
41879e788d0SKelvin Li             size_t pad{compOffset - prev_offset};
41979e788d0SKelvin Li             mlir::Type i8Ty{mlir::IntegerType::get(context, 8)};
42079e788d0SKelvin Li             fir::SequenceType::Shape shape{static_cast<int64_t>(pad)};
42179e788d0SKelvin Li             mlir::Type padTy{fir::SequenceType::get(shape, i8Ty)};
42279e788d0SKelvin Li             prev_offset += pad;
42379e788d0SKelvin Li             cs.emplace_back("__padding" + std::to_string(padCounter++), padTy);
42479e788d0SKelvin Li           }
42579e788d0SKelvin Li           prev_offset += compSize;
42679e788d0SKelvin Li         }
427e45f6e93SjeanPerier         cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
42879e788d0SKelvin Li         if (rec.isPacked()) {
42979e788d0SKelvin Li           // For the last component, determine if any padding is needed.
43079e788d0SKelvin Li           if (componentName ==
43179e788d0SKelvin Li               typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
43279e788d0SKelvin Li                   .componentNames()
43379e788d0SKelvin Li                   .back()) {
43479e788d0SKelvin Li             auto compEnd{component.offset() + component.size()};
43579e788d0SKelvin Li             if (compEnd < derivedScope.size()) {
43679e788d0SKelvin Li               size_t pad{derivedScope.size() - compEnd};
43779e788d0SKelvin Li               mlir::Type i8Ty{mlir::IntegerType::get(context, 8)};
43879e788d0SKelvin Li               fir::SequenceType::Shape shape{static_cast<int64_t>(pad)};
43979e788d0SKelvin Li               mlir::Type padTy{fir::SequenceType::get(shape, i8Ty)};
44079e788d0SKelvin Li               cs.emplace_back("__padding" + std::to_string(padCounter++),
44179e788d0SKelvin Li                               padTy);
44279e788d0SKelvin Li             }
44379e788d0SKelvin Li           }
44479e788d0SKelvin Li         }
445e45f6e93SjeanPerier       }
446e45f6e93SjeanPerier     } else {
44799a54b83SjeanPerier       for (const auto &component :
448589d51eaSValentin Clement            Fortran::semantics::OrderedComponentIterator(tySpec)) {
449e45f6e93SjeanPerier         // In the lowering to FIR the parent component does not appear in the
450e45f6e93SjeanPerier         // fir.type and its components are inlined at the beginning of the
451e45f6e93SjeanPerier         // fir.type<>.
452e45f6e93SjeanPerier         // FIXME: this strategy leads to bugs because padding should be inserted
453e45f6e93SjeanPerier         // after the component of the parents so that the next components do not
454e45f6e93SjeanPerier         // end-up in the parent storage if the sum of the parent's component
455e45f6e93SjeanPerier         // storage size is not a multiple of the parent type storage alignment.
456e45f6e93SjeanPerier 
457e45f6e93SjeanPerier         // Lowering is assuming non deferred component lower bounds are
458e45f6e93SjeanPerier         // always 1. Catch any situations where this is not true for now.
459e45f6e93SjeanPerier         if (componentHasNonDefaultLowerBounds(component))
46099a54b83SjeanPerier           TODO(converter.genLocation(component.name()),
46139377d52SValentin Clement                "derived type components with non default lower bounds");
46299a54b83SjeanPerier         if (IsProcedure(component))
46399a54b83SjeanPerier           TODO(converter.genLocation(component.name()), "procedure components");
46499a54b83SjeanPerier         mlir::Type ty = genSymbolType(component);
465589d51eaSValentin Clement         // Do not add the parent component (component of the parents are
466589d51eaSValentin Clement         // added and should be sufficient, the parent component would
467e45f6e93SjeanPerier         // duplicate the fields). Note that genSymbolType must be called above
468e45f6e93SjeanPerier         // on it so that the dispatch table for the parent type still gets
469e45f6e93SjeanPerier         // emitted as needed.
47099a54b83SjeanPerier         if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
471589d51eaSValentin Clement           continue;
47299a54b83SjeanPerier         cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
473589d51eaSValentin Clement       }
474e45f6e93SjeanPerier     }
475589d51eaSValentin Clement 
476be30cd62SjeanPerier     mlir::Location loc = converter.genLocation(typeSymbol.name());
477589d51eaSValentin Clement     // (2) The LEN type parameters.
478589d51eaSValentin Clement     for (const auto &param :
479589d51eaSValentin Clement          Fortran::semantics::OrderParameterDeclarations(typeSymbol))
480589d51eaSValentin Clement       if (param->get<Fortran::semantics::TypeParamDetails>().attr() ==
481be30cd62SjeanPerier           Fortran::common::TypeParamAttr::Len) {
482be30cd62SjeanPerier         TODO(loc, "parameterized derived types");
483be30cd62SjeanPerier         // TODO: emplace in ps. Beware that param is the symbol in the type
484be30cd62SjeanPerier         // declaration, not instantiation: its kind may not be a constant.
485be30cd62SjeanPerier         // The instantiated symbol in tySpec.scope should be used instead.
486589d51eaSValentin Clement         ps.emplace_back(param->name().ToString(), genSymbolType(*param));
487be30cd62SjeanPerier       }
488589d51eaSValentin Clement 
489589d51eaSValentin Clement     rec.finalize(ps, cs);
490589d51eaSValentin Clement 
491589d51eaSValentin Clement     if (!ps.empty()) {
492be30cd62SjeanPerier       // TODO: this type is a PDT (parametric derived type) with length
493be30cd62SjeanPerier       // parameter. Create the functions to use for allocation, dereferencing,
494be30cd62SjeanPerier       // and address arithmetic here.
495589d51eaSValentin Clement     }
496589d51eaSValentin Clement     LLVM_DEBUG(llvm::dbgs() << "derived type: " << rec << '\n');
4979aeb7f03SValentin Clement 
4989aeb7f03SValentin Clement     // Generate the type descriptor object if any
4999aeb7f03SValentin Clement     if (const Fortran::semantics::Symbol *typeInfoSym =
500e45f6e93SjeanPerier             derivedScope.runtimeDerivedTypeDescription())
5014ccd57ddSjeanPerier       converter.registerTypeInfo(loc, *typeInfoSym, tySpec, rec);
502589d51eaSValentin Clement     return rec;
503589d51eaSValentin Clement   }
504589d51eaSValentin Clement 
5058c22cb84SValentin Clement   // To get the character length from a symbol, make an fold a designator for
5068c22cb84SValentin Clement   // the symbol to cover the case where the symbol is an assumed length named
5078c22cb84SValentin Clement   // constant and its length comes from its init expression length.
5088c22cb84SValentin Clement   template <int Kind>
5098c22cb84SValentin Clement   fir::SequenceType::Extent
5108c22cb84SValentin Clement   getCharacterLengthHelper(const Fortran::semantics::Symbol &symbol) {
5118c22cb84SValentin Clement     using TC =
5128c22cb84SValentin Clement         Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, Kind>;
5138c22cb84SValentin Clement     auto designator = Fortran::evaluate::Fold(
5148c22cb84SValentin Clement         converter.getFoldingContext(),
5158c22cb84SValentin Clement         Fortran::evaluate::Expr<TC>{Fortran::evaluate::Designator<TC>{symbol}});
5168c22cb84SValentin Clement     if (auto len = toInt64(std::move(designator.LEN())))
5178c22cb84SValentin Clement       return *len;
5188c22cb84SValentin Clement     return fir::SequenceType::getUnknownExtent();
5198c22cb84SValentin Clement   }
5208c22cb84SValentin Clement 
5218c22cb84SValentin Clement   template <typename T>
5228c22cb84SValentin Clement   void translateLenParameters(
5238c22cb84SValentin Clement       llvm::SmallVectorImpl<Fortran::lower::LenParameterTy> &params,
5248c22cb84SValentin Clement       Fortran::common::TypeCategory category, const T &exprOrSym) {
5258c22cb84SValentin Clement     if (category == Fortran::common::TypeCategory::Character)
5268c22cb84SValentin Clement       params.push_back(getCharacterLength(exprOrSym));
5278c22cb84SValentin Clement     else if (category == Fortran::common::TypeCategory::Derived)
52839377d52SValentin Clement       TODO(converter.getCurrentLocation(), "derived type length parameters");
5298c22cb84SValentin Clement   }
5308c22cb84SValentin Clement   Fortran::lower::LenParameterTy
5318c22cb84SValentin Clement   getCharacterLength(const Fortran::semantics::Symbol &symbol) {
5328c22cb84SValentin Clement     const Fortran::semantics::DeclTypeSpec *type = symbol.GetType();
5338c22cb84SValentin Clement     if (!type ||
5348c22cb84SValentin Clement         type->category() != Fortran::semantics::DeclTypeSpec::Character ||
5358c22cb84SValentin Clement         !type->AsIntrinsic())
5368c22cb84SValentin Clement       llvm::report_fatal_error("not a character symbol");
5378c22cb84SValentin Clement     int kind =
5388c22cb84SValentin Clement         toInt64(Fortran::common::Clone(type->AsIntrinsic()->kind())).value();
5398c22cb84SValentin Clement     switch (kind) {
5408c22cb84SValentin Clement     case 1:
5418c22cb84SValentin Clement       return getCharacterLengthHelper<1>(symbol);
5428c22cb84SValentin Clement     case 2:
5438c22cb84SValentin Clement       return getCharacterLengthHelper<2>(symbol);
5448c22cb84SValentin Clement     case 4:
5458c22cb84SValentin Clement       return getCharacterLengthHelper<4>(symbol);
5468c22cb84SValentin Clement     }
5478c22cb84SValentin Clement     llvm_unreachable("unknown character kind");
5488c22cb84SValentin Clement   }
549d71c1de0SJean Perier 
550d71c1de0SJean Perier   template <typename A>
551d71c1de0SJean Perier   Fortran::lower::LenParameterTy getCharacterLength(const A &expr) {
552d71c1de0SJean Perier     return fir::SequenceType::getUnknownExtent();
553d71c1de0SJean Perier   }
554da78ae46SJean Perier 
555da78ae46SJean Perier   template <typename T>
556da78ae46SJean Perier   Fortran::lower::LenParameterTy
557da78ae46SJean Perier   getCharacterLength(const Fortran::evaluate::FunctionRef<T> &funcRef) {
558da78ae46SJean Perier     if (auto constantLen = toInt64(funcRef.LEN()))
559da78ae46SJean Perier       return *constantLen;
560da78ae46SJean Perier     return fir::SequenceType::getUnknownExtent();
561da78ae46SJean Perier   }
562da78ae46SJean Perier 
5638c22cb84SValentin Clement   Fortran::lower::LenParameterTy
5648c22cb84SValentin Clement   getCharacterLength(const Fortran::lower::SomeExpr &expr) {
5658c22cb84SValentin Clement     // Do not use dynamic type length here. We would miss constant
5668c22cb84SValentin Clement     // lengths opportunities because dynamic type only has the length
5678c22cb84SValentin Clement     // if it comes from a declaration.
568d8d91b2aSJean Perier     if (const auto *charExpr = std::get_if<
569d8d91b2aSJean Perier             Fortran::evaluate::Expr<Fortran::evaluate::SomeCharacter>>(
570d8d91b2aSJean Perier             &expr.u)) {
571d8d91b2aSJean Perier       if (auto constantLen = toInt64(charExpr->LEN()))
5728c22cb84SValentin Clement         return *constantLen;
573d8d91b2aSJean Perier     } else if (auto dynamicType = expr.GetType()) {
574d8d91b2aSJean Perier       // When generating derived type type descriptor as structure constructor,
575d8d91b2aSJean Perier       // semantics wraps designators to data component initialization into
576d8d91b2aSJean Perier       // CLASS(*), regardless of their actual type.
577d8d91b2aSJean Perier       // GetType() will recover the actual symbol type as the dynamic type, so
578d8d91b2aSJean Perier       // getCharacterLength may be reached even if expr is packaged as an
579d8d91b2aSJean Perier       // Expr<SomeDerived> instead of an Expr<SomeChar>.
580d8d91b2aSJean Perier       // Just use the dynamic type here again to retrieve the length.
581d8d91b2aSJean Perier       if (auto constantLen = toInt64(dynamicType->GetCharLength()))
582d8d91b2aSJean Perier         return *constantLen;
583d8d91b2aSJean Perier     }
5848c22cb84SValentin Clement     return fir::SequenceType::getUnknownExtent();
5858c22cb84SValentin Clement   }
5868c22cb84SValentin Clement 
5872c2e5a5dSValentin Clement   mlir::Type genVariableType(const Fortran::lower::pft::Variable &var) {
588ad40cc14SValentin Clement     return genSymbolType(var.getSymbol(), var.isHeapAlloc(), var.isPointer());
589baa12ddbSEric Schweitz   }
590baa12ddbSEric Schweitz 
591589d51eaSValentin Clement   /// Derived type can be recursive. That is, pointer components of a derived
592589d51eaSValentin Clement   /// type `t` have type `t`. This helper returns `t` if it is already being
593589d51eaSValentin Clement   /// lowered to avoid infinite loops.
594589d51eaSValentin Clement   mlir::Type getTypeIfDerivedAlreadyInConstruction(
59584564e10SjeanPerier       const Fortran::semantics::Scope &derivedScope) const {
59684564e10SjeanPerier     return derivedTypeInConstruction.lookup(&derivedScope);
597589d51eaSValentin Clement   }
598589d51eaSValentin Clement 
599589d51eaSValentin Clement   /// Stack derived type being processed to avoid infinite loops in case of
600589d51eaSValentin Clement   /// recursive derived types. The depth of derived types is expected to be
601589d51eaSValentin Clement   /// shallow (<10), so a SmallVector is sufficient.
602c373f581SjeanPerier   Fortran::lower::TypeConstructionStack &derivedTypeInConstruction;
603ad40cc14SValentin Clement   Fortran::lower::AbstractConverter &converter;
604baa12ddbSEric Schweitz   mlir::MLIRContext *context;
605baa12ddbSEric Schweitz };
606baa12ddbSEric Schweitz } // namespace
607baa12ddbSEric Schweitz 
608dc6a3446SValentin Clement mlir::Type Fortran::lower::getFIRType(mlir::MLIRContext *context,
609dc6a3446SValentin Clement                                       Fortran::common::TypeCategory tc,
6108c22cb84SValentin Clement                                       int kind,
6118c22cb84SValentin Clement                                       llvm::ArrayRef<LenParameterTy> params) {
6128c22cb84SValentin Clement   return genFIRType(context, tc, kind, params);
613baa12ddbSEric Schweitz }
614baa12ddbSEric Schweitz 
615589d51eaSValentin Clement mlir::Type Fortran::lower::translateDerivedTypeToFIRType(
616589d51eaSValentin Clement     Fortran::lower::AbstractConverter &converter,
617589d51eaSValentin Clement     const Fortran::semantics::DerivedTypeSpec &tySpec) {
618d71c1de0SJean Perier   return TypeBuilderImpl{converter}.genDerivedType(tySpec);
619589d51eaSValentin Clement }
620589d51eaSValentin Clement 
621baa12ddbSEric Schweitz mlir::Type Fortran::lower::translateSomeExprToFIRType(
622e641c29fSValentin Clement     Fortran::lower::AbstractConverter &converter, const SomeExpr &expr) {
623d71c1de0SJean Perier   return TypeBuilderImpl{converter}.genExprType(expr);
624baa12ddbSEric Schweitz }
625baa12ddbSEric Schweitz 
626baa12ddbSEric Schweitz mlir::Type Fortran::lower::translateSymbolToFIRType(
6272c2e5a5dSValentin Clement     Fortran::lower::AbstractConverter &converter, const SymbolRef symbol) {
628d71c1de0SJean Perier   return TypeBuilderImpl{converter}.genSymbolType(symbol);
629baa12ddbSEric Schweitz }
630baa12ddbSEric Schweitz 
631baa12ddbSEric Schweitz mlir::Type Fortran::lower::translateVariableToFIRType(
6322c2e5a5dSValentin Clement     Fortran::lower::AbstractConverter &converter,
633baa12ddbSEric Schweitz     const Fortran::lower::pft::Variable &var) {
634d71c1de0SJean Perier   return TypeBuilderImpl{converter}.genVariableType(var);
635baa12ddbSEric Schweitz }
636baa12ddbSEric Schweitz 
637baa12ddbSEric Schweitz mlir::Type Fortran::lower::convertReal(mlir::MLIRContext *context, int kind) {
638b3d1f073SValentin Clement   return genRealType(context, kind);
639baa12ddbSEric Schweitz }
640d71c1de0SJean Perier 
6412d9b4a50SJean Perier bool Fortran::lower::isDerivedTypeWithLenParameters(
6422d9b4a50SJean Perier     const Fortran::semantics::Symbol &sym) {
6432d9b4a50SJean Perier   if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
6442d9b4a50SJean Perier     if (const Fortran::semantics::DerivedTypeSpec *derived =
6452d9b4a50SJean Perier             declTy->AsDerived())
6462d9b4a50SJean Perier       return Fortran::semantics::CountLenParameters(*derived) > 0;
6472d9b4a50SJean Perier   return false;
6482d9b4a50SJean Perier }
6492d9b4a50SJean Perier 
650d71c1de0SJean Perier template <typename T>
651d71c1de0SJean Perier mlir::Type Fortran::lower::TypeBuilder<T>::genType(
652d71c1de0SJean Perier     Fortran::lower::AbstractConverter &converter,
653d71c1de0SJean Perier     const Fortran::evaluate::FunctionRef<T> &funcRef) {
654d71c1de0SJean Perier   return TypeBuilderImpl{converter}.genExprType(funcRef);
655d71c1de0SJean Perier }
656d71c1de0SJean Perier 
657e45f6e93SjeanPerier const Fortran::semantics::DerivedTypeSpec &
658e45f6e93SjeanPerier Fortran::lower::ComponentReverseIterator::advanceToParentType() {
659e45f6e93SjeanPerier   const Fortran::semantics::Scope *scope = currentParentType->GetScope();
660e45f6e93SjeanPerier   auto parentComp =
661e45f6e93SjeanPerier       DEREF(scope).find(currentTypeDetails->GetParentComponentName().value());
662e45f6e93SjeanPerier   assert(parentComp != scope->cend() && "failed to get parent component");
663e45f6e93SjeanPerier   setCurrentType(parentComp->second->GetType()->derivedTypeSpec());
664e45f6e93SjeanPerier   return *currentParentType;
665e45f6e93SjeanPerier }
666e45f6e93SjeanPerier 
667e45f6e93SjeanPerier void Fortran::lower::ComponentReverseIterator::setCurrentType(
668e45f6e93SjeanPerier     const Fortran::semantics::DerivedTypeSpec &derived) {
669e45f6e93SjeanPerier   currentParentType = &derived;
670e45f6e93SjeanPerier   currentTypeDetails = &currentParentType->typeSymbol()
671e45f6e93SjeanPerier                             .get<Fortran::semantics::DerivedTypeDetails>();
672e45f6e93SjeanPerier   componentIt = currentTypeDetails->componentNames().crbegin();
673e45f6e93SjeanPerier   componentItEnd = currentTypeDetails->componentNames().crend();
674e45f6e93SjeanPerier }
675e45f6e93SjeanPerier 
676d71c1de0SJean Perier using namespace Fortran::evaluate;
677d71c1de0SJean Perier using namespace Fortran::common;
678d71c1de0SJean Perier FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::TypeBuilder, )
679