source: src/Validate/ForallPointerDecay.cpp @ 7d7ef6f

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since 7d7ef6f was 51b8582, checked in by Andrew Beach <ajbeach@…>, 3 years ago

So it was a bug in old code that seemed to be cancelling itself out but the new version does not have it. This solution got everything but one test (a polymorphic function calling itself) working.

  • 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// ForallPointerDecay.cpp --
8//
9// Author           : Andrew Beach
10// Created On       : Tue Dec  7 16:15:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Feb 11 10:59:00 2022
13// Update Count     : 0
14//
15
16#include "ForallPointerDecay.hpp"
17
18#include "AST/Copy.hpp"
19#include "AST/Decl.hpp"
20#include "AST/DeclReplacer.hpp"
21#include "AST/Pass.hpp"
22#include "CodeGen/OperatorTable.h"
23#include "Common/CodeLocation.h"
24#include "SymTab/FixFunction.h"
25
26#include "AST/Print.hpp"
27
28namespace Validate {
29
30namespace {
31
32// Create a function type only using information on the FunctionDecl.
33ast::FunctionType * makeFuncType( const ast::FunctionDecl * decl ) {
34        auto type = new ast::FunctionType( decl->type->isVarArgs );
35        for ( auto & param : decl->params ) {
36                type->params.emplace_back( param->get_type() );
37        }
38        for ( auto & ret : decl->returns ) {
39                type->returns.emplace_back( ret->get_type() );
40        }
41        for ( auto & type_param : decl->type_params ) {
42                type->forall.emplace_back(
43                        new ast::TypeInstType( type_param->name, type_param ) );
44        }
45        for ( auto & assertion : decl->assertions ) {
46                type->assertions.emplace_back( new ast::VariableExpr(
47                        assertion->location, assertion ) );
48        }
49        return type;
50}
51
52template<typename T>
53void append( std::vector<T> & dst, std::vector<T> & src ) {
54        dst.reserve( dst.size() + src.size() );
55        for ( auto el : src ) {
56                dst.emplace_back( std::move( el ) );
57        }
58        src.clear();
59}
60
61// Component Passes:
62/// Expand assertions from a trait instance,
63/// performing appropriate type variable substitutions.
64struct TraitExpander final {
65        using AssertionList = std::vector<ast::ptr<ast::DeclWithType>>;
66
67        static AssertionList expandTrait( const ast::TraitInstType * inst ) {
68                assertf( inst->base, "Trait instance not linked to base trait: %s",
69                        toCString( inst ) );
70                AssertionList assertions;
71                // Substitute trait decl parameters for instance parameters.
72                ast::TypeSubstitution sub(
73                        inst->base->params.begin(),
74                        inst->base->params.end(),
75                        inst->params.begin()
76                );
77                for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
78                        ast::ptr<ast::DeclWithType> copy =
79                                ast::deepCopy( decl.strict_as<ast::DeclWithType>() );
80
81                        int count = sub.apply( copy );
82                        (void)count;
83
84                        if ( auto func = copy.as<ast::FunctionDecl>() ) {
85                                auto mut = ast::mutate( func );
86                                mut->type = makeFuncType( func );
87                                copy = mut;
88                        }
89                        assertions.push_back( copy );
90                }
91                return assertions;
92        }
93
94        static AssertionList expandAssertions( const AssertionList & old ) {
95                AssertionList assertions;
96                for ( const ast::ptr<ast::DeclWithType> & decl : old ) {
97                        if ( auto traitInst = dynamic_cast<const ast::TraitInstType *>(
98                                        decl->get_type() ) ) {
99                                auto moreAsserts = expandTrait( traitInst );
100                                append( assertions, moreAsserts );
101                        } else {
102                                assertions.push_back( decl );
103                        }
104                }
105                return assertions;
106        }
107
108        using TypeDeclVec = std::vector<ast::ptr<ast::TypeDecl>>;
109
110        static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
111                TypeDeclVec typeDecls;
112                for ( const ast::TypeDecl * typeDecl : old ) {
113                        typeDecls.push_back( ast::mutate_field( typeDecl,
114                                &ast::TypeDecl::assertions,
115                                expandAssertions( typeDecl->assertions ) ) );
116                }
117                return typeDecls;
118        }
119
120        static AssertionList expandTrait_DR(
121                        const TypeDeclVec & typeDecls, const ast::TraitInstType * inst ) {
122                assertf( inst->base, "Trait instance not linked to base trait: %s",
123                        toCString( inst ) );
124                AssertionList assertions;
125                assertf( inst->params.size() == inst->base->params.size(),
126                        "Trait instance has incorrect number of params: %s",
127                        toCString( inst ) );
128                // Replace the TypeDecls that used to point to the trait.
129                ast::DeclReplacer::TypeMap typeMap;
130                for ( size_t i = 0 ; i < inst->params.size() ; ++i ) {
131                        typeMap[ inst->base->params[i].get() ] = typeDecls[i].get();
132                }
133                for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
134                        auto copy = strict_dynamic_cast<const ast::DeclWithType *>(
135                                ast::DeclReplacer::replace(
136                                        ast::deepCopy( decl.get() ), typeMap ) );
137                        // TODO: Does DeclReplacer make this redundent?
138                        if ( auto func = dynamic_cast<const ast::FunctionDecl *>(copy) ) {
139                                auto mut = ast::mutate( func );
140                                mut->type = makeFuncType( func );
141                                copy = mut;
142                        }
143                        assertions.push_back( copy );
144                }
145                return assertions;
146        }
147
148        static AssertionList expandAssertions_DR(
149                        const TypeDeclVec & typeDecls, const AssertionList & assertions ) {
150                AssertionList newAsserts;
151                for ( const ast::ptr<ast::DeclWithType> & assert : assertions ) {
152                        if ( auto traitInst = dynamic_cast<const ast::TraitInstType *>(
153                                        assert->get_type() ) ) {
154                                auto moreAsserts = expandTrait_DR( typeDecls, traitInst );
155                                append( newAsserts, moreAsserts );
156                        } else {
157                                newAsserts.push_back( assert );
158                        }
159                }
160                return newAsserts;
161        }
162
163        // They had better all be unique for this to work.
164        static TypeDeclVec expandTypeDecls_DR( const TypeDeclVec & old ) {
165                TypeDeclVec typeDecls;
166                for ( const ast::TypeDecl * typeDecl : old ) {
167                        typeDecls.push_back( ast::mutate_field( typeDecl,
168                                &ast::TypeDecl::assertions,
169                                expandAssertions_DR( old, typeDecl->assertions ) ) );
170                }
171                return typeDecls;
172        }
173
174        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
175                if ( decl->assertions.empty() ) {
176                        return decl;
177                }
178                auto mut = ast::mutate( decl );
179                mut->assertions = expandAssertions( decl->assertions );
180                auto mutType = ast::mutate( mut->type.get() );
181                // *
182                mutType->params.clear();
183                for ( auto & param : mut->params ) {
184                        mutType->params.emplace_back( param->get_type() );
185                }
186                mutType->returns.clear();
187                for ( auto & ret : mut->returns ) {
188                        mutType->returns.emplace_back( ret->get_type() );
189                }
190                mutType->forall.clear();
191                for ( auto & type_param : mut->type_params ) {
192                        mutType->forall.emplace_back(
193                                new ast::TypeInstType( type_param->name, type_param ) );
194                }
195                // * /
196                mutType->assertions.clear();
197                for ( auto & assertion : mut->assertions ) {
198                        mutType->assertions.emplace_back(
199                                new ast::VariableExpr( mut->location, assertion ) );
200                }
201                mut->type = mutType;
202                return mut;
203        }
204
205        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
206                if ( decl->params.empty() ) {
207                        return decl;
208                }
209                return ast::mutate_field( decl, &ast::StructDecl::params,
210                        expandTypeDecls( decl->params ) );
211        }
212
213        const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
214                if ( decl->params.empty() ) {
215                        return decl;
216                }
217                return ast::mutate_field( decl, &ast::UnionDecl::params,
218                        expandTypeDecls( decl->params ) );
219        }
220};
221
222std::vector<ast::ptr<ast::DeclWithType>> fixAssertionList(
223                const ast::ParseNode * node,
224                const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
225        std::vector<ast::ptr<ast::DeclWithType>> ret;
226        for ( const auto & assn : assertions ) {
227                bool isVoid = false;
228                ret.push_back( SymTab::fixFunction( assn, isVoid ) );
229                if ( isVoid ) {
230                        SemanticError( node->location, node,
231                                "invalid type void in assertion of function " );
232                }
233        }
234        return ret;
235}
236
237std::vector<ast::ptr<ast::TypeDecl>> fixTypeDeclList(
238                const ast::ParseNode * node,
239                const std::vector<ast::ptr<ast::TypeDecl>> & type_params ) {
240        std::vector<ast::ptr<ast::TypeDecl>> ret;
241        ret.reserve( type_params.size() );
242        for ( const ast::TypeDecl * type_param : type_params ) {
243                auto mutParam = ast::mutate( type_param );
244                mutParam->assertions = fixAssertionList( node, mutParam->assertions );
245                ret.push_back( mutParam );
246        }
247        return ret;
248}
249
250struct AssertionFunctionFixer final {
251        const ast::FunctionDecl * previsit( const ast::FunctionDecl * decl ) {
252                if ( decl->assertions.empty() ) {
253                        return decl;
254                }
255                return ast::mutate_field( decl, &ast::FunctionDecl::assertions,
256                        fixAssertionList( decl, decl->assertions ) );
257        }
258
259        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
260                if ( decl->params.empty() ) {
261                        return decl;
262                }
263                return ast::mutate_field( decl, &ast::StructDecl::params,
264                        fixTypeDeclList( decl, decl->params ) );
265        }
266
267        const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
268                if ( decl->params.empty() ) {
269                        return decl;
270                }
271                return ast::mutate_field( decl, &ast::UnionDecl::params,
272                        fixTypeDeclList( decl, decl->params ) );
273        }
274};
275
276struct OberatorChecker final {
277        void previsit( const ast::ObjectDecl * obj ) {
278                if ( CodeGen::isOperator( obj->name ) ) {
279                        auto type = obj->type->stripDeclarator();
280                        if ( ! dynamic_cast< const ast::FunctionType * >( type ) ) {
281                                SemanticError( obj->location,
282                                        toCString( "operator ", obj->name.c_str(), " is not "
283                                        "a function or function pointer." ) );
284                        }
285                }
286        }
287};
288
289struct UniqueFixCore final {
290        const ast::DeclWithType * postvisit( const ast::DeclWithType * decl ) {
291                if ( decl->uniqueId ) {
292                        return decl;
293                } else {
294                        auto mut = ast::mutate( decl );
295                        mut->fixUniqueId();
296                        return mut;
297                }
298        }
299};
300
301} // namespace
302
303void decayForallPointers( ast::TranslationUnit & transUnit ) {
304        ast::Pass<TraitExpander>::run( transUnit );
305        ast::Pass<AssertionFunctionFixer>::run( transUnit );
306        ast::Pass<OberatorChecker>::run( transUnit );
307        ast::Pass<UniqueFixCore>::run( transUnit );
308}
309
310} // namespace Validate
311
312// Local Variables: //
313// tab-width: 4 //
314// mode: c++ //
315// compile-command: "make install" //
316// End: //
Note: See TracBrowser for help on using the repository browser.