source: src/Validate/LinkReferenceToTypes.cpp @ 4acf56d

Last change on this file since 4acf56d was b4d2b3b, checked in by Andrew Beach <ajbeach@…>, 11 months ago

Some cases in linkReferencesToTypes: It always hits one or both of the conditionals, so moving the mutation outside is a slight optimization and also reduces noise.

  • Property mode set to 100644
File size: 8.8 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// LinkReferenceToTypes.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 : Tue Sep 20 16:17:00 2022
13// Update Count     : 2
14//
15
16#include "Validate/LinkReferenceToTypes.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::WithGuards,
30                public ast::WithShortCircuiting,
31                public ast::WithVisitorRef<LinkTypesCore> {
32        ast::TypeInstType const * postvisit( ast::TypeInstType const * type );
33        ast::EnumInstType const * postvisit( ast::EnumInstType const * type );
34        ast::StructInstType const * postvisit( ast::StructInstType const * type );
35        ast::UnionInstType const * postvisit( ast::UnionInstType const * type );
36        ast::TraitInstType const * postvisit( ast::TraitInstType const * type );
37        void previsit( ast::QualifiedType const * type );
38        void postvisit( ast::QualifiedType const * type );
39
40        ast::EnumDecl const * postvisit( ast::EnumDecl const * decl );
41        ast::StructDecl const * previsit( ast::StructDecl const * decl );
42        void postvisit( ast::StructDecl const * decl );
43        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
44        void postvisit( ast::UnionDecl const * decl );
45        ast::TraitDecl const * postvisit( ast::TraitDecl const * decl );
46
47private:
48        using ForwardStructsType =
49                std::map< std::string, std::list< ast::StructInstType * > >;
50        using ForwardUnionsType =
51                std::map< std::string, std::list< ast::UnionInstType * > >;
52        using ForwardEnumsType =
53                std::map< std::string, std::list< ast::EnumInstType * > >;
54
55        ForwardStructsType forwardStructs;
56        ForwardUnionsType forwardUnions;
57        ForwardEnumsType forwardEnums;
58
59        /// true if currently in a generic type body,
60        /// so that type parameter instances can be renamed appropriately
61        bool inGeneric = false;
62
63        template<typename AggrDecl>
64        AggrDecl const * renameGenericParams( AggrDecl const * decl );
65};
66
67ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
68        auto mut = ast::mutate( type );
69        if ( inGeneric && mut->base ) {
70                mut->name = mut->base->name;
71        }
72        if ( auto namedTypeDecl = symtab.lookupType( mut->name ) ) {
73                if ( auto typeDecl = dynamic_cast<ast::TypeDecl const *>( namedTypeDecl ) ) {
74                        mut->kind = typeDecl->kind;
75                }
76        }
77        return mut;
78}
79
80ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
81        ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
82        ast::EnumInstType * mut = ast::mutate( type );
83        // It's not a semantic error if the enum is not found, just an implicit forward declaration.
84        if ( decl ) {
85                // Just linking in the node.
86                mut->base = decl;
87        }
88        if ( !decl || !decl->body ) {
89                forwardEnums[ mut->name ].push_back( mut );
90        }
91        return mut;
92}
93
94ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
95        ast::StructDecl const * decl = symtab.lookupStruct( type->name );
96        ast::StructInstType * mut = ast::mutate( type );
97        // It's not a semantic error if the struct is not found, just an implicit forward declaration.
98        if ( decl ) {
99                // Just linking in the node.
100                mut->base = decl;
101        }
102        if ( !decl || !decl->body ) {
103                forwardStructs[ mut->name ].push_back( mut );
104        }
105        return mut;
106}
107
108ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
109        ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
110        ast::UnionInstType * mut = ast::mutate( type );
111        // It's not a semantic error if the union is not found, just an implicit forward declaration.
112        if ( decl ) {
113                // Just linking in the node.
114                mut->base = decl;
115        }
116        if ( !decl || !decl->body ) {
117                forwardUnions[ mut->name ].push_back( mut );
118        }
119        return mut;
120}
121
122ast::TraitInstType const * LinkTypesCore::postvisit( ast::TraitInstType const * type ) {
123        assert( location );
124
125        ast::TraitDecl const * decl = symtab.lookupTrait( type->name );
126        if ( !decl ) {
127                SemanticError( *location, "use of undeclared trait " + type->name );
128        } else if ( decl->params.size() != type->params.size() ) {
129                SemanticError( *location, "incorrect number of trait parameters: " );
130        }
131        auto mut = ast::mutate( type );
132
133        // Just linking in the node.
134        mut->base = decl;
135
136        // Need to carry over the 'sized' status of each decl in the instance.
137        for ( auto p : group_iterate( decl->params, type->params ) ) {
138                ast::TypeExpr const * expr = std::get<1>(p).as<ast::TypeExpr>();
139                if ( !expr ) {
140                        SemanticError( std::get<1>(p).get(), "Expression parameters for trait instances are currently unsupported: " );
141                }
142                if ( auto inst = expr->type.as<ast::TypeInstType>() ) {
143                        ast::ptr<ast::TypeDecl> const & formalDecl = std::get<0>(p);
144                        if ( !formalDecl->sized ) {
145                                continue;
146                        }
147                        // To do this modification we need to reach through a readonly
148                        // pointer. The Pass doesn't quite work in that way, so we just
149                        // ensure it mutates in-place so it should work out.
150                        ast::TypeDecl const * base = inst->base.get();
151                        assert( base->unique() );
152                        ast::TypeDecl * mutBase = ast::mutate( base );
153                        mutBase->sized = true;
154                }
155        }
156        return mut;
157}
158
159void LinkTypesCore::previsit( ast::QualifiedType const * ) {
160        visit_children = false;
161}
162
163void LinkTypesCore::postvisit( ast::QualifiedType const * type ) {
164        // Linking only makes sense for the 'oldest ancestor' of the qualified type.
165        type->parent->accept( *visitor );
166}
167
168ast::EnumDecl const * LinkTypesCore::postvisit( ast::EnumDecl const * decl ) {
169        // After visiting enum members for self-referencing members,
170        // we replace the enum base. Right now it only works for StructDecl.
171        if ( decl->base ) {
172                if ( auto base = decl->base.as<ast::TypeInstType>() ) {
173                        if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
174                                auto mut = ast::mutate( decl );
175                                mut->base = new ast::StructInstType( structDecl );
176                                decl = mut;
177                        }
178                        // visit the base
179                } else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
180                        if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
181                                if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
182                                        auto mut = ast::mutate( decl );
183                                        mut->base = new ast::PointerType(
184                                                new ast::StructInstType( structDecl ) );
185                                        decl = mut;
186                                }
187                        }
188                }
189        }
190
191        // This section is common with struct/union, except for the return value.
192        if ( !decl->body ) {
193                return decl;
194        }
195
196        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
197        if ( fwds != forwardEnums.end() ) {
198                for ( auto inst : fwds->second ) {
199                        inst->base = decl;
200                }
201                forwardEnums.erase( fwds );
202        }
203
204        return decl;
205}
206
207template<typename AggrDecl>
208AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
209        GuardValue( inGeneric ) = !decl->params.empty();
210        if ( !inGeneric ) {
211                return decl;
212        }
213        auto mut = ast::mutate( decl );
214        for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
215                typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
216        }
217        return mut;
218}
219
220ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
221        return renameGenericParams( decl );
222}
223
224void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
225        if ( !decl->body ) {
226                return;
227        }
228
229        ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
230        if ( fwds != forwardStructs.end() ) {
231                for ( auto inst : fwds->second ) {
232                        inst->base = decl;
233                }
234                forwardStructs.erase( fwds );
235        }
236}
237
238ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
239        return renameGenericParams( decl );
240}
241
242void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
243        if ( !decl->body ) {
244                return;
245        }
246
247        ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
248        if ( fwds != forwardUnions.end() ) {
249                for ( auto inst : fwds->second ) {
250                        inst->base = decl;
251                }
252                forwardUnions.erase( fwds );
253        }
254}
255
256ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
257        // There is some overlap with code from decayForallPointers,
258        // perhaps reorganization or shared helper functions are called for.
259        // Move assertions from type parameters into the body of the trait.
260        auto mut = ast::mutate( decl );
261        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
262                auto expanded = expandAssertions( td->assertions );
263                for ( auto declWithType : expanded ) {
264                        mut->members.emplace_back( declWithType.release() );
265                }
266        }
267        return mut;
268}
269
270} // namespace
271
272void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
273        ast::Pass<LinkTypesCore>::run( translationUnit );
274}
275
276} // namespace Validate
277
278// Local Variables: //
279// tab-width: 4 //
280// mode: c++ //
281// compile-command: "make install" //
282// End: //
Note: See TracBrowser for help on using the repository browser.