source: src/Validate/LinkReferenceToTypes.cpp @ 11df881

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since 11df881 was 72e76fd, checked in by Andrew Beach <ajbeach@…>, 23 months ago

Converted the last pass in validate B (linkReferenceToTypes). Cleaned up a related test.

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