source: src/Validate/LinkReferenceToTypes.cpp @ a25bcf8

ADTast-experimental
Last change on this file since a25bcf8 was e9e9f56, checked in by Andrew Beach <ajbeach@…>, 22 months 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.