source: src/Validate/LinkReferenceToTypes.cpp @ b0d9ff7

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since b0d9ff7 was b0d9ff7, checked in by JiadaL <j82liang@…>, 2 years ago

Fix up the QualifiedNameExpr?. It should now work on both old AST and new AST. There are some known bugs to fix so make all-tests will fail.

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