source: src/SymTab/Indexer.cc @ 42f1279c

arm-ehcleanup-dtorsjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpersistent-indexer
Last change on this file since 42f1279c was 42f1279c, checked in by Aaron Moss <a3moss@…>, 3 years ago

Eagerly remove over-ridden generated functions

  • Property mode set to 100644
File size: 28.3 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 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// Indexer.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 21:37:33 2015
11// Last Modified By : Aaron B. Moss
12// Last Modified On : Fri Mar  8 13:55:00 2019
13// Update Count     : 21
14//
15
16#include "Indexer.h"
17
18#include <cassert>                 // for assert, strict_dynamic_cast
19#include <string>                  // for string, operator<<, operator!=
20#include <memory>                  // for shared_ptr, make_shared
21#include <unordered_map>           // for operator!=, unordered_map<>::const...
22#include <unordered_set>           // for unordered_set
23#include <utility>                 // for pair, make_pair, move
24#include <vector>                  // for vector
25
26#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
27#include "Common/SemanticError.h"  // for SemanticError
28#include "Common/utility.h"        // for cloneAll
29#include "Common/Stats/Counter.h"  // for counters
30#include "GenPoly/GenPoly.h"       // for getFunctionType
31#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
32#include "Mangler.h"               // for Mangler
33#include "Parser/LinkageSpec.h"    // for isMangled, isOverridable, Spec
34#include "ResolvExpr/typeops.h"    // for typesCompatible
35#include "SynTree/Constant.h"      // for Constant
36#include "SynTree/Declaration.h"   // for DeclarationWithType, FunctionDecl
37#include "SynTree/Expression.h"    // for Expression, ImplicitCopyCtorExpr
38#include "SynTree/Initializer.h"   // for Initializer
39#include "SynTree/Statement.h"     // for CompoundStmt, Statement, ForStmt (...
40#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
41
42namespace SymTab {
43
44        // Statistics block
45        namespace {
46                static inline auto stats() {
47                        using namespace Stats::Counters;
48                        static auto group   = build<CounterGroup>("Indexers");
49                        static struct {
50                                SimpleCounter * count;
51                                AverageCounter<double> * size;
52                                SimpleCounter * new_scopes;
53                                SimpleCounter * lazy_scopes;
54                                AverageCounter<double> * avg_scope_depth;
55                                MaxCounter<size_t> * max_scope_depth;
56                                SimpleCounter * add_calls;
57                                SimpleCounter * lookup_calls;
58                                SimpleCounter * map_lookups;
59                                SimpleCounter * map_mutations;
60                        } ret = {
61                                .count   = build<SimpleCounter>("Count", group),
62                                .size    = build<AverageCounter<double>>("Average Size", group),
63                                .new_scopes = build<SimpleCounter>("Scopes", group),
64                                .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group),
65                                .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
66                                .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
67                                .add_calls = build<SimpleCounter>("Add Calls", group),
68                                .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
69                                .map_lookups = build<SimpleCounter>("Map Lookups", group),
70                                .map_mutations = build<SimpleCounter>("Map Mutations", group)
71                        };
72                        return ret;
73                }
74        }
75
76        void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
77                // only need to perform this step for constructors, destructors, and assignment functions
78                if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
79
80                // helpful data structure to organize properties for a type
81                struct ValueType {
82                        struct DeclBall { // properties for this particular decl
83                                IdData decl;
84                                bool isUserDefinedFunc;
85                                bool isCopyFunc;
86                        };
87                        // properties for this type
88                        bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
89                        BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
90                        std::list< DeclBall > decls;
91
92                        // another FunctionDecl for the current type was found - determine
93                        // if it has special properties and update data structure accordingly
94                        ValueType & operator+=( IdData data ) {
95                                DeclarationWithType * function = data.id;
96                                bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
97                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
98                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
99                                existsUserDefinedCopyFunc |= (isUserDefinedFunc && isCopyFunc);
100                                if ( isUserDefinedFunc && ! deleteStmt ) {
101                                        // any user-defined function can act as an implicit delete statement for generated constructors.
102                                        // a delete stmt should not act as an implicit delete statement.
103                                        deleteStmt = data.id;
104                                }
105                                return *this;
106                        }
107                }; // ValueType
108
109                std::list< IdData > copy;
110                copy.splice( copy.end(), out );
111
112                // organize discovered declarations by type
113                std::unordered_map< std::string, ValueType > funcMap;
114                for ( auto decl : copy ) {
115                        if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
116                                std::list< DeclarationWithType * > & params = function->type->parameters;
117                                assert( ! params.empty() );
118                                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
119                                Type * base = InitTweak::getPointerBase( params.front()->get_type() );
120                                assert( base );
121                                funcMap[ Mangler::mangle( base ) ] += decl;
122                        } else {
123                                out.push_back( decl );
124                        }
125                }
126
127                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
128                // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
129                // if the user defines a default ctor, then the generated default ctor is unavailable,
130                // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
131                // field ctors are available. If the user defines any ctor then the generated default ctor
132                // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
133                // anything that looks like a copy constructor, then the generated copy constructor is
134                // unavailable, and likewise for the assignment operator.
135                for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
136                        ValueType & val = pair.second;
137                        for ( ValueType::DeclBall ball : val.decls ) {
138                                bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
139                                bool isCopyFunc = ball.isCopyFunc;
140                                bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
141
142                                // only implicitly delete non-user defined functions that are not intrinsic, and are
143                                // not copy functions (assignment or copy constructor). If a  user-defined copy
144                                // function exists, do not pass along the non-user-defined copy functions since
145                                // signatures do not have to match, and the generated functions will often be
146                                // cheaper.
147                                if ( isNotUserDefinedFunc ) {
148                                        if ( isCopyFunc ) {
149                                                // Skip over non-user-defined copy functions when there is a user-defined
150                                                // copy function. Since their signatures do not have to be exact, deleting
151                                                // them is the wrong choice.
152                                                if ( existsUserDefinedCopyFunc ) continue;
153                                        } else {
154                                                // delete non-user-defined non-copy functions if applicable.
155                                                // deleteStmt will be non-null only if a user-defined function is found.
156                                                ball.decl.deleteStmt = val.deleteStmt;
157                                        }
158                                }
159                                out.push_back( ball.decl );
160                        }
161                }
162        }
163
164        Indexer::Indexer() 
165        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 
166          prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
167
168        Indexer::~Indexer() {
169                stats().size->push( idTable ? idTable->size() : 0 );
170        }
171
172        void Indexer::lazyInitScope() {
173                if ( repScope < scope ) {
174                        ++*stats().lazy_scopes;
175                        // create rollback
176                        prevScope = std::make_shared<Indexer>( *this );
177                        // update repScope
178                        repScope = scope;
179                }
180        }
181
182        void Indexer::enterScope() {
183                ++scope;
184
185                ++*stats().new_scopes;
186                stats().avg_scope_depth->push( scope );
187                stats().max_scope_depth->push( scope );
188        }
189
190        void Indexer::leaveScope() {
191                if ( repScope == scope ) {
192                        Ptr prev = prevScope;           // make sure prevScope stays live
193                        *this = std::move(*prevScope);  // replace with previous scope
194                }
195
196                --scope;
197        }
198
199        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
200                ++*stats().lookup_calls;
201                if ( ! idTable ) return;
202
203                ++*stats().map_lookups;
204                auto decls = idTable->find( id );
205                if ( decls == idTable->end() ) return;
206
207                for ( auto decl : *(decls->second) ) {
208                        out.push_back( decl.second );
209                }
210               
211                // some special functions, e.g. constructors and destructors
212                // remove autogenerated functions when they are defined so that
213                // they can never be matched
214                removeSpecialOverrides( id, out );
215        }
216
217        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
218                ++*stats().lookup_calls;
219                if ( ! typeTable ) return nullptr;
220                ++*stats().map_lookups;
221                auto it = typeTable->find( id );
222                return it == typeTable->end() ? nullptr : it->second.decl;
223        }
224
225        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
226                ++*stats().lookup_calls;
227                if ( ! structTable ) return nullptr;
228                ++*stats().map_lookups;
229                auto it = structTable->find( id );
230                return it == structTable->end() ? nullptr : it->second.decl;
231        }
232
233        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
234                ++*stats().lookup_calls;
235                if ( ! enumTable ) return nullptr;
236                ++*stats().map_lookups;
237                auto it = enumTable->find( id );
238                return it == enumTable->end() ? nullptr : it->second.decl;
239        }
240
241        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
242                ++*stats().lookup_calls;
243                if ( ! unionTable ) return nullptr;
244                ++*stats().map_lookups;
245                auto it = unionTable->find( id );
246                return it == unionTable->end() ? nullptr : it->second.decl;
247        }
248
249        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
250                ++*stats().lookup_calls;
251                if ( ! traitTable ) return nullptr;
252                ++*stats().map_lookups;
253                auto it = traitTable->find( id );
254                return it == traitTable->end() ? nullptr : it->second.decl;
255        }
256
257        const Indexer* Indexer::atScope( unsigned long target ) const {
258                // by lazy construction, final indexer in list has repScope 0, cannot be > target
259                // otherwise, will find first scope representing the target
260                const Indexer* indexer = this;
261                while ( indexer->repScope > target ) {
262                        indexer = indexer->prevScope.get();
263                }
264                return indexer;
265        }
266
267        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
268                return atScope( 0 )->lookupType( id );
269        }
270
271        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
272                return atScope( 0 )->lookupStruct( id );
273        }
274
275        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
276                return atScope( 0 )->lookupUnion( id );
277        }
278
279        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
280                return atScope( 0 )->lookupEnum( id );
281        }
282
283        bool isFunction( DeclarationWithType * decl ) {
284                return GenPoly::getFunctionType( decl->get_type() );
285        }
286
287        bool isObject( DeclarationWithType * decl ) {
288                return ! isFunction( decl );
289        }
290
291        bool isDefinition( DeclarationWithType * decl ) {
292                if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
293                        // a function is a definition if it has a body
294                        return func->statements;
295                } else {
296                        // an object is a definition if it is not marked extern.
297                        // both objects must be marked extern
298                        return ! decl->get_storageClasses().is_extern;
299                }
300        }
301
302       
303        bool Indexer::addedIdConflicts( 
304                        const Indexer::IdData & existing, DeclarationWithType *added, 
305                        Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
306                // if we're giving the same name mangling to things of different types then there is
307                // something wrong
308                assert( (isObject( added ) && isObject( existing.id ) )
309                        || ( isFunction( added ) && isFunction( existing.id ) ) );
310
311                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
312                        // new definition shadows the autogenerated one, even at the same scope
313                        return false;
314                } else if ( LinkageSpec::isMangled( added->linkage ) 
315                                || ResolvExpr::typesCompatible( 
316                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
317
318                        // it is a conflict if one declaration is deleted and the other is not
319                        if ( deleteStmt && ! existing.deleteStmt ) {
320                                if ( handleConflicts.mode == OnConflict::Error ) {
321                                        SemanticError( added, "deletion of defined identifier " );
322                                }
323                                return true;
324                        } else if ( ! deleteStmt && existing.deleteStmt ) {
325                                if ( handleConflicts.mode == OnConflict::Error ) {
326                                        SemanticError( added, "definition of deleted identifier " );
327                                }
328                                return true;
329                        }
330
331                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
332                                if ( handleConflicts.mode == OnConflict::Error ) {
333                                        SemanticError( added, 
334                                                isFunction( added ) ? 
335                                                        "duplicate function definition for " : 
336                                                        "duplicate object definition for " );
337                                }
338                                return true;
339                        } // if
340                } else {
341                        if ( handleConflicts.mode == OnConflict::Error ) {
342                                SemanticError( added, "duplicate definition for " );
343                        }
344                        return true;
345                } // if
346
347                return true;
348        }
349
350        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
351                if ( ! idTable ) return false;
352
353                ++*stats().map_lookups;
354                auto decls = idTable->find( id );
355                if ( decls == idTable->end() ) return false;
356
357                for ( auto decl : *(decls->second) ) {
358                        // skip other scopes (hidden by this decl)
359                        if ( decl.second.scope != scope ) continue;
360                        // check for C decl with compatible type (by mangleName)
361                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
362                                return true;
363                        }
364                }
365               
366                return false;
367        }
368
369        bool Indexer::hasIncompatibleCDecl( 
370                        const std::string &id, const std::string &mangleName ) const {
371                if ( ! idTable ) return false;
372
373                ++*stats().map_lookups;
374                auto decls = idTable->find( id );
375                if ( decls == idTable->end() ) return false;
376
377                for ( auto decl : *(decls->second) ) {
378                        // skip other scopes (hidden by this decl)
379                        if ( decl.second.scope != scope ) continue;
380                        // check for C decl with incompatible type (by manglename)
381                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
382                                return true;
383                        }
384                }
385
386                return false;
387        }
388
389        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
390        std::string getOtypeKey( FunctionDecl* function ) {
391                auto& params = function->type->parameters;
392                assert( ! params.empty() );
393                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
394                Type* base = InitTweak::getPointerBase( params.front()->get_type() );
395                assert( base );
396                return Mangler::mangle( base );
397        }
398
399        /// gets the declaration for the function acting on a type specified by otype key,
400        /// nullptr if none such
401        FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
402                FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
403                if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
404                return func;
405        }
406
407        bool Indexer::removeSpecialOverrides( 
408                        Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
409                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
410                // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
411                // if the user defines a default ctor, then the generated default ctor is unavailable,
412                // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
413                // field ctors are available. If the user defines any ctor then the generated default ctor
414                // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
415                // anything that looks like a copy constructor, then the generated copy constructor is
416                // unavailable, and likewise for the assignment operator.
417
418                // only relevant on function declarations
419                FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
420                if ( ! function ) return true;
421                // only need to perform this check for constructors, destructors, and assignment functions
422                if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
423
424                // set up information for this type
425                bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
426                bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
427                std::string dataOtypeKey = getOtypeKey( function );
428
429                if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
430                        // this is a user-defined copy function
431                        // if this is the first such, delete/remove non-user-defined overloads as needed
432                        std::vector< std::string > removed;
433                        std::vector< MangleTable::value_type > deleted;
434                        bool alreadyUserDefinedFunc = false;
435                       
436                        for ( const auto& entry : *mangleTable ) {
437                                // skip decls that aren't functions or are for the wrong type
438                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
439                                if ( ! decl ) continue;
440
441                                bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
442                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
443                                        // matching user-defined function
444                                        if ( isCopyFunc ) {
445                                                // mutation already performed, return early
446                                                return true;
447                                        } else {
448                                                // note that non-copy deletions already performed
449                                                alreadyUserDefinedFunc = true;
450                                        }
451                                } else {
452                                        // non-user-defined function; mark for deletion/removal as appropriate
453                                        if ( isCopyFunc ) {
454                                                removed.push_back( entry.first );
455                                        } else if ( ! alreadyUserDefinedFunc ) {
456                                                deleted.push_back( entry );
457                                        }
458                                }
459                        }
460
461                        // perform removals from mangle table, and deletions if necessary
462                        for ( const auto& key : removed ) {
463                                mangleTable = mangleTable->erase( key );
464                        }
465                        if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
466                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
467                        }
468                } else if ( dataIsUserDefinedFunc ) {
469                        // this is a user-defined non-copy function
470                        // if this is the first user-defined function, delete non-user-defined overloads
471                        std::vector< MangleTable::value_type > deleted;
472                       
473                        for ( const auto& entry : *mangleTable ) {
474                                // skip decls that aren't functions or are for the wrong type
475                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
476                                if ( ! decl ) continue;
477
478                                // exit early if already a matching user-defined function;
479                                // earlier function will have mutated table
480                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
481
482                                // skip mutating intrinsic functions
483                                if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
484
485                                // user-defined non-copy functions do not override copy functions
486                                if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
487
488                                // this function to be deleted after mangleTable iteration is complete
489                                deleted.push_back( entry );
490                        }
491
492                        // mark deletions to update mangle table
493                        // this needs to be a separate loop because of iterator invalidation
494                        for ( const auto& entry : deleted ) {
495                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
496                        }
497                } else if ( function->linkage != LinkageSpec::Intrinsic ) {
498                        // this is an overridable generated function
499                        // if there already exists a matching user-defined function, delete this appropriately
500                        for ( const auto& entry : *mangleTable ) {
501                                // skip decls that aren't functions or are for the wrong type
502                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
503                                if ( ! decl ) continue;
504
505                                // skip non-user-defined functions
506                                if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
507
508                                if ( dataIsCopyFunc ) {
509                                        // remove current function if exists a user-defined copy function
510                                        // since the signatures for copy functions don't need to match exactly, using
511                                        // a delete statement is the wrong approach
512                                        if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
513                                } else {
514                                        // mark current function deleted by first user-defined function found
515                                        data.deleteStmt = decl;
516                                        return true;
517                                }
518                        }
519                }
520               
521                // nothing (more) to fix, return true
522                return true;
523        }
524
525        void Indexer::addId( 
526                        DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr, 
527                        BaseSyntaxNode * deleteStmt ) {
528                ++*stats().add_calls;
529                const std::string &name = decl->name;
530                if ( name == "" ) return;
531               
532                std::string mangleName;
533                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
534                        // mangle the name without including the appropriate suffix, so overridable routines
535                        // are placed into the same "bucket" as their user defined versions.
536                        mangleName = Mangler::mangle( decl, false );
537                } else {
538                        mangleName = Mangler::mangle( decl );
539                } // if
540
541                // this ensures that no two declarations with the same unmangled name at the same scope
542                // both have C linkage
543                if ( LinkageSpec::isMangled( decl->linkage ) ) {
544                        // Check that a Cforall declaration doesn't override any C declaration
545                        if ( hasCompatibleCDecl( name, mangleName ) ) {
546                                SemanticError( decl, "Cforall declaration hides C function " );
547                        }
548                } else {
549                        // NOTE: only correct if name mangling is completely isomorphic to C
550                        // type-compatibility, which it may not be.
551                        if ( hasIncompatibleCDecl( name, mangleName ) ) {
552                                SemanticError( decl, "conflicting overload of C function " );
553                        }
554                }
555
556                // ensure tables exist and add identifier
557                MangleTable::Ptr mangleTable;
558                if ( ! idTable ) {
559                        idTable = IdTable::new_ptr();
560                        mangleTable = MangleTable::new_ptr();
561                } else {
562                        ++*stats().map_lookups;
563                        auto decls = idTable->find( name );
564                        if ( decls == idTable->end() ) {
565                                mangleTable = MangleTable::new_ptr();
566                        } else {
567                                mangleTable = decls->second;
568                                // skip in-scope repeat declarations of same identifier
569                                ++*stats().map_lookups;
570                                auto existing = mangleTable->find( mangleName );
571                                if ( existing != mangleTable->end()
572                                                && existing->second.scope == scope
573                                                && existing->second.id ) {
574                                        if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
575                                                if ( handleConflicts.mode == OnConflict::Delete ) {
576                                                        // set delete expression for conflicting identifier
577                                                        lazyInitScope();
578                                                        *stats().map_mutations += 2;
579                                                        idTable = idTable->set(
580                                                                name,
581                                                                mangleTable->set( 
582                                                                        mangleName, 
583                                                                        IdData{ existing->second, handleConflicts.deleteStmt } ) );
584                                                }
585                                                return;
586                                        }
587                                }
588                        }
589                }
590
591                // add/overwrite with new identifier
592                lazyInitScope();
593                IdData data{ decl, baseExpr, deleteStmt, scope };
594                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
595                *stats().map_mutations += 2;
596                idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
597        }
598
599        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
600                // default handling of conflicts is to raise an error
601                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
602        }
603
604        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
605                // default handling of conflicts is to raise an error
606                addId( decl, OnConflict::error(), nullptr, deleteStmt );
607        }
608
609        bool addedTypeConflicts( NamedTypeDecl *existing, NamedTypeDecl *added ) {
610                if ( existing->base == nullptr ) {
611                        return false;
612                } else if ( added->base == nullptr ) {
613                        return true;
614                } else {
615                        assert( existing->base && added->base );
616                        // typedef redeclarations are errors only if types are different
617                        if ( ! ResolvExpr::typesCompatible( existing->base, added->base, Indexer() ) ) {
618                                SemanticError( added->location, "redeclaration of " + added->name );
619                        }
620                }
621                // does not need to be added to the table if both existing and added have a base that are
622                // the same
623                return true;
624        }
625
626        void Indexer::addType( NamedTypeDecl *decl ) {
627                ++*stats().add_calls;
628                const std::string &id = decl->name;
629
630                if ( ! typeTable ) { 
631                        typeTable = TypeTable::new_ptr();
632                } else {
633                        ++*stats().map_lookups;
634                        auto existing = typeTable->find( id );
635                        if ( existing != typeTable->end() 
636                                && existing->second.scope == scope
637                                && addedTypeConflicts( existing->second.decl, decl ) ) return;
638                }
639               
640                lazyInitScope();
641                ++*stats().map_mutations;
642                typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
643        }
644
645        bool addedDeclConflicts( AggregateDecl *existing, AggregateDecl *added ) {
646                if ( ! existing->body ) {
647                        return false;
648                } else if ( added->body ) {
649                        SemanticError( added, "redeclaration of " );
650                } // if
651                return true;
652        }
653
654        void Indexer::addStruct( const std::string &id ) {
655                addStruct( new StructDecl( id ) );
656        }
657
658        void Indexer::addStruct( StructDecl *decl ) {
659                ++*stats().add_calls;
660                const std::string &id = decl->name;
661
662                if ( ! structTable ) {
663                        structTable = StructTable::new_ptr();
664                } else {
665                        ++*stats().map_lookups;
666                        auto existing = structTable->find( id );
667                        if ( existing != structTable->end() 
668                                && existing->second.scope == scope
669                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
670                }
671
672                lazyInitScope();
673                ++*stats().map_mutations;
674                structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
675        }
676
677        void Indexer::addEnum( EnumDecl *decl ) {
678                ++*stats().add_calls;
679                const std::string &id = decl->name;
680
681                if ( ! enumTable ) {
682                        enumTable = EnumTable::new_ptr();
683                } else {
684                        ++*stats().map_lookups;
685                        auto existing = enumTable->find( id );
686                        if ( existing != enumTable->end() 
687                                && existing->second.scope == scope
688                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
689                }
690               
691                lazyInitScope();
692                ++*stats().map_mutations;
693                enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
694        }
695
696        void Indexer::addUnion( const std::string &id ) {
697                addUnion( new UnionDecl( id ) );
698        }
699
700        void Indexer::addUnion( UnionDecl *decl ) {
701                ++*stats().add_calls;
702                const std::string &id = decl->name;
703
704                if ( ! unionTable ) {
705                        unionTable = UnionTable::new_ptr();
706                } else {
707                        ++*stats().map_lookups;
708                        auto existing = unionTable->find( id );
709                        if ( existing != unionTable->end() 
710                                && existing->second.scope == scope
711                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
712                }
713
714                lazyInitScope();
715                ++*stats().map_mutations;
716                unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
717        }
718
719        void Indexer::addTrait( TraitDecl *decl ) {
720                ++*stats().add_calls;
721                const std::string &id = decl->name;
722
723                if ( ! traitTable ) {
724                        traitTable = TraitTable::new_ptr();
725                } else {
726                        ++*stats().map_lookups;
727                        auto existing = traitTable->find( id );
728                        if ( existing != traitTable->end() 
729                                && existing->second.scope == scope
730                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
731                }
732
733                lazyInitScope();
734                ++*stats().map_mutations;
735                traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
736        }
737
738        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, 
739                        OnConflict handleConflicts ) {
740                for ( Declaration * decl : aggr->members ) {
741                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
742                                addId( dwt, handleConflicts, expr );
743                                if ( dwt->name == "" ) {
744                                        Type * t = dwt->get_type()->stripReferences();
745                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
746                                                Expression * base = expr->clone();
747                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
748                                                ResolvExpr::referenceToRvalueConversion( base, cost );
749                                                addMembers( t->getAggr(), new MemberExpr( dwt, base ), handleConflicts );
750                                        }
751                                }
752                        }
753                }
754        }
755
756        void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) {
757                for ( Expression * expr : withExprs ) {
758                        if ( expr->result ) {
759                                AggregateDecl * aggr = expr->result->stripReferences()->getAggr();
760                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
761
762                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
763                        }
764                }
765        }
766
767        void Indexer::addIds( const std::list< DeclarationWithType * > & decls ) {
768                for ( auto d : decls ) {
769                        addId( d );
770                }
771        }
772
773        void Indexer::addTypes( const std::list< TypeDecl * > & tds ) {
774                for ( auto td : tds ) {
775                        addType( td );
776                        addIds( td->assertions );
777                }
778        }
779
780        void Indexer::addFunctionType( FunctionType * ftype ) {
781                addTypes( ftype->forall );
782                addIds( ftype->returnVals );
783                addIds( ftype->parameters );
784        }
785
786        Expression * Indexer::IdData::combine( ResolvExpr::Cost & cost ) const {
787                Expression * ret = nullptr;
788                if ( baseExpr ) {
789                        Expression * base = baseExpr->clone();
790                        ResolvExpr::referenceToRvalueConversion( base, cost );
791                        ret = new MemberExpr( id, base );
792                        // xxx - this introduces hidden environments, for now remove them.
793                        // std::swap( base->env, ret->env );
794                        delete base->env;
795                        base->env = nullptr;
796                } else {
797                        ret = new VariableExpr( id );
798                }
799                if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt );
800                return ret;
801        }
802} // namespace SymTab
803
804// Local Variables: //
805// tab-width: 4 //
806// mode: c++ //
807// compile-command: "make install" //
808// End: //
Note: See TracBrowser for help on using the repository browser.