source: src/Validate/LinkReferenceToTypes.cpp@ 28372f7

ADT ast-experimental
Last change on this file since 28372f7 was 77de429, checked in by JiadaL <j82liang@…>, 3 years ago

Fix overriding enum value

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