source: src/Validate/LinkReferenceToTypes.cpp@ 01ba701

ADT ast-experimental pthread-emulation
Last change on this file since 01ba701 was 72e76fd, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Converted the last pass in validate B (linkReferenceToTypes). Cleaned up a related test.

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