Ignore:
Timestamp:
May 24, 2019, 10:19:41 AM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
d908563
Parents:
6a9d4b4 (diff), 292642a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into cleanup-dtors

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/SymTab/Indexer.cc

    r6a9d4b4 r933f32f  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:08:40 2017
    13 // Update Count     : 20
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 21
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
    19 #include <iostream>                // for operator<<, basic_ostream, ostream
    2019#include <string>                  // for string, operator<<, operator!=
     20#include <memory>                  // for shared_ptr, make_shared
    2121#include <unordered_map>           // for operator!=, unordered_map<>::const...
    2222#include <unordered_set>           // for unordered_set
    2323#include <utility>                 // for pair, make_pair, move
     24#include <vector>                  // for vector
    2425
    2526#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2627#include "Common/SemanticError.h"  // for SemanticError
    2728#include "Common/utility.h"        // for cloneAll
    28 #include "GenPoly/GenPoly.h"
     29#include "Common/Stats/Counter.h"  // for counters
     30#include "GenPoly/GenPoly.h"       // for getFunctionType
    2931#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3032#include "Mangler.h"               // for Mangler
     
    3840#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    3941
    40 #define debugPrint(x) if ( doDebug ) { std::cerr << x; }
    41 
    4242namespace SymTab {
    43         std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
    44                 return out << "(" << data.id << "," << data.baseExpr << ")";
    45         }
    46 
    47         typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
    48         typedef std::unordered_map< std::string, MangleTable > IdTable;
    49         typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
    50         typedef std::unordered_map< std::string, StructDecl* > StructTable;
    51         typedef std::unordered_map< std::string, EnumDecl* > EnumTable;
    52         typedef std::unordered_map< std::string, UnionDecl* > UnionTable;
    53         typedef std::unordered_map< std::string, TraitDecl* > TraitTable;
    54 
    55         void dump( const IdTable &table, std::ostream &os ) {
    56                 for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
    57                         for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
    58                                 os << mangle->second << std::endl;
    59                         }
    60                 }
    61         }
    62 
    63         template< typename Decl >
    64         void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) {
    65                 for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) {
    66                         os << it->second << std::endl;
    67                 } // for
    68         }
    69 
    70         struct Indexer::Impl {
    71                 Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(),
    72                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    73                 Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ),
    74                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    75                 unsigned long refCount;   ///< Number of references to these tables
    76                 unsigned long scope;      ///< Scope these tables are associated with
    77                 unsigned long size;       ///< Number of elements stored in this table
    78                 const Indexer base;       ///< Base indexer this extends
    79 
    80                 IdTable idTable;          ///< Identifier namespace
    81                 TypeTable typeTable;      ///< Type namespace
    82                 StructTable structTable;  ///< Struct namespace
    83                 EnumTable enumTable;      ///< Enum namespace
    84                 UnionTable unionTable;    ///< Union namespace
    85                 TraitTable traitTable;    ///< Trait namespace
    86         };
    87 
    88         Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) {
    89                 if ( ! toClone ) return 0;
    90 
    91                 // shorten the search chain by skipping empty links
    92                 Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone;
    93                 if ( ret ) { ++ret->refCount; }
    94 
    95                 return ret;
    96         }
    97 
    98         void Indexer::deleteRef( Indexer::Impl *toFree ) {
    99                 if ( ! toFree ) return;
    100 
    101                 if ( --toFree->refCount == 0 ) delete toFree;
    102         }
    103 
    104         void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
    105                 // only need to perform this step for constructors, destructors, and assignment functions
    106                 if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
    107 
    108                 // helpful data structure to organize properties for a type
    109                 struct ValueType {
    110                         struct DeclBall { // properties for this particular decl
    111                                 IdData decl;
    112                                 bool isUserDefinedFunc;
    113                                 bool isCopyFunc;
     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)
    11471                        };
    115                         // properties for this type
    116                         bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
    117                         BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
    118                         std::list< DeclBall > decls;
    119 
    120                         // another FunctionDecl for the current type was found - determine
    121                         // if it has special properties and update data structure accordingly
    122                         ValueType & operator+=( IdData data ) {
    123                                 DeclarationWithType * function = data.id;
    124                                 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
    125                                 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
    126                                 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
    127                                 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
    128                                 if ( isUserDefinedFunc && ! deleteStmt ) {
    129                                         // any user-defined function can act as an implicit delete statement for generated constructors.
    130                                         // a delete stmt should not act as an implicit delete statement.
    131                                         deleteStmt = data.id;
    132                                 }
    133                                 return *this;
    134                         }
    135                 }; // ValueType
    136 
    137                 std::list< IdData > copy;
    138                 copy.splice( copy.end(), out );
    139 
    140                 // organize discovered declarations by type
    141                 std::unordered_map< std::string, ValueType > funcMap;
    142                 for ( auto decl : copy ) {
    143                         if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
    144                                 std::list< DeclarationWithType * > & params = function->type->parameters;
    145                                 assert( ! params.empty() );
    146                                 // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    147                                 Type * base = InitTweak::getPointerBase( params.front()->get_type() );
    148                                 assert( base );
    149                                 funcMap[ Mangler::mangle( base ) ] += decl;
    150                         } else {
    151                                 out.push_back( decl );
    152                         }
    153                 }
    154 
    155                 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
    156                 // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
    157                 // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
    158                 // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
    159                 // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
    160                 // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
    161                 // then the generated copy constructor is unavailable, and likewise for the assignment operator.
    162                 for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
    163                         ValueType & val = pair.second;
    164                         for ( ValueType::DeclBall ball : val.decls ) {
    165                                 bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
    166                                 bool isCopyFunc = ball.isCopyFunc;
    167                                 bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
    168 
    169                                 // only implicitly delete non-user defined functions that are not intrinsic, and are
    170                                 // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
    171                                 // do not pass along the non-user-defined copy functions since signatures do not have to match,
    172                                 // and the generated functions will often be cheaper.
    173                                 if ( isNotUserDefinedFunc ) {
    174                                         if ( isCopyFunc ) {
    175                                                 // Skip over non-user-defined copy functions when there is a user-defined copy function.
    176                                                 // Since their signatures do not have to be exact, deleting them is the wrong choice.
    177                                                 if ( existsUserDefinedCopyFunc ) continue;
    178                                         } else {
    179                                                 // delete non-user-defined non-copy functions if applicable.
    180                                                 // deleteStmt will be non-null only if a user-defined function is found.
    181                                                 ball.decl.deleteStmt = val.deleteStmt;
    182                                         }
    183                                 }
    184                                 out.push_back( ball.decl );
    185                         }
    186                 }
    187         }
    188 
    189         void Indexer::makeWritable() {
    190                 if ( ! tables ) {
    191                         // create indexer if not yet set
    192                         tables = new Indexer::Impl( scope );
    193                 } else if ( tables->refCount > 1 || tables->scope != scope ) {
    194                         // make this indexer the base of a fresh indexer at the current scope
    195                         tables = new Indexer::Impl( scope, std::move( *this ) );
    196                 }
    197         }
    198 
    199         Indexer::Indexer() : tables( 0 ), scope( 0 ) {}
    200 
    201         Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {}
    202 
    203         Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
    204                 that.tables = 0;
    205         }
     72                        return ret;
     73                }
     74        }
     75
     76        Indexer::Indexer()
     77        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
     78          prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
    20679
    20780        Indexer::~Indexer() {
    208                 deleteRef( tables );
    209         }
    210 
    211         Indexer& Indexer::operator= ( const Indexer &that ) {
    212                 deleteRef( tables );
    213 
    214                 tables = newRef( that.tables );
    215                 scope = that.scope;
    216                 doDebug = that.doDebug;
    217 
    218                 return *this;
    219         }
    220 
    221         Indexer& Indexer::operator= ( Indexer &&that ) {
    222                 deleteRef( tables );
    223 
    224                 tables = that.tables;
    225                 scope = that.scope;
    226                 doDebug = that.doDebug;
    227 
    228                 that.tables = 0;
    229 
    230                 return *this;
     81                stats().size->push( idTable ? idTable->size() : 0 );
     82        }
     83
     84        void Indexer::lazyInitScope() {
     85                if ( repScope < scope ) {
     86                        ++*stats().lazy_scopes;
     87                        // create rollback
     88                        prevScope = std::make_shared<Indexer>( *this );
     89                        // update repScope
     90                        repScope = scope;
     91                }
     92        }
     93
     94        void Indexer::enterScope() {
     95                ++scope;
     96
     97                ++*stats().new_scopes;
     98                stats().avg_scope_depth->push( scope );
     99                stats().max_scope_depth->push( scope );
     100        }
     101
     102        void Indexer::leaveScope() {
     103                if ( repScope == scope ) {
     104                        Ptr prev = prevScope;           // make sure prevScope stays live
     105                        *this = std::move(*prevScope);  // replace with previous scope
     106                }
     107
     108                --scope;
    231109        }
    232110
    233111        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    234                 std::unordered_set< std::string > foundMangleNames;
    235 
    236                 Indexer::Impl *searchTables = tables;
    237                 while ( searchTables ) {
    238 
    239                         IdTable::const_iterator decls = searchTables->idTable.find( id );
    240                         if ( decls != searchTables->idTable.end() ) {
    241                                 const MangleTable &mangleTable = decls->second;
    242                                 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    243                                         // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
    244                                         if ( foundMangleNames.insert( decl->first ).second == false ) continue;
    245 
    246                                         out.push_back( decl->second );
    247                                 }
    248                         }
    249 
    250                         // get declarations from base indexers
    251                         searchTables = searchTables->base.tables;
    252                 }
    253 
    254                 // some special functions, e.g. constructors and destructors
    255                 // remove autogenerated functions when they are defined so that
    256                 // they can never be matched
    257                 removeSpecialOverrides( id, out );
     112                ++*stats().lookup_calls;
     113                if ( ! idTable ) return;
     114
     115                ++*stats().map_lookups;
     116                auto decls = idTable->find( id );
     117                if ( decls == idTable->end() ) return;
     118
     119                for ( auto decl : *(decls->second) ) {
     120                        out.push_back( decl.second );
     121                }
    258122        }
    259123
    260124        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    261                 if ( ! tables ) return 0;
    262 
    263                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    264                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
     125                ++*stats().lookup_calls;
     126                if ( ! typeTable ) return nullptr;
     127                ++*stats().map_lookups;
     128                auto it = typeTable->find( id );
     129                return it == typeTable->end() ? nullptr : it->second.decl;
    265130        }
    266131
    267132        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    268                 if ( ! tables ) return 0;
    269 
    270                 StructTable::const_iterator ret = tables->structTable.find( id );
    271                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
     133                ++*stats().lookup_calls;
     134                if ( ! structTable ) return nullptr;
     135                ++*stats().map_lookups;
     136                auto it = structTable->find( id );
     137                return it == structTable->end() ? nullptr : it->second.decl;
     138        }
     139
     140        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
     141                ++*stats().lookup_calls;
     142                if ( ! enumTable ) return nullptr;
     143                ++*stats().map_lookups;
     144                auto it = enumTable->find( id );
     145                return it == enumTable->end() ? nullptr : it->second.decl;
     146        }
     147
     148        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
     149                ++*stats().lookup_calls;
     150                if ( ! unionTable ) return nullptr;
     151                ++*stats().map_lookups;
     152                auto it = unionTable->find( id );
     153                return it == unionTable->end() ? nullptr : it->second.decl;
     154        }
     155
     156        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
     157                ++*stats().lookup_calls;
     158                if ( ! traitTable ) return nullptr;
     159                ++*stats().map_lookups;
     160                auto it = traitTable->find( id );
     161                return it == traitTable->end() ? nullptr : it->second.decl;
     162        }
     163
     164        const Indexer* Indexer::atScope( unsigned long target ) const {
     165                // by lazy construction, final indexer in list has repScope 0, cannot be > target
     166                // otherwise, will find first scope representing the target
     167                const Indexer* indexer = this;
     168                while ( indexer->repScope > target ) {
     169                        indexer = indexer->prevScope.get();
     170                }
     171                return indexer;
    272172        }
    273173
    274174        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    275                 return lookupTypeAtScope( id, 0 );
     175                return atScope( 0 )->lookupType( id );
    276176        }
    277177
    278178        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    279                 return lookupStructAtScope( id, 0 );
     179                return atScope( 0 )->lookupStruct( id );
    280180        }
    281181
    282182        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    283                 return lookupUnionAtScope( id, 0 );
     183                return atScope( 0 )->lookupUnion( id );
    284184        }
    285185
    286186        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    287                 return lookupEnumAtScope( id, 0 );
    288         }
    289 
    290         EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    291                 if ( ! tables ) return 0;
    292 
    293                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    294                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    295         }
    296 
    297         UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    298                 if ( ! tables ) return 0;
    299 
    300                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    301                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    302         }
    303 
    304         TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    305                 if ( ! tables ) return 0;
    306 
    307                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    308                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
    309         }
    310 
    311         const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    312                 if ( ! tables ) return nullptr;
    313                 if ( tables->scope < scope ) return nullptr;
    314 
    315                 IdTable::const_iterator decls = tables->idTable.find( id );
    316                 if ( decls != tables->idTable.end() ) {
    317                         const MangleTable &mangleTable = decls->second;
    318                         MangleTable::const_iterator decl = mangleTable.find( mangleName );
    319                         if ( decl != mangleTable.end() ) return &decl->second;
    320                 }
    321 
    322                 return tables->base.lookupIdAtScope( id, mangleName, scope );
    323         }
    324 
    325         Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
    326                 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
    327         }
    328 
    329         bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    330                 if ( ! tables ) return false;
    331                 if ( tables->scope < scope ) return false;
    332 
    333                 IdTable::const_iterator decls = tables->idTable.find( id );
    334                 if ( decls != tables->idTable.end() ) {
    335                         const MangleTable &mangleTable = decls->second;
    336                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    337                                 // check for C decls with the same name, skipping those with a compatible type (by mangleName)
    338                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
    339                         }
    340                 }
    341 
    342                 return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
    343         }
    344 
    345         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    346                 if ( ! tables ) return false;
    347                 if ( tables->scope < scope ) return false;
    348 
    349                 IdTable::const_iterator decls = tables->idTable.find( id );
    350                 if ( decls != tables->idTable.end() ) {
    351                         const MangleTable &mangleTable = decls->second;
    352                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    353                                 // check for C decls with the same name, skipping
    354                                 // those with an incompatible type (by mangleName)
    355                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
    356                         }
    357                 }
    358 
    359                 return tables->base.hasCompatibleCDecl( id, mangleName, scope );
    360         }
    361 
    362         NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
    363                 if ( ! tables ) return 0;
    364                 if ( tables->scope < scope ) return 0;
    365                 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
    366 
    367                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    368                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
    369         }
    370 
    371         StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
    372                 if ( ! tables ) return 0;
    373                 if ( tables->scope < scope ) return 0;
    374                 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
    375 
    376                 StructTable::const_iterator ret = tables->structTable.find( id );
    377                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
    378         }
    379 
    380         EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
    381                 if ( ! tables ) return 0;
    382                 if ( tables->scope < scope ) return 0;
    383                 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
    384 
    385                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    386                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
    387         }
    388 
    389         UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
    390                 if ( ! tables ) return 0;
    391                 if ( tables->scope < scope ) return 0;
    392                 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
    393 
    394                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    395                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
    396         }
    397 
    398         TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
    399                 if ( ! tables ) return 0;
    400                 if ( tables->scope < scope ) return 0;
    401                 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
    402 
    403                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    404                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
     187                return atScope( 0 )->lookupEnum( id );
    405188        }
    406189
     
    424207        }
    425208
    426         bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
    427                 // if we're giving the same name mangling to things of different types then there is something wrong
     209       
     210        bool Indexer::addedIdConflicts(
     211                        const Indexer::IdData & existing, DeclarationWithType *added,
     212                        Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
     213                // if we're giving the same name mangling to things of different types then there is
     214                // something wrong
    428215                assert( (isObject( added ) && isObject( existing.id ) )
    429216                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    430217
    431                 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     218                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
    432219                        // new definition shadows the autogenerated one, even at the same scope
    433220                        return false;
    434                 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
     221                } else if ( LinkageSpec::isMangled( added->linkage )
     222                                || ResolvExpr::typesCompatible(
     223                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
    435224
    436225                        // it is a conflict if one declaration is deleted and the other is not
    437226                        if ( deleteStmt && ! existing.deleteStmt ) {
    438                                 return handleConflicts( existing, "deletion of defined identifier " );
     227                                if ( handleConflicts.mode == OnConflict::Error ) {
     228                                        SemanticError( added, "deletion of defined identifier " );
     229                                }
     230                                return true;
    439231                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    440                                 return handleConflicts( existing, "definition of deleted identifier " );
     232                                if ( handleConflicts.mode == OnConflict::Error ) {
     233                                        SemanticError( added, "definition of deleted identifier " );
     234                                }
     235                                return true;
    441236                        }
    442237
    443238                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    444                                 if ( isFunction( added ) ) {
    445                                         return handleConflicts( existing, "duplicate function definition for " );
     239                                if ( handleConflicts.mode == OnConflict::Error ) {
     240                                        SemanticError( added,
     241                                                isFunction( added ) ?
     242                                                        "duplicate function definition for " :
     243                                                        "duplicate object definition for " );
     244                                }
     245                                return true;
     246                        } // if
     247                } else {
     248                        if ( handleConflicts.mode == OnConflict::Error ) {
     249                                SemanticError( added, "duplicate definition for " );
     250                        }
     251                        return true;
     252                } // if
     253
     254                return true;
     255        }
     256
     257        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
     258                if ( ! idTable ) return false;
     259
     260                ++*stats().map_lookups;
     261                auto decls = idTable->find( id );
     262                if ( decls == idTable->end() ) return false;
     263
     264                for ( auto decl : *(decls->second) ) {
     265                        // skip other scopes (hidden by this decl)
     266                        if ( decl.second.scope != scope ) continue;
     267                        // check for C decl with compatible type (by mangleName)
     268                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
     269                                return true;
     270                        }
     271                }
     272               
     273                return false;
     274        }
     275
     276        bool Indexer::hasIncompatibleCDecl(
     277                        const std::string &id, const std::string &mangleName ) const {
     278                if ( ! idTable ) return false;
     279
     280                ++*stats().map_lookups;
     281                auto decls = idTable->find( id );
     282                if ( decls == idTable->end() ) return false;
     283
     284                for ( auto decl : *(decls->second) ) {
     285                        // skip other scopes (hidden by this decl)
     286                        if ( decl.second.scope != scope ) continue;
     287                        // check for C decl with incompatible type (by manglename)
     288                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
     289                                return true;
     290                        }
     291                }
     292
     293                return false;
     294        }
     295
     296        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
     297        std::string getOtypeKey( FunctionDecl* function ) {
     298                auto& params = function->type->parameters;
     299                assert( ! params.empty() );
     300                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     301                Type* base = InitTweak::getPointerBase( params.front()->get_type() );
     302                assert( base );
     303                return Mangler::mangle( base );
     304        }
     305
     306        /// gets the declaration for the function acting on a type specified by otype key,
     307        /// nullptr if none such
     308        FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
     309                FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
     310                if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
     311                return func;
     312        }
     313
     314        bool Indexer::removeSpecialOverrides(
     315                        Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
     316                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
     317                // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
     318                // if the user defines a default ctor, then the generated default ctor is unavailable,
     319                // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
     320                // field ctors are available. If the user defines any ctor then the generated default ctor
     321                // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
     322                // anything that looks like a copy constructor, then the generated copy constructor is
     323                // unavailable, and likewise for the assignment operator.
     324
     325                // only relevant on function declarations
     326                FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
     327                if ( ! function ) return true;
     328                // only need to perform this check for constructors, destructors, and assignment functions
     329                if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
     330
     331                // set up information for this type
     332                bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     333                bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
     334                std::string dataOtypeKey = getOtypeKey( function );
     335
     336                if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
     337                        // this is a user-defined copy function
     338                        // if this is the first such, delete/remove non-user-defined overloads as needed
     339                        std::vector< std::string > removed;
     340                        std::vector< MangleTable::value_type > deleted;
     341                        bool alreadyUserDefinedFunc = false;
     342                       
     343                        for ( const auto& entry : *mangleTable ) {
     344                                // skip decls that aren't functions or are for the wrong type
     345                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     346                                if ( ! decl ) continue;
     347
     348                                bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
     349                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
     350                                        // matching user-defined function
     351                                        if ( isCopyFunc ) {
     352                                                // mutation already performed, return early
     353                                                return true;
     354                                        } else {
     355                                                // note that non-copy deletions already performed
     356                                                alreadyUserDefinedFunc = true;
     357                                        }
    446358                                } else {
    447                                         return handleConflicts( existing, "duplicate object definition for " );
    448                                 } // if
    449                         } // if
    450                 } else {
    451                         return handleConflicts( existing, "duplicate definition for " );
    452                 } // if
    453 
     359                                        // non-user-defined function; mark for deletion/removal as appropriate
     360                                        if ( isCopyFunc ) {
     361                                                removed.push_back( entry.first );
     362                                        } else if ( ! alreadyUserDefinedFunc ) {
     363                                                deleted.push_back( entry );
     364                                        }
     365                                }
     366                        }
     367
     368                        // perform removals from mangle table, and deletions if necessary
     369                        for ( const auto& key : removed ) {
     370                                ++*stats().map_mutations;
     371                                mangleTable = mangleTable->erase( key );
     372                        }
     373                        if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
     374                                ++*stats().map_mutations;
     375                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     376                        }
     377                } else if ( dataIsUserDefinedFunc ) {
     378                        // this is a user-defined non-copy function
     379                        // if this is the first user-defined function, delete non-user-defined overloads
     380                        std::vector< MangleTable::value_type > deleted;
     381                       
     382                        for ( const auto& entry : *mangleTable ) {
     383                                // skip decls that aren't functions or are for the wrong type
     384                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     385                                if ( ! decl ) continue;
     386
     387                                // exit early if already a matching user-defined function;
     388                                // earlier function will have mutated table
     389                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
     390
     391                                // skip mutating intrinsic functions
     392                                if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
     393
     394                                // user-defined non-copy functions do not override copy functions
     395                                if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
     396
     397                                // this function to be deleted after mangleTable iteration is complete
     398                                deleted.push_back( entry );
     399                        }
     400
     401                        // mark deletions to update mangle table
     402                        // this needs to be a separate loop because of iterator invalidation
     403                        for ( const auto& entry : deleted ) {
     404                                ++*stats().map_mutations;
     405                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     406                        }
     407                } else if ( function->linkage != LinkageSpec::Intrinsic ) {
     408                        // this is an overridable generated function
     409                        // if there already exists a matching user-defined function, delete this appropriately
     410                        for ( const auto& entry : *mangleTable ) {
     411                                // skip decls that aren't functions or are for the wrong type
     412                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     413                                if ( ! decl ) continue;
     414
     415                                // skip non-user-defined functions
     416                                if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
     417
     418                                if ( dataIsCopyFunc ) {
     419                                        // remove current function if exists a user-defined copy function
     420                                        // since the signatures for copy functions don't need to match exactly, using
     421                                        // a delete statement is the wrong approach
     422                                        if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
     423                                } else {
     424                                        // mark current function deleted by first user-defined function found
     425                                        data.deleteStmt = decl;
     426                                        return true;
     427                                }
     428                        }
     429                }
     430               
     431                // nothing (more) to fix, return true
    454432                return true;
    455433        }
    456434
    457         void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
    458                 if ( decl->name == "" ) return;
    459                 debugPrint( "Adding Id " << decl->name << std::endl );
    460                 makeWritable();
    461 
     435        void Indexer::addId(
     436                        DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
     437                        BaseSyntaxNode * deleteStmt ) {
     438                ++*stats().add_calls;
    462439                const std::string &name = decl->name;
     440                if ( name == "" ) return;
     441               
    463442                std::string mangleName;
    464443                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    465                         // mangle the name without including the appropriate suffix, so overridable routines are placed into the
    466                         // same "bucket" as their user defined versions.
     444                        // mangle the name without including the appropriate suffix, so overridable routines
     445                        // are placed into the same "bucket" as their user defined versions.
    467446                        mangleName = Mangler::mangle( decl, false );
    468447                } else {
     
    470449                } // if
    471450
    472                 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
    473                 if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
    474                         // NOTE this is broken in Richard's original code in such a way that it never triggers (it
    475                         // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
    476                         // have their name as their manglename, hence the error can never trigger).
    477                         // The code here is closer to correct, but name mangling would have to be completely
    478                         // isomorphic to C type-compatibility, which it may not be.
    479                         if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     451                // this ensures that no two declarations with the same unmangled name at the same scope
     452                // both have C linkage
     453                if ( LinkageSpec::isMangled( decl->linkage ) ) {
     454                        // Check that a Cforall declaration doesn't override any C declaration
     455                        if ( hasCompatibleCDecl( name, mangleName ) ) {
     456                                SemanticError( decl, "Cforall declaration hides C function " );
     457                        }
     458                } else {
     459                        // NOTE: only correct if name mangling is completely isomorphic to C
     460                        // type-compatibility, which it may not be.
     461                        if ( hasIncompatibleCDecl( name, mangleName ) ) {
    480462                                SemanticError( decl, "conflicting overload of C function " );
    481463                        }
    482                 } else {
    483                         // Check that a Cforall declaration doesn't override any C declaration
    484                         if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    485                                 SemanticError( decl, "Cforall declaration hides C function " );
    486                         }
    487                 }
    488 
    489                 // Skip repeat declarations of the same identifier
    490                 IdData * existing = lookupIdAtScope( name, mangleName, scope );
    491                 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
    492 
    493                 // add to indexer
    494                 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
    495                 ++tables->size;
     464                }
     465
     466                // ensure tables exist and add identifier
     467                MangleTable::Ptr mangleTable;
     468                if ( ! idTable ) {
     469                        idTable = IdTable::new_ptr();
     470                        mangleTable = MangleTable::new_ptr();
     471                } else {
     472                        ++*stats().map_lookups;
     473                        auto decls = idTable->find( name );
     474                        if ( decls == idTable->end() ) {
     475                                mangleTable = MangleTable::new_ptr();
     476                        } else {
     477                                mangleTable = decls->second;
     478                                // skip in-scope repeat declarations of same identifier
     479                                ++*stats().map_lookups;
     480                                auto existing = mangleTable->find( mangleName );
     481                                if ( existing != mangleTable->end()
     482                                                && existing->second.scope == scope
     483                                                && existing->second.id ) {
     484                                        if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
     485                                                if ( handleConflicts.mode == OnConflict::Delete ) {
     486                                                        // set delete expression for conflicting identifier
     487                                                        lazyInitScope();
     488                                                        *stats().map_mutations += 2;
     489                                                        idTable = idTable->set(
     490                                                                name,
     491                                                                mangleTable->set(
     492                                                                        mangleName,
     493                                                                        IdData{ existing->second, handleConflicts.deleteStmt } ) );
     494                                                }
     495                                                return;
     496                                        }
     497                                }
     498                        }
     499                }
     500
     501                // add/overwrite with new identifier
     502                lazyInitScope();
     503                IdData data{ decl, baseExpr, deleteStmt, scope };
     504                // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
     505                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
     506                *stats().map_mutations += 2;
     507                idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
    496508        }
    497509
    498510        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    499511                // default handling of conflicts is to raise an error
    500                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
     512                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    501513        }
    502514
    503515        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    504516                // default handling of conflicts is to raise an error
    505                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
     517                addId( decl, OnConflict::error(), nullptr, deleteStmt );
    506518        }
    507519
     
    518530                        }
    519531                }
    520                 // does not need to be added to the table if both existing and added have a base that are the same
     532                // does not need to be added to the table if both existing and added have a base that are
     533                // the same
    521534                return true;
    522535        }
    523536
    524537        void Indexer::addType( NamedTypeDecl *decl ) {
    525                 debugPrint( "Adding type " << decl->name << std::endl );
    526                 makeWritable();
    527 
     538                ++*stats().add_calls;
    528539                const std::string &id = decl->name;
    529                 TypeTable::iterator existing = tables->typeTable.find( id );
    530                 if ( existing == tables->typeTable.end() ) {
    531                         NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
    532                         if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
    533                                 tables->typeTable.insert( existing, std::make_pair( id, decl ) );
    534                                 ++tables->size;
    535                         }
    536                 } else {
    537                         if ( ! addedTypeConflicts( existing->second, decl ) ) {
    538                                 existing->second = decl;
    539                         }
    540                 }
     540
     541                if ( ! typeTable ) {
     542                        typeTable = TypeTable::new_ptr();
     543                } else {
     544                        ++*stats().map_lookups;
     545                        auto existing = typeTable->find( id );
     546                        if ( existing != typeTable->end()
     547                                && existing->second.scope == scope
     548                                && addedTypeConflicts( existing->second.decl, decl ) ) return;
     549                }
     550               
     551                lazyInitScope();
     552                ++*stats().map_mutations;
     553                typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
    541554        }
    542555
     
    551564
    552565        void Indexer::addStruct( const std::string &id ) {
    553                 debugPrint( "Adding fwd decl for struct " << id << std::endl );
    554566                addStruct( new StructDecl( id ) );
    555567        }
    556568
    557569        void Indexer::addStruct( StructDecl *decl ) {
    558                 debugPrint( "Adding struct " << decl->name << std::endl );
    559                 makeWritable();
    560 
     570                ++*stats().add_calls;
    561571                const std::string &id = decl->name;
    562                 StructTable::iterator existing = tables->structTable.find( id );
    563                 if ( existing == tables->structTable.end() ) {
    564                         StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
    565                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    566                                 tables->structTable.insert( existing, std::make_pair( id, decl ) );
    567                                 ++tables->size;
    568                         }
    569                 } else {
    570                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    571                                 existing->second = decl;
    572                         }
    573                 }
     572
     573                if ( ! structTable ) {
     574                        structTable = StructTable::new_ptr();
     575                } else {
     576                        ++*stats().map_lookups;
     577                        auto existing = structTable->find( id );
     578                        if ( existing != structTable->end() 
     579                                && existing->second.scope == scope
     580                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     581                }
     582
     583                lazyInitScope();
     584                ++*stats().map_mutations;
     585                structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
    574586        }
    575587
    576588        void Indexer::addEnum( EnumDecl *decl ) {
    577                 debugPrint( "Adding enum " << decl->name << std::endl );
    578                 makeWritable();
    579 
     589                ++*stats().add_calls;
    580590                const std::string &id = decl->name;
    581                 EnumTable::iterator existing = tables->enumTable.find( id );
    582                 if ( existing == tables->enumTable.end() ) {
    583                         EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
    584                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    585                                 tables->enumTable.insert( existing, std::make_pair( id, decl ) );
    586                                 ++tables->size;
    587                         }
    588                 } else {
    589                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    590                                 existing->second = decl;
    591                         }
    592                 }
     591
     592                if ( ! enumTable ) {
     593                        enumTable = EnumTable::new_ptr();
     594                } else {
     595                        ++*stats().map_lookups;
     596                        auto existing = enumTable->find( id );
     597                        if ( existing != enumTable->end() 
     598                                && existing->second.scope == scope
     599                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     600                }
     601               
     602                lazyInitScope();
     603                ++*stats().map_mutations;
     604                enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
    593605        }
    594606
    595607        void Indexer::addUnion( const std::string &id ) {
    596                 debugPrint( "Adding fwd decl for union " << id << std::endl );
    597608                addUnion( new UnionDecl( id ) );
    598609        }
    599610
    600611        void Indexer::addUnion( UnionDecl *decl ) {
    601                 debugPrint( "Adding union " << decl->name << std::endl );
    602                 makeWritable();
    603 
     612                ++*stats().add_calls;
    604613                const std::string &id = decl->name;
    605                 UnionTable::iterator existing = tables->unionTable.find( id );
    606                 if ( existing == tables->unionTable.end() ) {
    607                         UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
    608                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    609                                 tables->unionTable.insert( existing, std::make_pair( id, decl ) );
    610                                 ++tables->size;
    611                         }
    612                 } else {
    613                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    614                                 existing->second = decl;
    615                         }
    616                 }
     614
     615                if ( ! unionTable ) {
     616                        unionTable = UnionTable::new_ptr();
     617                } else {
     618                        ++*stats().map_lookups;
     619                        auto existing = unionTable->find( id );
     620                        if ( existing != unionTable->end()
     621                                && existing->second.scope == scope
     622                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     623                }
     624
     625                lazyInitScope();
     626                ++*stats().map_mutations;
     627                unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
    617628        }
    618629
    619630        void Indexer::addTrait( TraitDecl *decl ) {
    620                 debugPrint( "Adding trait " << decl->name << std::endl );
    621                 makeWritable();
    622 
     631                ++*stats().add_calls;
    623632                const std::string &id = decl->name;
    624                 TraitTable::iterator existing = tables->traitTable.find( id );
    625                 if ( existing == tables->traitTable.end() ) {
    626                         TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
    627                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    628                                 tables->traitTable.insert( existing, std::make_pair( id, decl ) );
    629                                 ++tables->size;
    630                         }
    631                 } else {
    632                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    633                                 existing->second = decl;
    634                         }
    635                 }
    636         }
    637 
    638         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
     633
     634                if ( ! traitTable ) {
     635                        traitTable = TraitTable::new_ptr();
     636                } else {
     637                        ++*stats().map_lookups;
     638                        auto existing = traitTable->find( id );
     639                        if ( existing != traitTable->end()
     640                                && existing->second.scope == scope
     641                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     642                }
     643
     644                lazyInitScope();
     645                ++*stats().map_mutations;
     646                traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
     647        }
     648
     649        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr,
     650                        OnConflict handleConflicts ) {
    639651                for ( Declaration * decl : aggr->members ) {
    640652                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    642654                                if ( dwt->name == "" ) {
    643655                                        Type * t = dwt->get_type()->stripReferences();
    644                                         if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     656                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
    645657                                                Expression * base = expr->clone();
    646658                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    659671                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    660672
    661                                 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
    662                                         // on conflict, delete the identifier
    663                                         existing.deleteStmt = withStmt;
    664                                         return true;
    665                                 });
     673                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
    666674                        }
    667675                }
     
    685693                addIds( ftype->returnVals );
    686694                addIds( ftype->parameters );
    687         }
    688 
    689         void Indexer::enterScope() {
    690                 ++scope;
    691 
    692                 if ( doDebug ) {
    693                         std::cerr << "--- Entering scope " << scope << std::endl;
    694                 }
    695         }
    696 
    697         void Indexer::leaveScope() {
    698                 using std::cerr;
    699 
    700                 assert( scope > 0 && "cannot leave initial scope" );
    701                 if ( doDebug ) {
    702                         cerr << "--- Leaving scope " << scope << " containing" << std::endl;
    703                 }
    704                 --scope;
    705 
    706                 while ( tables && tables->scope > scope ) {
    707                         if ( doDebug ) {
    708                                 dump( tables->idTable, cerr );
    709                                 dump( tables->typeTable, cerr );
    710                                 dump( tables->structTable, cerr );
    711                                 dump( tables->enumTable, cerr );
    712                                 dump( tables->unionTable, cerr );
    713                                 dump( tables->traitTable, cerr );
    714                         }
    715 
    716                         // swap tables for base table until we find one at an appropriate scope
    717                         Indexer::Impl *base = newRef( tables->base.tables );
    718                         deleteRef( tables );
    719                         tables = base;
    720                 }
    721         }
    722 
    723         void Indexer::print( std::ostream &os, int indent ) const {
    724                 using std::cerr;
    725 
    726                 if ( tables ) {
    727                         os << "--- scope " << tables->scope << " ---" << std::endl;
    728 
    729                         os << "===idTable===" << std::endl;
    730                         dump( tables->idTable, os );
    731                         os << "===typeTable===" << std::endl;
    732                         dump( tables->typeTable, os );
    733                         os << "===structTable===" << std::endl;
    734                         dump( tables->structTable, os );
    735                         os << "===enumTable===" << std::endl;
    736                         dump( tables->enumTable, os );
    737                         os << "===unionTable===" << std::endl;
    738                         dump( tables->unionTable, os );
    739                         os << "===contextTable===" << std::endl;
    740                         dump( tables->traitTable, os );
    741 
    742                         tables->base.print( os, indent );
    743                 } else {
    744                         os << "--- end ---" << std::endl;
    745                 }
    746 
    747695        }
    748696
Note: See TracChangeset for help on using the changeset viewer.