source: src/Validate/LinkReferenceToTypes.cpp@ affb51b

ADT ast-experimental
Last change on this file since affb51b was e9e9f56, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Used the WithCodeLocation helper in more passes. This cleans up some code and should improve efficiency.

  • 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// 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 ast::QualifiedNameExpr const * previsit( ast::QualifiedNameExpr 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
68ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
69 auto mut = ast::mutate( type );
70 if ( inGeneric && mut->base ) {
71 mut->name = mut->base->name;
72 }
73 if ( auto namedTypeDecl = symtab.lookupType( mut->name ) ) {
74 if ( auto typeDecl = dynamic_cast<ast::TypeDecl const *>( namedTypeDecl ) ) {
75 mut->kind = typeDecl->kind;
76 }
77 }
78 return mut;
79}
80
81ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
82 ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
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 auto mut = ast::mutate( type );
87 mut->base = const_cast<ast::EnumDecl *>( decl );
88 type = mut;
89 }
90 if ( !decl || !decl->body ) {
91 auto mut = ast::mutate( type );
92 forwardEnums[ mut->name ].push_back( mut );
93 type = mut;
94 }
95 return type;
96}
97
98ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
99 ast::StructDecl const * decl = symtab.lookupStruct( type->name );
100 // It's not a semantic error if the struct is not found, just an implicit forward declaration.
101 if ( decl ) {
102 // Just linking in the node.
103 auto mut = ast::mutate( type );
104 mut->base = const_cast<ast::StructDecl *>( decl );
105 type = mut;
106 }
107 if ( !decl || !decl->body ) {
108 auto mut = ast::mutate( type );
109 forwardStructs[ mut->name ].push_back( mut );
110 type = mut;
111 }
112 return type;
113}
114
115ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
116 ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
117 // It's not a semantic error if the union is not found, just an implicit forward declaration.
118 if ( decl ) {
119 // Just linking in the node.
120 auto mut = ast::mutate( type );
121 mut->base = const_cast<ast::UnionDecl *>( decl );
122 type = mut;
123 }
124 if ( !decl || !decl->body ) {
125 auto mut = ast::mutate( type );
126 forwardUnions[ mut->name ].push_back( mut );
127 type = mut;
128 }
129 return type;
130}
131
132ast::TraitInstType const * LinkTypesCore::postvisit( ast::TraitInstType const * type ) {
133 assert( location );
134
135 ast::TraitDecl const * decl = symtab.lookupTrait( type->name );
136 if ( !decl ) {
137 SemanticError( *location, "use of undeclared trait " + type->name );
138 } else if ( decl->params.size() != type->params.size() ) {
139 SemanticError( *location, "incorrect number of trait parameters: " );
140 }
141 auto mut = ast::mutate( type );
142
143 // Just linking in the node.
144 mut->base = const_cast<ast::TraitDecl *>( decl );
145
146 // Need to carry over the 'sized' status of each decl in the instance.
147 for ( auto p : group_iterate( decl->params, type->params ) ) {
148 ast::TypeExpr const * expr = std::get<1>(p).as<ast::TypeExpr>();
149 if ( !expr ) {
150 SemanticError( std::get<1>(p).get(), "Expression parameters for trait instances are currently unsupported: " );
151 }
152 if ( auto inst = expr->type.as<ast::TypeInstType>() ) {
153 ast::ptr<ast::TypeDecl> const & formalDecl = std::get<0>(p);
154 if ( !formalDecl->sized ) {
155 continue;
156 }
157 // To do this modification we need to reach through a readonly
158 // pointer. The Pass doesn't quite work in that way, so we just
159 // ensure it mutates in-place so it should work out.
160 ast::TypeDecl const * base = inst->base.get();
161 assert( base->unique() );
162 ast::TypeDecl * mutBase = ast::mutate( base );
163 mutBase->sized = true;
164 }
165 }
166 return mut;
167}
168
169void LinkTypesCore::previsit( ast::QualifiedType const * ) {
170 visit_children = false;
171}
172
173void LinkTypesCore::postvisit( ast::QualifiedType const * type ) {
174 // Linking only makes sense for the 'oldest ancestor' of the qualified type.
175 type->parent->accept( *visitor );
176}
177
178ast::EnumDecl const * LinkTypesCore::postvisit( ast::EnumDecl const * decl ) {
179 // After visiting enum members for self-referencing members,
180 // we replace the enum base. Right now it only works for StructDecl.
181 if ( decl->base ) {
182 if ( auto base = decl->base.as<ast::TypeInstType>() ) {
183 if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
184 auto mut = ast::mutate( decl );
185 mut->base = new ast::StructInstType( structDecl );
186 decl = mut;
187 }
188 } else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
189 if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
190 if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
191 auto mut = ast::mutate( decl );
192 mut->base = new ast::PointerType(
193 new ast::StructInstType( structDecl ) );
194 decl = mut;
195 }
196 }
197 }
198 }
199
200 // This section is common with struct/union, except for the return value.
201 if ( !decl->body ) {
202 return decl;
203 }
204
205 ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
206 if ( fwds != forwardEnums.end() ) {
207 for ( auto inst : fwds->second ) {
208 inst->base = decl;
209 }
210 forwardEnums.erase( fwds );
211 }
212
213 return decl;
214}
215
216template<typename AggrDecl>
217AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
218 GuardValue( inGeneric ) = !decl->params.empty();
219 if ( !inGeneric ) {
220 return decl;
221 }
222 auto mut = ast::mutate( decl );
223 for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
224 typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
225 }
226 return mut;
227}
228
229ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
230 return renameGenericParams( decl );
231}
232
233void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
234 if ( !decl->body ) {
235 return;
236 }
237
238 ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
239 if ( fwds != forwardStructs.end() ) {
240 for ( auto inst : fwds->second ) {
241 inst->base = decl;
242 }
243 forwardStructs.erase( fwds );
244 }
245}
246
247ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
248 return renameGenericParams( decl );
249}
250
251void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
252 if ( !decl->body ) {
253 return;
254 }
255
256 ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
257 if ( fwds != forwardUnions.end() ) {
258 for ( auto inst : fwds->second ) {
259 inst->base = decl;
260 }
261 forwardUnions.erase( fwds );
262 }
263}
264
265ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
266 auto mut = ast::mutate( decl );
267 if ( mut->name == "sized" ) {
268 // "sized" is a special trait - flick the sized status on for the type variable.
269 assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );
270 ast::TypeDecl * td = mut->params.front().get_and_mutate();
271 td->sized = true;
272 }
273
274 // There is some overlap with code from decayForallPointers,
275 // perhaps reorganization or shared helper functions are called for.
276 // Move assertions from type parameters into the body of the trait.
277 for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
278 auto expanded = expandAssertions( td->assertions );
279 for ( auto declWithType : expanded ) {
280 mut->members.emplace_back( declWithType.release() );
281 }
282 }
283 return mut;
284}
285
286ast::QualifiedNameExpr const * LinkTypesCore::previsit( ast::QualifiedNameExpr const * decl ) {
287 // Try to lookup type
288 if ( auto objDecl = decl->type_decl.as<ast::ObjectDecl>() ) {
289 if ( auto inst = objDecl->type.as<ast::TypeInstType>()) {
290 if ( auto enumDecl = symtab.lookupEnum ( inst->name ) ) {
291 auto mut = ast::mutate( decl );
292 mut->type_decl = enumDecl;
293 auto enumInst = new ast::EnumInstType( enumDecl );
294 enumInst->name = decl->name;
295 // Adding result; addCandidate() use result
296 mut->result = enumInst;
297 decl = mut;
298 }
299 }
300 } else if ( auto enumDecl = decl->type_decl.as<ast::EnumDecl>() ) {
301 auto mut = ast::mutate( decl );
302 auto enumInst = new ast::EnumInstType( enumDecl );
303 enumInst->name = decl->name;
304 // Adding result; addCandidate() use result
305 mut->result = enumInst;
306 decl = mut;
307 }
308 // ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
309 // // It's not a semantic error if the enum is not found, just an implicit forward declaration.
310 // if ( decl ) {
311 // // Just linking in the node.
312 // auto mut = ast::mutate( type );
313 // mut->base = const_cast<ast::EnumDecl *>( decl );
314 // type = mut;
315 // }
316 return decl;
317}
318
319} // namespace
320
321void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
322 ast::Pass<LinkTypesCore>::run( translationUnit );
323}
324
325} // namespace Validate
326
327// Local Variables: //
328// tab-width: 4 //
329// mode: c++ //
330// compile-command: "make install" //
331// End: //
Note: See TracBrowser for help on using the repository browser.