source: src/Validate/LinkInstanceTypes.cpp

Last change on this file was 37b3151, checked in by Andrew Beach <ajbeach@…>, 5 months ago

Rename the linkReferenceTypes pass and the file that contains it. BaseInstType? used to be called ReferenceToType?, so the reason for the pass being called that is no longer true.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// LinkInstanceTypes.cpp -- Connect instance types to declarations.
8//
9// Author           : Andrew Beach
10// Created On       : Thr Apr 21 11:41:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Jul 14  9:19:00 2023
13// Update Count     : 3
14//
15
16#include "Validate/LinkInstanceTypes.hpp"
17
18#include "AST/Pass.hpp"
19#include "AST/TranslationUnit.hpp"
20#include "Validate/ForallPointerDecay.hpp"
21#include "Validate/NoIdSymbolTable.hpp"
22
23namespace Validate {
24
25namespace {
26
27struct LinkTypesCore : public WithNoIdSymbolTable,
28                public ast::WithCodeLocation,
29                public ast::WithDeclsToAdd<>,
30                public ast::WithGuards,
31                public ast::WithShortCircuiting,
32                public ast::WithVisitorRef<LinkTypesCore> {
33        ast::TypeInstType const * postvisit( ast::TypeInstType const * type );
34        ast::EnumInstType const * postvisit( ast::EnumInstType const * type );
35        ast::StructInstType const * postvisit( ast::StructInstType const * type );
36        ast::UnionInstType const * postvisit( ast::UnionInstType const * type );
37        ast::TraitInstType const * postvisit( ast::TraitInstType const * type );
38        void previsit( ast::QualifiedType const * type );
39        void postvisit( ast::QualifiedType const * type );
40
41        ast::EnumDecl const * postvisit( ast::EnumDecl const * decl );
42        ast::StructDecl const * previsit( ast::StructDecl const * decl );
43        void postvisit( ast::StructDecl const * decl );
44        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
45        void postvisit( ast::UnionDecl const * decl );
46        ast::TraitDecl const * postvisit( ast::TraitDecl const * decl );
47
48private:
49        using ForwardStructsType =
50                std::map< std::string, std::list< ast::StructInstType * > >;
51        using ForwardUnionsType =
52                std::map< std::string, std::list< ast::UnionInstType * > >;
53        using ForwardEnumsType =
54                std::map< std::string, std::list< ast::EnumInstType * > >;
55
56        ForwardStructsType forwardStructs;
57        ForwardUnionsType forwardUnions;
58        ForwardEnumsType forwardEnums;
59
60        /// true if currently in a generic type body,
61        /// so that type parameter instances can be renamed appropriately
62        bool inGeneric = false;
63
64        template<typename AggrDecl>
65        AggrDecl const * renameGenericParams( AggrDecl const * decl );
66
67        // This cluster is used to add declarations (before) but outside of
68        // any "namespaces" which would qualify the names.
69        bool inNamespace = false;
70        std::list<ast::ptr<ast::Decl>> declsToAddOutside;
71        /// The "leaveNamespace" is handled by guard.
72        void enterNamespace();
73        /// Puts the decl on the back of declsToAddAfter once traversal is
74        /// outside of any namespaces.
75        void addDeclAfterOutside( ast::Decl const * );
76};
77
78void LinkTypesCore::enterNamespace() {
79        if ( inNamespace ) return;
80        inNamespace = true;
81        GuardAction( [this](){
82                inNamespace = false;
83                declsToAddAfter.splice( declsToAddAfter.begin(), declsToAddOutside );
84        } );
85}
86
87void LinkTypesCore::addDeclAfterOutside( ast::Decl const * decl ) {
88        if ( inNamespace ) {
89                declsToAddOutside.emplace_back( decl );
90        } else {
91                declsToAddAfter.emplace_back( decl );
92        }
93}
94
95ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
96        auto mut = ast::mutate( type );
97        if ( inGeneric && mut->base ) {
98                mut->name = mut->base->name;
99        }
100        if ( auto namedTypeDecl = symtab.lookupType( mut->name ) ) {
101                if ( auto typeDecl = dynamic_cast<ast::TypeDecl const *>( namedTypeDecl ) ) {
102                        mut->kind = typeDecl->kind;
103                }
104        }
105        return mut;
106}
107
108ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
109        ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
110        // It's not a semantic error if the enum is not found, just an implicit forward declaration.
111        // The unset code location is used to detect imaginary declarations.
112        // (They may never be used for enumerations.)
113        if ( !decl || decl->location.isUnset() ) {
114                assert( location );
115                ast::EnumDecl * mut = new ast::EnumDecl( *location, type->name );
116                mut->linkage = ast::Linkage::Compiler;
117                decl = mut;
118                symtab.addEnum( decl );
119                addDeclAfterOutside( decl );
120        }
121
122        ast::EnumInstType * mut = ast::mutate( type );
123
124        // Just linking in the node.
125        mut->base = decl;
126
127        if ( !decl->body ) {
128                forwardEnums[ mut->name ].push_back( mut );
129        }
130        return mut;
131}
132
133ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
134        ast::StructDecl const * decl = symtab.lookupStruct( type->name );
135        // It's not a semantic error if the struct is not found, just an implicit forward declaration.
136        // The unset code location is used to detect imaginary declarations.
137        if ( !decl || decl->location.isUnset() ) {
138                assert( location );
139                ast::StructDecl * mut = new ast::StructDecl( *location, type->name );
140                mut->linkage = ast::Linkage::Compiler;
141                decl = mut;
142                symtab.addStruct( decl );
143                addDeclAfterOutside( decl );
144        }
145
146        ast::StructInstType * mut = ast::mutate( type );
147
148        // Just linking in the node.
149        mut->base = decl;
150
151        if ( !decl->body ) {
152                forwardStructs[ mut->name ].push_back( mut );
153        }
154        return mut;
155}
156
157ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
158        ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
159        // It's not a semantic error if the union is not found, just an implicit forward declaration.
160        // The unset code location is used to detect imaginary declarations.
161        if ( !decl || decl->location.isUnset() ) {
162                assert( location );
163                ast::UnionDecl * mut = new ast::UnionDecl( *location, type->name );
164                mut->linkage = ast::Linkage::Compiler;
165                decl = mut;
166                symtab.addUnion( decl );
167                addDeclAfterOutside( decl );
168        }
169
170        ast::UnionInstType * mut = ast::mutate( type );
171
172        // Just linking in the node.
173        mut->base = decl;
174
175        if ( !decl->body ) {
176                forwardUnions[ mut->name ].push_back( mut );
177        }
178        return mut;
179}
180
181ast::TraitInstType const * LinkTypesCore::postvisit( ast::TraitInstType const * type ) {
182        assert( location );
183
184        ast::TraitDecl const * decl = symtab.lookupTrait( type->name );
185        if ( !decl ) {
186                SemanticError( *location, "use of undeclared trait " + type->name );
187        } else if ( decl->params.size() != type->params.size() ) {
188                SemanticError( *location, "incorrect number of trait parameters: " );
189        }
190        auto mut = ast::mutate( type );
191
192        // Just linking in the node.
193        mut->base = decl;
194
195        // Need to carry over the 'sized' status of each decl in the instance.
196        for ( auto p : group_iterate( decl->params, type->params ) ) {
197                ast::TypeExpr const * expr = std::get<1>(p).as<ast::TypeExpr>();
198                if ( !expr ) {
199                        SemanticError( std::get<1>(p).get(), "Expression parameters for trait instances are currently unsupported: " );
200                }
201                if ( auto inst = expr->type.as<ast::TypeInstType>() ) {
202                        ast::ptr<ast::TypeDecl> const & formalDecl = std::get<0>(p);
203                        if ( !formalDecl->sized ) {
204                                continue;
205                        }
206                        // To do this modification we need to reach through a readonly
207                        // pointer. The Pass doesn't quite work in that way, so we just
208                        // ensure it mutates in-place so it should work out.
209                        ast::TypeDecl const * base = inst->base.get();
210                        assert( base->unique() );
211                        ast::TypeDecl * mutBase = ast::mutate( base );
212                        mutBase->sized = true;
213                }
214        }
215        return mut;
216}
217
218void LinkTypesCore::previsit( ast::QualifiedType const * ) {
219        visit_children = false;
220}
221
222void LinkTypesCore::postvisit( ast::QualifiedType const * type ) {
223        // Linking only makes sense for the 'oldest ancestor' of the qualified type.
224        type->parent->accept( *visitor );
225}
226
227ast::EnumDecl const * LinkTypesCore::postvisit( ast::EnumDecl const * decl ) {
228        // After visiting enum members for self-referencing members,
229        // we replace the enum base. Right now it only works for StructDecl.
230        if ( decl->base ) {
231                if ( auto base = decl->base.as<ast::TypeInstType>() ) {
232                        if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
233                                auto mut = ast::mutate( decl );
234                                mut->base = new ast::StructInstType( structDecl );
235                                decl = mut;
236                        }
237                        // visit the base
238                } else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
239                        if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
240                                if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
241                                        auto mut = ast::mutate( decl );
242                                        mut->base = new ast::PointerType(
243                                                new ast::StructInstType( structDecl ) );
244                                        decl = mut;
245                                }
246                        }
247                }
248        }
249
250        // This section is common with struct/union, except for the return value.
251        if ( !decl->body ) {
252                return decl;
253        }
254
255        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
256        if ( fwds != forwardEnums.end() ) {
257                for ( auto inst : fwds->second ) {
258                        inst->base = decl;
259                }
260                forwardEnums.erase( fwds );
261        }
262
263        return decl;
264}
265
266template<typename AggrDecl>
267AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
268        GuardValue( inGeneric ) = !decl->params.empty();
269        if ( !inGeneric ) {
270                return decl;
271        }
272        auto mut = ast::mutate( decl );
273        for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
274                typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
275        }
276        return mut;
277}
278
279ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
280        enterNamespace();
281        return renameGenericParams( decl );
282}
283
284void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
285        if ( !decl->body ) {
286                return;
287        }
288
289        ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
290        if ( fwds != forwardStructs.end() ) {
291                for ( auto inst : fwds->second ) {
292                        inst->base = decl;
293                }
294                forwardStructs.erase( fwds );
295        }
296}
297
298ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
299        enterNamespace();
300        return renameGenericParams( decl );
301}
302
303void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
304        if ( !decl->body ) {
305                return;
306        }
307
308        ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
309        if ( fwds != forwardUnions.end() ) {
310                for ( auto inst : fwds->second ) {
311                        inst->base = decl;
312                }
313                forwardUnions.erase( fwds );
314        }
315}
316
317ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
318        // There is some overlap with code from decayForallPointers,
319        // perhaps reorganization or shared helper functions are called for.
320        // Move assertions from type parameters into the body of the trait.
321        auto mut = ast::mutate( decl );
322        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
323                auto expanded = expandAssertions( td->assertions );
324                for ( auto declWithType : expanded ) {
325                        mut->members.emplace_back( declWithType.release() );
326                }
327        }
328        return mut;
329}
330
331} // namespace
332
333void linkInstanceTypes( ast::TranslationUnit & translationUnit ) {
334        ast::Pass<LinkTypesCore>::run( translationUnit );
335}
336
337} // namespace Validate
338
339// Local Variables: //
340// tab-width: 4 //
341// mode: c++ //
342// compile-command: "make install" //
343// End: //
Note: See TracBrowser for help on using the repository browser.