source: src/Validate/LinkReferenceToTypes.cpp @ 3bf9d10

Last change on this file since 3bf9d10 was 132e4c1, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Some clean-up in LinkReferenceToTypes?.cpp.

  • Property mode set to 100644
File size: 9.2 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 = 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 = 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 = 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 = 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        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
286} // namespace
287
288void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
289        ast::Pass<LinkTypesCore>::run( translationUnit );
290}
291
292} // namespace Validate
293
294// Local Variables: //
295// tab-width: 4 //
296// mode: c++ //
297// compile-command: "make install" //
298// End: //
Note: See TracBrowser for help on using the repository browser.