source: src/Validate/LinkInstanceTypes.cpp@ 332e93a

Last change on this file since 332e93a was ed96731, checked in by Andrew Beach <ajbeach@…>, 10 months ago

With{Stmts,Decls}ToAdd how has an -X version like WithSymbolTableX. Although these -X versions might be useful can could possibly be removed in the future. (This is a therapy commit.)

  • 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.