Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (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' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/SymTab/Indexer.cc

    r7951100 rb067d9b  
    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 && ! data.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                                 // only implicitly delete non-user defined functions that are  not intrinsic, and are
    169                                 // not copy functions (assignment or copy constructor), unless a user-defined copy function exists.
    170                                 // deleteStmt will be non-null only if a user-defined function is found.
    171                                 if (isNotUserDefinedFunc && (! isCopyFunc || existsUserDefinedCopyFunc)) {
    172                                         ball.decl.deleteStmt = val.deleteStmt;
    173                                 }
    174                                 out.push_back( ball.decl );
    175                         }
    176                 }
    177         }
    178 
    179         void Indexer::makeWritable() {
    180                 if ( ! tables ) {
    181                         // create indexer if not yet set
    182                         tables = new Indexer::Impl( scope );
    183                 } else if ( tables->refCount > 1 || tables->scope != scope ) {
    184                         // make this indexer the base of a fresh indexer at the current scope
    185                         tables = new Indexer::Impl( scope, std::move( *this ) );
    186                 }
    187         }
    188 
    189         Indexer::Indexer() : tables( 0 ), scope( 0 ) {}
    190 
    191         Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {}
    192 
    193         Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
    194                 that.tables = 0;
    195         }
     72                        return ret;
     73                }
     74        }
     75
     76        Indexer::Indexer()
     77        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
     78          prevScope(), scope( 0 ), repScope( 0 ) { ++* stats().count; }
    19679
    19780        Indexer::~Indexer() {
    198                 deleteRef( tables );
    199         }
    200 
    201         Indexer& Indexer::operator= ( const Indexer &that ) {
    202                 deleteRef( tables );
    203 
    204                 tables = newRef( that.tables );
    205                 scope = that.scope;
    206                 doDebug = that.doDebug;
    207 
    208                 return *this;
    209         }
    210 
    211         Indexer& Indexer::operator= ( Indexer &&that ) {
    212                 deleteRef( tables );
    213 
    214                 tables = that.tables;
    215                 scope = that.scope;
    216                 doDebug = that.doDebug;
    217 
    218                 that.tables = 0;
    219 
    220                 return *this;
    221         }
    222 
    223         void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    224                 std::unordered_set< std::string > foundMangleNames;
    225 
    226                 Indexer::Impl *searchTables = tables;
    227                 while ( searchTables ) {
    228 
    229                         IdTable::const_iterator decls = searchTables->idTable.find( id );
    230                         if ( decls != searchTables->idTable.end() ) {
    231                                 const MangleTable &mangleTable = decls->second;
    232                                 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    233                                         // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
    234                                         if ( foundMangleNames.insert( decl->first ).second == false ) continue;
    235 
    236                                         out.push_back( decl->second );
    237                                 }
    238                         }
    239 
    240                         // get declarations from base indexers
    241                         searchTables = searchTables->base.tables;
    242                 }
    243 
    244                 // some special functions, e.g. constructors and destructors
    245                 // remove autogenerated functions when they are defined so that
    246                 // they can never be matched
    247                 removeSpecialOverrides( id, out );
    248         }
    249 
    250         NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    251                 if ( ! tables ) return 0;
    252 
    253                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    254                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
    255         }
    256 
    257         StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    258                 if ( ! tables ) return 0;
    259 
    260                 StructTable::const_iterator ret = tables->structTable.find( id );
    261                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
    262         }
    263 
    264         EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    265                 if ( ! tables ) return 0;
    266 
    267                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    268                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    269         }
    270 
    271         UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    272                 if ( ! tables ) return 0;
    273 
    274                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    275                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    276         }
    277 
    278         TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    279                 if ( ! tables ) return 0;
    280 
    281                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    282                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
    283         }
    284 
    285         const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    286                 if ( ! tables ) return nullptr;
    287                 if ( tables->scope < scope ) return nullptr;
    288 
    289                 IdTable::const_iterator decls = tables->idTable.find( id );
    290                 if ( decls != tables->idTable.end() ) {
    291                         const MangleTable &mangleTable = decls->second;
    292                         MangleTable::const_iterator decl = mangleTable.find( mangleName );
    293                         if ( decl != mangleTable.end() ) return &decl->second;
    294                 }
    295 
    296                 return tables->base.lookupIdAtScope( id, mangleName, scope );
    297         }
    298 
    299         Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
    300                 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
    301         }
    302 
    303         bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    304                 if ( ! tables ) return false;
    305                 if ( tables->scope < scope ) return false;
    306 
    307                 IdTable::const_iterator decls = tables->idTable.find( id );
    308                 if ( decls != tables->idTable.end() ) {
    309                         const MangleTable &mangleTable = decls->second;
    310                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    311                                 // check for C decls with the same name, skipping those with a compatible type (by mangleName)
    312                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
    313                         }
    314                 }
    315 
    316                 return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
    317         }
    318 
    319         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    320                 if ( ! tables ) return false;
    321                 if ( tables->scope < scope ) return false;
    322 
    323                 IdTable::const_iterator decls = tables->idTable.find( id );
    324                 if ( decls != tables->idTable.end() ) {
    325                         const MangleTable &mangleTable = decls->second;
    326                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    327                                 // check for C decls with the same name, skipping
    328                                 // those with an incompatible type (by mangleName)
    329                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
    330                         }
    331                 }
    332 
    333                 return tables->base.hasCompatibleCDecl( id, mangleName, scope );
    334         }
    335 
    336         NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
    337                 if ( ! tables ) return 0;
    338                 if ( tables->scope < scope ) return 0;
    339 
    340                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    341                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
    342         }
    343 
    344         StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
    345                 if ( ! tables ) return 0;
    346                 if ( tables->scope < scope ) return 0;
    347 
    348                 StructTable::const_iterator ret = tables->structTable.find( id );
    349                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
    350         }
    351 
    352         EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
    353                 if ( ! tables ) return 0;
    354                 if ( tables->scope < scope ) return 0;
    355 
    356                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    357                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
    358         }
    359 
    360         UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
    361                 if ( ! tables ) return 0;
    362                 if ( tables->scope < scope ) return 0;
    363 
    364                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    365                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
    366         }
    367 
    368         TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
    369                 if ( ! tables ) return 0;
    370                 if ( tables->scope < scope ) return 0;
    371 
    372                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    373                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
    374         }
    375 
    376         bool isFunction( DeclarationWithType * decl ) {
     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;
     109        }
     110
     111        void Indexer::lookupId( const std::string & id, std::list< IdData > &out ) const {
     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                }
     122        }
     123
     124        const NamedTypeDecl * Indexer::lookupType( const std::string & id ) const {
     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;
     130        }
     131
     132        const StructDecl * Indexer::lookupStruct( const std::string & id ) const {
     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        const 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        const 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        const 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;
     172        }
     173
     174        const NamedTypeDecl * Indexer::globalLookupType( const std::string & id ) const {
     175                return atScope( 0 )->lookupType( id );
     176        }
     177
     178        const StructDecl * Indexer::globalLookupStruct( const std::string & id ) const {
     179                return atScope( 0 )->lookupStruct( id );
     180        }
     181
     182        const UnionDecl * Indexer::globalLookupUnion( const std::string & id ) const {
     183                return atScope( 0 )->lookupUnion( id );
     184        }
     185
     186        const EnumDecl * Indexer::globalLookupEnum( const std::string & id ) const {
     187                return atScope( 0 )->lookupEnum( id );
     188        }
     189
     190        bool isFunction( const DeclarationWithType * decl ) {
    377191                return GenPoly::getFunctionType( decl->get_type() );
    378192        }
    379193
    380         bool isObject( DeclarationWithType * decl ) {
     194        bool isObject( const DeclarationWithType * decl ) {
    381195                return ! isFunction( decl );
    382196        }
    383197
    384         bool isDefinition( DeclarationWithType * decl ) {
    385                 if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
     198        bool isDefinition( const DeclarationWithType * decl ) {
     199                if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {
    386200                        // a function is a definition if it has a body
    387201                        return func->statements;
     
    393207        }
    394208
    395         bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
    396                 // 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, const DeclarationWithType * added,
     212                        Indexer::OnConflict handleConflicts, const Declaration * deleteStmt ) {
     213                // if we're giving the same name mangling to things of different types then there is
     214                // something wrong
    397215                assert( (isObject( added ) && isObject( existing.id ) )
    398216                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    399217
    400                 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     218                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
    401219                        // new definition shadows the autogenerated one, even at the same scope
    402220                        return false;
    403                 } 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() ) ) {
    404224
    405225                        // it is a conflict if one declaration is deleted and the other is not
    406226                        if ( deleteStmt && ! existing.deleteStmt ) {
    407                                 return handleConflicts( existing, "deletion of defined identifier " );
     227                                if ( handleConflicts.mode == OnConflict::Error ) {
     228                                        SemanticError( added, "deletion of defined identifier " );
     229                                }
     230                                return true;
    408231                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    409                                 return handleConflicts( existing, "definition of deleted identifier " );
     232                                if ( handleConflicts.mode == OnConflict::Error ) {
     233                                        SemanticError( added, "definition of deleted identifier " );
     234                                }
     235                                return true;
    410236                        }
    411237
    412238                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    413                                 if ( isFunction( added ) ) {
    414                                         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(const std::string & id, const std::string &mangleName ) const {
     277                if ( ! idTable ) return false;
     278
     279                ++* stats().map_lookups;
     280                auto decls = idTable->find( id );
     281                if ( decls == idTable->end() ) return false;
     282
     283                for ( auto decl : *(decls->second) ) {
     284                        // skip other scopes (hidden by this decl)
     285                        if ( decl.second.scope != scope ) continue;
     286                        // check for C decl with incompatible type (by manglename)
     287                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
     288                                return true;
     289                        }
     290                }
     291
     292                return false;
     293        }
     294
     295        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
     296        std::string getOtypeKey( const FunctionDecl * function ) {
     297                auto& params = function->type->parameters;
     298                assert( ! params.empty() );
     299                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     300                Type * base = InitTweak::getPointerBase( params.front()->get_type() );
     301                assert( base );
     302                return Mangler::mangle( base );
     303        }
     304
     305        /// gets the declaration for the function acting on a type specified by otype key,
     306        /// nullptr if none such
     307        const FunctionDecl * getFunctionForOtype( const DeclarationWithType * decl, const std::string& otypeKey ) {
     308                const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl );
     309                if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
     310                return func;
     311        }
     312
     313        bool Indexer::removeSpecialOverrides(Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
     314                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
     315                // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
     316                // if the user defines a default ctor, then the generated default ctor is unavailable,
     317                // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
     318                // field ctors are available. If the user defines any ctor then the generated default ctor
     319                // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
     320                // anything that looks like a copy constructor, then the generated copy constructor is
     321                // unavailable, and likewise for the assignment operator.
     322
     323                // only relevant on function declarations
     324                const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( data.id );
     325                if ( ! function ) return true;
     326                // only need to perform this check for constructors, destructors, and assignment functions
     327                if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
     328
     329                // set up information for this type
     330                bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     331                bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
     332                std::string dataOtypeKey = getOtypeKey( function );
     333
     334                if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
     335                        // this is a user-defined copy function
     336                        // if this is the first such, delete/remove non-user-defined overloads as needed
     337                        std::vector< std::string > removed;
     338                        std::vector< MangleTable::value_type > deleted;
     339                        bool alreadyUserDefinedFunc = false;
     340
     341                        for ( const auto& entry : * mangleTable ) {
     342                                // skip decls that aren't functions or are for the wrong type
     343                                const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     344                                if ( ! decl ) continue;
     345
     346                                bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
     347                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
     348                                        // matching user-defined function
     349                                        if ( isCopyFunc ) {
     350                                                // mutation already performed, return early
     351                                                return true;
     352                                        } else {
     353                                                // note that non-copy deletions already performed
     354                                                alreadyUserDefinedFunc = true;
     355                                        }
    415356                                } else {
    416                                         return handleConflicts( existing, "duplicate object definition for " );
    417                                 } // if
    418                         } // if
    419                 } else {
    420                         return handleConflicts( existing, "duplicate definition for " );
    421                 } // if
    422 
     357                                        // non-user-defined function; mark for deletion/removal as appropriate
     358                                        if ( isCopyFunc ) {
     359                                                removed.push_back( entry.first );
     360                                        } else if ( ! alreadyUserDefinedFunc ) {
     361                                                deleted.push_back( entry );
     362                                        }
     363                                }
     364                        }
     365
     366                        // perform removals from mangle table, and deletions if necessary
     367                        for ( const auto& key : removed ) {
     368                                ++* stats().map_mutations;
     369                                mangleTable = mangleTable->erase( key );
     370                        }
     371                        if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
     372                                ++* stats().map_mutations;
     373                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     374                        }
     375                } else if ( dataIsUserDefinedFunc ) {
     376                        // this is a user-defined non-copy function
     377                        // if this is the first user-defined function, delete non-user-defined overloads
     378                        std::vector< MangleTable::value_type > deleted;
     379
     380                        for ( const auto& entry : * mangleTable ) {
     381                                // skip decls that aren't functions or are for the wrong type
     382                                const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     383                                if ( ! decl ) continue;
     384
     385                                // exit early if already a matching user-defined function;
     386                                // earlier function will have mutated table
     387                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
     388
     389                                // skip mutating intrinsic functions
     390                                if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
     391
     392                                // user-defined non-copy functions do not override copy functions
     393                                if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
     394
     395                                // this function to be deleted after mangleTable iteration is complete
     396                                deleted.push_back( entry );
     397                        }
     398
     399                        // mark deletions to update mangle table
     400                        // this needs to be a separate loop because of iterator invalidation
     401                        for ( const auto& entry : deleted ) {
     402                                ++* stats().map_mutations;
     403                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     404                        }
     405                } else if ( function->linkage != LinkageSpec::Intrinsic ) {
     406                        // this is an overridable generated function
     407                        // if there already exists a matching user-defined function, delete this appropriately
     408                        for ( const auto& entry : * mangleTable ) {
     409                                // skip decls that aren't functions or are for the wrong type
     410                                const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     411                                if ( ! decl ) continue;
     412
     413                                // skip non-user-defined functions
     414                                if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
     415
     416                                if ( dataIsCopyFunc ) {
     417                                        // remove current function if exists a user-defined copy function
     418                                        // since the signatures for copy functions don't need to match exactly, using
     419                                        // a delete statement is the wrong approach
     420                                        if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
     421                                } else {
     422                                        // mark current function deleted by first user-defined function found
     423                                        data.deleteStmt = decl;
     424                                        return true;
     425                                }
     426                        }
     427                }
     428
     429                // nothing (more) to fix, return true
    423430                return true;
    424431        }
    425432
    426         void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
    427                 if ( decl->name == "" ) return;
    428                 debugPrint( "Adding Id " << decl->name << std::endl );
    429                 makeWritable();
    430 
     433        void Indexer::addId(const DeclarationWithType * decl, OnConflict handleConflicts, const Expression * baseExpr,
     434                        const Declaration * deleteStmt ) {
     435                ++* stats().add_calls;
    431436                const std::string &name = decl->name;
     437                if ( name == "" ) return;
     438
    432439                std::string mangleName;
    433440                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    434                         // mangle the name without including the appropriate suffix, so overridable routines are placed into the
    435                         // same "bucket" as their user defined versions.
     441                        // mangle the name without including the appropriate suffix, so overridable routines
     442                        // are placed into the same "bucket" as their user defined versions.
    436443                        mangleName = Mangler::mangle( decl, false );
    437444                } else {
     
    439446                } // if
    440447
    441                 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
    442                 if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
    443                         // NOTE this is broken in Richard's original code in such a way that it never triggers (it
    444                         // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
    445                         // have their name as their manglename, hence the error can never trigger).
    446                         // The code here is closer to correct, but name mangling would have to be completely
    447                         // isomorphic to C type-compatibility, which it may not be.
    448                         if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     448                // this ensures that no two declarations with the same unmangled name at the same scope
     449                // both have C linkage
     450                if ( LinkageSpec::isMangled( decl->linkage ) ) {
     451                        // Check that a Cforall declaration doesn't override any C declaration
     452                        if ( hasCompatibleCDecl( name, mangleName ) ) {
     453                                SemanticError( decl, "Cforall declaration hides C function " );
     454                        }
     455                } else {
     456                        // NOTE: only correct if name mangling is completely isomorphic to C
     457                        // type-compatibility, which it may not be.
     458                        if ( hasIncompatibleCDecl( name, mangleName ) ) {
    449459                                SemanticError( decl, "conflicting overload of C function " );
    450460                        }
    451                 } else {
    452                         // Check that a Cforall declaration doesn't override any C declaration
    453                         if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    454                                 SemanticError( decl, "Cforall declaration hides C function " );
    455                         }
    456                 }
    457 
    458                 // Skip repeat declarations of the same identifier
    459                 IdData * existing = lookupIdAtScope( name, mangleName, scope );
    460                 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
    461 
    462                 // add to indexer
    463                 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
    464                 ++tables->size;
    465         }
    466 
    467         void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
     461                }
     462
     463                // ensure tables exist and add identifier
     464                MangleTable::Ptr mangleTable;
     465                if ( ! idTable ) {
     466                        idTable = IdTable::new_ptr();
     467                        mangleTable = MangleTable::new_ptr();
     468                } else {
     469                        ++* stats().map_lookups;
     470                        auto decls = idTable->find( name );
     471                        if ( decls == idTable->end() ) {
     472                                mangleTable = MangleTable::new_ptr();
     473                        } else {
     474                                mangleTable = decls->second;
     475                                // skip in-scope repeat declarations of same identifier
     476                                ++* stats().map_lookups;
     477                                auto existing = mangleTable->find( mangleName );
     478                                if ( existing != mangleTable->end()
     479                                                && existing->second.scope == scope
     480                                                && existing->second.id ) {
     481                                        if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
     482                                                if ( handleConflicts.mode == OnConflict::Delete ) {
     483                                                        // set delete expression for conflicting identifier
     484                                                        lazyInitScope();
     485                                                        * stats().map_mutations += 2;
     486                                                        idTable = idTable->set(
     487                                                                name,
     488                                                                mangleTable->set(
     489                                                                        mangleName,
     490                                                                        IdData{ existing->second, handleConflicts.deleteStmt } ) );
     491                                                }
     492                                                return;
     493                                        }
     494                                }
     495                        }
     496                }
     497
     498                // add/overwrite with new identifier
     499                lazyInitScope();
     500                IdData data{ decl, baseExpr, deleteStmt, scope };
     501                // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
     502                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
     503                * stats().map_mutations += 2;
     504                idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
     505        }
     506
     507        void Indexer::addId( const DeclarationWithType * decl, const Expression * baseExpr ) {
    468508                // default handling of conflicts is to raise an error
    469                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
    470         }
    471 
    472         void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
     509                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     510        }
     511
     512        void Indexer::addDeletedId( const DeclarationWithType * decl, const Declaration * deleteStmt ) {
    473513                // default handling of conflicts is to raise an error
    474                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
    475         }
    476 
    477         bool addedTypeConflicts( NamedTypeDecl *existing, NamedTypeDecl *added ) {
    478                 if ( existing->get_base() == 0 ) {
     514                addId( decl, OnConflict::error(), nullptr, deleteStmt );
     515        }
     516
     517        bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) {
     518                if ( existing->base == nullptr ) {
    479519                        return false;
    480                 } else if ( added->get_base() == 0 ) {
     520                } else if ( added->base == nullptr ) {
    481521                        return true;
    482522                } else {
    483                         SemanticError( added, "redeclaration of " );
    484                 }
    485         }
    486 
    487         void Indexer::addType( NamedTypeDecl *decl ) {
    488                 debugPrint( "Adding type " << decl->name << std::endl );
    489                 makeWritable();
    490 
    491                 const std::string &id = decl->get_name();
    492                 TypeTable::iterator existing = tables->typeTable.find( id );
    493                 if ( existing == tables->typeTable.end() ) {
    494                         NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
    495                         if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
    496                                 tables->typeTable.insert( existing, std::make_pair( id, decl ) );
    497                                 ++tables->size;
    498                         }
    499                 } else {
    500                         if ( ! addedTypeConflicts( existing->second, decl ) ) {
    501                                 existing->second = decl;
    502                         }
    503                 }
    504         }
    505 
    506         bool addedDeclConflicts( AggregateDecl *existing, AggregateDecl *added ) {
     523                        assert( existing->base && added->base );
     524                        // typedef redeclarations are errors only if types are different
     525                        if ( ! ResolvExpr::typesCompatible( existing->base, added->base, Indexer() ) ) {
     526                                SemanticError( added->location, "redeclaration of " + added->name );
     527                        }
     528                }
     529                // does not need to be added to the table if both existing and added have a base that are
     530                // the same
     531                return true;
     532        }
     533
     534        void Indexer::addType( const NamedTypeDecl * decl ) {
     535                ++* stats().add_calls;
     536                const std::string & id = decl->name;
     537
     538                if ( ! typeTable ) {
     539                        typeTable = TypeTable::new_ptr();
     540                } else {
     541                        ++* stats().map_lookups;
     542                        auto existing = typeTable->find( id );
     543                        if ( existing != typeTable->end()
     544                                && existing->second.scope == scope
     545                                && addedTypeConflicts( existing->second.decl, decl ) ) return;
     546                }
     547
     548                lazyInitScope();
     549                ++* stats().map_mutations;
     550                typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
     551        }
     552
     553        bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) {
    507554                if ( ! existing->body ) {
    508555                        return false;
     
    513560        }
    514561
    515         void Indexer::addStruct( const std::string &id ) {
    516                 debugPrint( "Adding fwd decl for struct " << id << std::endl );
     562        void Indexer::addStruct( const std::string & id ) {
    517563                addStruct( new StructDecl( id ) );
    518564        }
    519565
    520         void Indexer::addStruct( StructDecl *decl ) {
    521                 debugPrint( "Adding struct " << decl->name << std::endl );
    522                 makeWritable();
    523 
    524                 const std::string &id = decl->get_name();
    525                 StructTable::iterator existing = tables->structTable.find( id );
    526                 if ( existing == tables->structTable.end() ) {
    527                         StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
    528                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    529                                 tables->structTable.insert( existing, std::make_pair( id, decl ) );
    530                                 ++tables->size;
    531                         }
    532                 } else {
    533                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    534                                 existing->second = decl;
    535                         }
    536                 }
    537         }
    538 
    539         void Indexer::addEnum( EnumDecl *decl ) {
    540                 debugPrint( "Adding enum " << decl->name << std::endl );
    541                 makeWritable();
    542 
    543                 const std::string &id = decl->get_name();
    544                 EnumTable::iterator existing = tables->enumTable.find( id );
    545                 if ( existing == tables->enumTable.end() ) {
    546                         EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
    547                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    548                                 tables->enumTable.insert( existing, std::make_pair( id, decl ) );
    549                                 ++tables->size;
    550                         }
    551                 } else {
    552                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    553                                 existing->second = decl;
    554                         }
    555                 }
    556         }
    557 
    558         void Indexer::addUnion( const std::string &id ) {
    559                 debugPrint( "Adding fwd decl for union " << id << std::endl );
     566        void Indexer::addStruct( const StructDecl * decl ) {
     567                ++* stats().add_calls;
     568                const std::string & id = decl->name;
     569
     570                if ( ! structTable ) {
     571                        structTable = StructTable::new_ptr();
     572                } else {
     573                        ++* stats().map_lookups;
     574                        auto existing = structTable->find( id );
     575                        if ( existing != structTable->end()
     576                                && existing->second.scope == scope
     577                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     578                }
     579
     580                lazyInitScope();
     581                ++* stats().map_mutations;
     582                structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
     583        }
     584
     585        void Indexer::addEnum( const EnumDecl * decl ) {
     586                ++* stats().add_calls;
     587                const std::string & id = decl->name;
     588
     589                if ( ! enumTable ) {
     590                        enumTable = EnumTable::new_ptr();
     591                } else {
     592                        ++* stats().map_lookups;
     593                        auto existing = enumTable->find( id );
     594                        if ( existing != enumTable->end()
     595                                && existing->second.scope == scope
     596                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     597                }
     598
     599                lazyInitScope();
     600                ++* stats().map_mutations;
     601                enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
     602        }
     603
     604        void Indexer::addUnion( const std::string & id ) {
    560605                addUnion( new UnionDecl( id ) );
    561606        }
    562607
    563         void Indexer::addUnion( UnionDecl *decl ) {
    564                 debugPrint( "Adding union " << decl->name << std::endl );
    565                 makeWritable();
    566 
    567                 const std::string &id = decl->get_name();
    568                 UnionTable::iterator existing = tables->unionTable.find( id );
    569                 if ( existing == tables->unionTable.end() ) {
    570                         UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
    571                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    572                                 tables->unionTable.insert( existing, std::make_pair( id, decl ) );
    573                                 ++tables->size;
    574                         }
    575                 } else {
    576                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    577                                 existing->second = decl;
    578                         }
    579                 }
    580         }
    581 
    582         void Indexer::addTrait( TraitDecl *decl ) {
    583                 debugPrint( "Adding trait " << decl->name << std::endl );
    584                 makeWritable();
    585 
    586                 const std::string &id = decl->get_name();
    587                 TraitTable::iterator existing = tables->traitTable.find( id );
    588                 if ( existing == tables->traitTable.end() ) {
    589                         TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
    590                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    591                                 tables->traitTable.insert( existing, std::make_pair( id, decl ) );
    592                                 ++tables->size;
    593                         }
    594                 } else {
    595                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    596                                 existing->second = decl;
    597                         }
    598                 }
    599         }
    600 
    601         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
     608        void Indexer::addUnion( const UnionDecl * decl ) {
     609                ++* stats().add_calls;
     610                const std::string & id = decl->name;
     611
     612                if ( ! unionTable ) {
     613                        unionTable = UnionTable::new_ptr();
     614                } else {
     615                        ++* stats().map_lookups;
     616                        auto existing = unionTable->find( id );
     617                        if ( existing != unionTable->end()
     618                                && existing->second.scope == scope
     619                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     620                }
     621
     622                lazyInitScope();
     623                ++* stats().map_mutations;
     624                unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
     625        }
     626
     627        void Indexer::addTrait( const TraitDecl * decl ) {
     628                ++* stats().add_calls;
     629                const std::string & id = decl->name;
     630
     631                if ( ! traitTable ) {
     632                        traitTable = TraitTable::new_ptr();
     633                } else {
     634                        ++* stats().map_lookups;
     635                        auto existing = traitTable->find( id );
     636                        if ( existing != traitTable->end()
     637                                && existing->second.scope == scope
     638                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     639                }
     640
     641                lazyInitScope();
     642                ++* stats().map_mutations;
     643                traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
     644        }
     645
     646        void Indexer::addMembers( const AggregateDecl * aggr, const Expression * expr, OnConflict handleConflicts ) {
    602647                for ( Declaration * decl : aggr->members ) {
    603648                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
    604649                                addId( dwt, handleConflicts, expr );
    605650                                if ( dwt->name == "" ) {
    606                                         Type * t = dwt->get_type()->stripReferences();
    607                                         if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     651                                        const Type * t = dwt->get_type()->stripReferences();
     652                                        if ( dynamic_cast<const StructInstType *>( t ) || dynamic_cast<const UnionInstType *>( t ) ) {
    608653                                                Expression * base = expr->clone();
    609654                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    616661        }
    617662
    618         void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) {
    619                 for ( Expression * expr : withExprs ) {
     663        void Indexer::addWith( const std::list< Expression * > & withExprs, const Declaration * withStmt ) {
     664                for ( const Expression * expr : withExprs ) {
    620665                        if ( expr->result ) {
    621666                                AggregateDecl * aggr = expr->result->stripReferences()->getAggr();
    622667                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    623668
    624                                 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
    625                                         // on conflict, delete the identifier
    626                                         existing.deleteStmt = withStmt;
    627                                         return true;
    628                                 });
     669                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
    629670                        }
    630671                }
     
    644685        }
    645686
    646         void Indexer::addFunctionType( FunctionType * ftype ) {
     687        void Indexer::addFunctionType( const FunctionType * ftype ) {
    647688                addTypes( ftype->forall );
    648689                addIds( ftype->returnVals );
    649690                addIds( ftype->parameters );
    650         }
    651 
    652         void Indexer::enterScope() {
    653                 ++scope;
    654 
    655                 if ( doDebug ) {
    656                         std::cerr << "--- Entering scope " << scope << std::endl;
    657                 }
    658         }
    659 
    660         void Indexer::leaveScope() {
    661                 using std::cerr;
    662 
    663                 assert( scope > 0 && "cannot leave initial scope" );
    664                 if ( doDebug ) {
    665                         cerr << "--- Leaving scope " << scope << " containing" << std::endl;
    666                 }
    667                 --scope;
    668 
    669                 while ( tables && tables->scope > scope ) {
    670                         if ( doDebug ) {
    671                                 dump( tables->idTable, cerr );
    672                                 dump( tables->typeTable, cerr );
    673                                 dump( tables->structTable, cerr );
    674                                 dump( tables->enumTable, cerr );
    675                                 dump( tables->unionTable, cerr );
    676                                 dump( tables->traitTable, cerr );
    677                         }
    678 
    679                         // swap tables for base table until we find one at an appropriate scope
    680                         Indexer::Impl *base = newRef( tables->base.tables );
    681                         deleteRef( tables );
    682                         tables = base;
    683                 }
    684         }
    685 
    686         void Indexer::print( std::ostream &os, int indent ) const {
    687                 using std::cerr;
    688 
    689                 if ( tables ) {
    690                         os << "--- scope " << tables->scope << " ---" << std::endl;
    691 
    692                         os << "===idTable===" << std::endl;
    693                         dump( tables->idTable, os );
    694                         os << "===typeTable===" << std::endl;
    695                         dump( tables->typeTable, os );
    696                         os << "===structTable===" << std::endl;
    697                         dump( tables->structTable, os );
    698                         os << "===enumTable===" << std::endl;
    699                         dump( tables->enumTable, os );
    700                         os << "===unionTable===" << std::endl;
    701                         dump( tables->unionTable, os );
    702                         os << "===contextTable===" << std::endl;
    703                         dump( tables->traitTable, os );
    704 
    705                         tables->base.print( os, indent );
    706                 } else {
    707                         os << "--- end ---" << std::endl;
    708                 }
    709 
    710691        }
    711692
     
    715696                        Expression * base = baseExpr->clone();
    716697                        ResolvExpr::referenceToRvalueConversion( base, cost );
    717                         ret = new MemberExpr( id, base );
     698                        ret = new MemberExpr( const_cast<DeclarationWithType *>(id), base );
    718699                        // xxx - this introduces hidden environments, for now remove them.
    719700                        // std::swap( base->env, ret->env );
     
    721702                        base->env = nullptr;
    722703                } else {
    723                         ret = new VariableExpr( id );
    724                 }
    725                 if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt );
     704                        ret = new VariableExpr( const_cast<DeclarationWithType *>(id) );
     705                }
     706                if ( deleteStmt ) ret = new DeletedExpr( ret, const_cast<Declaration *>(deleteStmt) );
    726707                return ret;
    727708        }
Note: See TracChangeset for help on using the changeset viewer.