source: src/Validate/LinkReferenceToTypes.cpp @ fa2c005

ADT
Last change on this file since fa2c005 was fa2c005, checked in by JiadaL <j82liang@…>, 12 months ago

Finish Adt POC

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