source: src/Validate/LinkReferenceToTypes.cpp @ 8463136

ast-experimental
Last change on this file since 8463136 was e874605, checked in by JiadaL <j82liang@…>, 2 years ago

Add class InlineValueDecl?, which is a Declaration class that works as a placeholder for aggregration value inherited from other aggregration. Disable inline value overwrite.

  • Property mode set to 100644
File size: 9.4 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                        // visit the base
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        // The following section
206
207        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
208        if ( fwds != forwardEnums.end() ) {
209                for ( auto inst : fwds->second ) {
210                        inst->base = decl;
211                }
212                forwardEnums.erase( fwds );
213        }
214
215        return decl;
216}
217
218template<typename AggrDecl>
219AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
220        GuardValue( inGeneric ) = !decl->params.empty();
221        if ( !inGeneric ) {
222                return decl;
223        }
224        auto mut = ast::mutate( decl );
225        for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
226                typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
227        }
228        return mut;
229}
230
231ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
232        return renameGenericParams( decl );
233}
234
235void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
236        if ( !decl->body ) {
237                return;
238        }
239
240        ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
241        if ( fwds != forwardStructs.end() ) {
242                for ( auto inst : fwds->second ) {
243                        inst->base = decl;
244                }
245                forwardStructs.erase( fwds );
246        }
247}
248
249ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
250        return renameGenericParams( decl );
251}
252
253void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
254        if ( !decl->body ) {
255                return;
256        }
257
258        ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
259        if ( fwds != forwardUnions.end() ) {
260                for ( auto inst : fwds->second ) {
261                        inst->base = decl;
262                }
263                forwardUnions.erase( fwds );
264        }
265}
266
267ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
268        auto mut = ast::mutate( decl );
269        if ( mut->name == "sized" ) {
270                // "sized" is a special trait - flick the sized status on for the type variable.
271                assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );
272                ast::TypeDecl * td = mut->params.front().get_and_mutate();
273                td->sized = true;
274        }
275
276        // There is some overlap with code from decayForallPointers,
277        // perhaps reorganization or shared helper functions are called for.
278        // Move assertions from type parameters into the body of the trait.
279        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
280                auto expanded = expandAssertions( td->assertions );
281                for ( auto declWithType : expanded ) {
282                        mut->members.emplace_back( declWithType.release() );
283                }
284        }
285        return mut;
286}
287
288} // namespace
289
290void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
291        ast::Pass<LinkTypesCore>::run( translationUnit );
292}
293
294} // namespace Validate
295
296// Local Variables: //
297// tab-width: 4 //
298// mode: c++ //
299// compile-command: "make install" //
300// End: //
Note: See TracBrowser for help on using the repository browser.