source: src/Validate/LinkInstanceTypes.cpp@ 97f8f0f

Last change on this file since 97f8f0f was 37b3151, checked in by Andrew Beach <ajbeach@…>, 22 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.