Changeset 6d6e829


Ignore:
Timestamp:
Oct 12, 2018, 3:19:35 PM (6 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, no_list, persistent-indexer, pthread-emulation, qualifiedEnum
Children:
da48183
Parents:
59cf83b
Message:

First compiling draft of deferred assertions (build failure)

Location:
src
Files:
3 added
12 edited

Legend:

Unmodified
Added
Removed
  • src/Makefile.am

    r59cf83b r6d6e829  
    126126  ResolvExpr/PtrsCastable.cc \
    127127  ResolvExpr/RenameVars.cc \
     128  ResolvExpr/ResolveAssertions.cc \
    128129  ResolvExpr/Resolver.cc \
    129130  ResolvExpr/ResolveTypeof.cc \
  • src/Makefile.in

    r59cf83b r6d6e829  
    203203        ResolvExpr/PtrsAssignable.$(OBJEXT) \
    204204        ResolvExpr/PtrsCastable.$(OBJEXT) \
    205         ResolvExpr/RenameVars.$(OBJEXT) ResolvExpr/Resolver.$(OBJEXT) \
     205        ResolvExpr/RenameVars.$(OBJEXT) \
     206        ResolvExpr/ResolveAssertions.$(OBJEXT) \
     207        ResolvExpr/Resolver.$(OBJEXT) \
    206208        ResolvExpr/ResolveTypeof.$(OBJEXT) \
    207209        ResolvExpr/SpecCost.$(OBJEXT) \
     
    261263        ResolvExpr/CurrentObject.$(OBJEXT) \
    262264        ResolvExpr/ExplodedActual.$(OBJEXT) \
    263         ResolvExpr/SpecCost.$(OBJEXT) SymTab/Indexer.$(OBJEXT) \
    264         SymTab/Mangler.$(OBJEXT) SymTab/ManglerCommon.$(OBJEXT) \
    265         SymTab/Validate.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
    266         SymTab/Autogen.$(OBJEXT) SynTree/Type.$(OBJEXT) \
    267         SynTree/VoidType.$(OBJEXT) SynTree/BasicType.$(OBJEXT) \
    268         SynTree/PointerType.$(OBJEXT) SynTree/ArrayType.$(OBJEXT) \
    269         SynTree/ReferenceType.$(OBJEXT) SynTree/FunctionType.$(OBJEXT) \
     265        ResolvExpr/SpecCost.$(OBJEXT) \
     266        ResolvExpr/ResolveAssertions.$(OBJEXT) \
     267        SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
     268        SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) \
     269        SymTab/FixFunction.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \
     270        SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
     271        SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
     272        SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \
     273        SynTree/FunctionType.$(OBJEXT) \
    270274        SynTree/ReferenceToType.$(OBJEXT) SynTree/TupleType.$(OBJEXT) \
    271275        SynTree/TypeofType.$(OBJEXT) SynTree/AttrType.$(OBJEXT) \
     
    549553        ResolvExpr/Occurs.cc ResolvExpr/TypeEnvironment.cc \
    550554        ResolvExpr/CurrentObject.cc ResolvExpr/ExplodedActual.cc \
    551         ResolvExpr/SpecCost.cc SymTab/Indexer.cc SymTab/Mangler.cc \
    552         SymTab/ManglerCommon.cc SymTab/Validate.cc \
    553         SymTab/FixFunction.cc SymTab/Autogen.cc SynTree/Type.cc \
    554         SynTree/VoidType.cc SynTree/BasicType.cc \
     555        ResolvExpr/SpecCost.cc ResolvExpr/ResolveAssertions.cc \
     556        SymTab/Indexer.cc SymTab/Mangler.cc SymTab/ManglerCommon.cc \
     557        SymTab/Validate.cc SymTab/FixFunction.cc SymTab/Autogen.cc \
     558        SynTree/Type.cc SynTree/VoidType.cc SynTree/BasicType.cc \
    555559        SynTree/PointerType.cc SynTree/ArrayType.cc \
    556560        SynTree/ReferenceType.cc SynTree/FunctionType.cc \
     
    657661  ResolvExpr/PtrsCastable.cc \
    658662  ResolvExpr/RenameVars.cc \
     663  ResolvExpr/ResolveAssertions.cc \
    659664  ResolvExpr/Resolver.cc \
    660665  ResolvExpr/ResolveTypeof.cc \
     
    908913ResolvExpr/RenameVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    909914        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     915ResolvExpr/ResolveAssertions.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     916        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    910917ResolvExpr/Resolver.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    911918        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     
    11641171@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/PtrsCastable.Po@am__quote@
    11651172@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/RenameVars.Po@am__quote@
     1173@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ResolveAssertions.Po@am__quote@
    11661174@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ResolveTypeof.Po@am__quote@
    11671175@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Resolver.Po@am__quote@
  • src/ResolvExpr/Alternative.cc

    r59cf83b r6d6e829  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:44:23 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 16 23:54:23 2015
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu Oct 11 10:55:00 2018
     13// Update Count     : 3
    1414//
    1515
     
    2727
    2828namespace ResolvExpr {
    29         Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr ) {}
     29        Alternative::Alternative()
     30        : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr ), env(), openVars(), need() {}
    3031
    31         Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost )
    32                 : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( env ) {}
     32        Alternative::Alternative( Expression *expr, const TypeEnvironment &env )
     33        : cost( Cost::zero ), cvtCost( Cost::zero ), expr( expr ), env( env ), openVars(), need() {}
     34       
     35        Alternative::Alternative( const Alternative &o, Expression *expr, const Cost &cost )
     36        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( o.env ), openVars( o.openVars ),
     37          need( o.need ) {}
    3338
    34         Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost, const Cost &cvtCost )
    35                 : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ) {}
     39        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     40                const OpenVarSet& openVars, const AssertionList& need, const Cost& cost )
     41        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( env ), openVars( openVars ),
     42          need( need ) {}
    3643
    37         Alternative::Alternative( const Alternative &other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( maybeClone( other.expr ) ), env( other.env ) {
    38         }
     44        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     45                const OpenVarSet& openVars, const AssertionList& need, const Cost& cost,
     46                const Cost &cvtCost )
     47        : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ), openVars( openVars ),
     48          need( need ) {}
     49
     50        Alternative::Alternative( const Alternative &other )
     51        : cost( other.cost ), cvtCost( other.cvtCost ), expr( maybeClone( other.expr ) ),
     52          env( other.env ), openVars( other.openVars ), need( other.need ) {}
    3953
    4054        Alternative &Alternative::operator=( const Alternative &other ) {
     
    4559                expr = maybeClone( other.expr );
    4660                env = other.env;
     61                openVars = other.openVars;
     62                need = other.need;
    4763                return *this;
    4864        }
    4965
    50         Alternative::Alternative( Alternative && other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ), env( std::move( other.env ) ) {
     66        Alternative::Alternative( Alternative && other )
     67        : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ),
     68          env( std::move( other.env ) ), openVars( std::move( other.openVars ) ),
     69          need( std::move( other.need ) ) {
    5170                other.expr = nullptr;
    5271        }
     
    5978                expr = other.expr;
    6079                env = std::move( other.env );
     80                openVars = std::move( other.openVars );
     81                need = std::move( other.need );
    6182                other.expr = nullptr;
    6283                return *this;
  • src/ResolvExpr/Alternative.h

    r59cf83b r6d6e829  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:45:43 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:36 2017
    13 // Update Count     : 3
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu Oct 11 10:55:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    2020
    2121#include "Cost.h"             // for Cost
    22 #include "TypeEnvironment.h"  // for TypeEnvironment
     22#include "TypeEnvironment.h"  // for TypeEnvironment, AssertionSetValue
    2323
    2424class Expression;
    2525
    2626namespace ResolvExpr {
     27        /// One assertion to resolve
     28        struct AssertionItem {
     29                DeclarationWithType* decl;
     30                AssertionSetValue info;
     31               
     32                AssertionItem() = default;
     33                AssertionItem( DeclarationWithType* decl, const AssertionSetValue& info )
     34                : decl(decl), info(info) {}
     35                AssertionItem( const AssertionSet::value_type& e ) : decl(e.first), info(e.second) {}
     36                operator AssertionSet::value_type () const { return { decl, info }; }
     37        };
     38        /// A list of unresolved assertions
     39        using AssertionList = std::vector<AssertionItem>;
     40
     41        /// One option for resolution of an expression
    2742        struct Alternative {
    2843                Alternative();
    29                 Alternative( Expression *expr, const TypeEnvironment &env, const Cost &cost );
    30                 Alternative( Expression *expr, const TypeEnvironment &env, const Cost &cost, const Cost &cvtCost );
     44                Alternative( Expression *expr, const TypeEnvironment &env );
     45                Alternative( const Alternative &o, Expression *expr, const Cost &cost );
     46                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet& openVars,
     47                        const AssertionList& need, const Cost &cost );
     48                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet& openVars,
     49                        const AssertionList& need, const Cost &cost, const Cost &cvtCost );
    3150                Alternative( const Alternative &other );
    3251                Alternative &operator=( const Alternative &other );
     
    4463                }
    4564
    46                 Cost cost;
    47                 Cost cvtCost;
    48                 Expression *expr;
    49                 TypeEnvironment env;
     65                /// Sorts by cost
     66                bool operator< ( const Alternative& o ) const { return cost < o.cost; }
     67
     68                Cost cost;            ///< Cost of the whole expression
     69                Cost cvtCost;         ///< Cost of conversions to the satisfying expression
     70                Expression *expr;     ///< Satisfying expression
     71                TypeEnvironment env;  ///< Containing type environment
     72                OpenVarSet openVars;  ///< Open variables for environment
     73                AssertionList need;   ///< Assertions which need to be resolved
    5074        };
    5175
  • src/ResolvExpr/AlternativeFinder.cc

    r59cf83b r6d6e829  
    3434#include "InitTweak/InitTweak.h"   // for getFunctionName
    3535#include "RenameVars.h"            // for RenameVars, global_renamer
     36#include "ResolveAssertions.h"     // for resolveAssertions
    3637#include "ResolveTypeof.h"         // for resolveTypeof
    3738#include "Resolver.h"              // for resolveStmtExpr
     
    102103                void addAnonConversions( const Alternative & alt );
    103104                /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
    104                 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
     105                template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Alternative &alt, const Cost &newCost, const std::string & name );
    105106                /// Adds alternatives for member expressions where the left side has tuple type
    106                 void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
     107                void addTupleMembers( TupleType *tupleType, Expression *expr, const Alternative &alt, const Cost &newCost, Expression *member );
    107108                /// Adds alternatives for offsetof expressions, given the base type and name of the member
    108109                template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
     
    253254                        SemanticError( expr, "No reasonable alternatives for expression " );
    254255                }
     256                if ( mode.resolveAssns ) {
     257                        // trim candidates just to those where the assertions resolve
     258                        AltList candidates;
     259                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
     260                                resolveAssertions( alternatives[i], indexer, candidates );
     261                        }
     262                        // fail early if none such
     263                        if ( mode.failFast && candidates.empty() ) {
     264                                std::ostringstream stream;
     265                                stream << "No resolvable alternatives for expression " << expr << "\n"
     266                                       << "Alternatives with failing assertions are:\n";
     267                                printAlts( alternatives, stream, 1 );
     268                                SemanticError( expr->location, stream.str() );
     269                        }
     270                        // reset alternatives
     271                        alternatives = std::move( candidates );
     272                }
    255273                if ( mode.prune ) {
    256274                        auto oldsize = alternatives.size();
     
    317335
    318336                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
    319                         addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
     337                        addAggMembers( structInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
    320338                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
    321                         addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
     339                        addAggMembers( unionInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
    322340                } // if
    323341        }
    324342
    325343        template< typename StructOrUnionType >
    326         void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
     344        void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Alternative& alt, const Cost &newCost, const std::string & name ) {
    327345                std::list< Declaration* > members;
    328346                aggInst->lookup( name, members );
     
    332350                                // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    333351                                // can't construct in place and use vector::back
    334                                 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost );
     352                                Alternative newAlt{ alt, new MemberExpr{ dwt, expr->clone() }, newCost };
    335353                                renameTypes( newAlt.expr );
    336354                                addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
     
    342360        }
    343361
    344         void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
     362        void AlternativeFinder::Finder::addTupleMembers( TupleType *tupleType, Expression *expr,                        const Alternative &alt, const Cost &newCost, Expression *member ) {
    345363                if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
    346364                        // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
     
    348366                        std::string tmp;
    349367                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    350                                 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
     368                                alternatives.push_back( Alternative{
     369                                        alt, new TupleIndexExpr( expr->clone(), val ), newCost } );
    351370                        } // if
    352371                } // if
     
    354373
    355374        void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
    356                 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
     375                alternatives.push_back( Alternative{ applicationExpr->clone(), env } );
    357376        }
    358377
     
    484503        }
    485504
    486         static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
    487 
    488         void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
    489                 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
    490                         if ( i->second.isUsed ) {
    491                                 indexer.addId( i->first );
    492                         }
    493                 }
    494         }
    495 
    496         template< typename ForwardIterator, typename OutputIterator >
    497         void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) {
    498                 if ( newAlt.cost == Cost::infinity ) return; // don't proceed down this dead end
    499                 if ( begin == end ) {
    500                         if ( newNeed.empty() ) {
    501                                 PRINT(
    502                                         std::cerr << "all assertions satisfied, output alternative: ";
    503                                         newAlt.print( std::cerr );
    504                                         std::cerr << std::endl;
    505                                 );
    506                                 *out++ = newAlt;
    507                                 return;
    508                         } else if ( level >= recursionLimit ) {
    509                                 SemanticError( newAlt.expr->location, "Too many recursive assertions" );
    510                         } else {
    511                                 AssertionSet newerNeed;
    512                                 PRINT(
    513                                         std::cerr << "recursing with new set:" << std::endl;
    514                                         printAssertionSet( newNeed, std::cerr, 8 );
    515                                 )
    516                                 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
    517                                 return;
    518                         }
    519                 }
    520 
    521                 ForwardIterator cur = begin++;
    522                 if ( ! cur->second.isUsed ) {
    523                         inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
    524                         return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
    525                 }
    526                 DeclarationWithType *curDecl = cur->first;
    527 
    528                 PRINT(
    529                         std::cerr << "inferRecursive: assertion is ";
    530                         curDecl->print( std::cerr );
    531                         std::cerr << std::endl;
    532                 )
    533                 std::list< SymTab::Indexer::IdData > candidates;
    534                 decls.lookupId( curDecl->get_name(), candidates );
    535 ///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
    536                 for ( const auto & data : candidates ) {
    537                         DeclarationWithType * candidate = data.id;
    538                         PRINT(
    539                                 std::cerr << "inferRecursive: candidate is ";
    540                                 candidate->print( std::cerr );
    541                                 std::cerr << std::endl;
    542                         )
    543 
    544                         AssertionSet newHave, newerNeed( newNeed );
    545                         TypeEnvironment newEnv( newAlt.env );
    546                         OpenVarSet newOpenVars( openVars );
    547                         Type *adjType = candidate->get_type()->clone();
    548                         adjustExprType( adjType, newEnv, indexer );
    549                         renameTyVars( adjType );
    550                         PRINT(
    551                                 std::cerr << "unifying ";
    552                                 curDecl->get_type()->print( std::cerr );
    553                                 std::cerr << " with ";
    554                                 adjType->print( std::cerr );
    555                                 std::cerr << std::endl;
    556                         )
    557                         if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
    558                                 PRINT(
    559                                         std::cerr << "success!" << std::endl;
    560                                 )
    561                                 SymTab::Indexer newDecls( decls );
    562                                 addToIndexer( newHave, newDecls );
    563                                 Alternative newerAlt( newAlt );
    564                                 newerAlt.env = newEnv;
    565                                 assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    566 
    567                                 // everything with an empty idChain was pulled in by the current assertion.
    568                                 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
    569                                 for ( auto & a : newerNeed ) {
    570                                         if ( a.second.idChain.empty() ) {
    571                                                 a.second.idChain = cur->second.idChain;
    572                                                 a.second.idChain.push_back( curDecl->get_uniqueId() );
    573                                         }
    574                                 }
    575 
    576                                 Expression *varExpr = data.combine( newerAlt.cvtCost );
    577                                 delete varExpr->get_result();
    578                                 varExpr->set_result( adjType->clone() );
    579                                 PRINT(
    580                                         std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
    581                                         curDecl->print( std::cerr );
    582                                         std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
    583                                         candidate->print( std::cerr );
    584                                         std::cerr << std::endl;
    585                                 )
    586                                 // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
    587                                 InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
    588                                 for ( UniqueId id : cur->second.idChain ) {
    589                                         inferParameters = (*inferParameters)[ id ].inferParams.get();
    590                                 }
    591                                 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
    592                                 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
    593                                 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
    594                         } else {
    595                                 delete adjType;
    596                         }
    597                 }
    598         }
     505//      template< typename ForwardIterator, typename OutputIterator >
     506//      void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) {
     507//              if ( newAlt.cost == Cost::infinity ) return; // don't proceed down this dead end
     508//              if ( begin == end ) {
     509//                      if ( newNeed.empty() ) {
     510//                              PRINT(
     511//                                      std::cerr << "all assertions satisfied, output alternative: ";
     512//                                      newAlt.print( std::cerr );
     513//                                      std::cerr << std::endl;
     514//                              );
     515//                              *out++ = newAlt;
     516//                              return;
     517//                      } else if ( level >= recursionLimit ) {
     518//                              SemanticError( newAlt.expr->location, "Too many recursive assertions" );
     519//                      } else {
     520//                              AssertionSet newerNeed;
     521//                              PRINT(
     522//                                      std::cerr << "recursing with new set:" << std::endl;
     523//                                      printAssertionSet( newNeed, std::cerr, 8 );
     524//                              )
     525//                              inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
     526//                              return;
     527//                      }
     528//              }
     529
     530//              ForwardIterator cur = begin++;
     531//              if ( ! cur->second.isUsed ) {
     532//                      inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
     533//                      return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
     534//              }
     535//              DeclarationWithType *curDecl = cur->first;
     536
     537//              PRINT(
     538//                      std::cerr << "inferRecursive: assertion is ";
     539//                      curDecl->print( std::cerr );
     540//                      std::cerr << std::endl;
     541//              )
     542//              std::list< SymTab::Indexer::IdData > candidates;
     543//              decls.lookupId( curDecl->get_name(), candidates );
     544// ///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
     545//              for ( const auto & data : candidates ) {
     546//                      DeclarationWithType * candidate = data.id;
     547//                      PRINT(
     548//                              std::cerr << "inferRecursive: candidate is ";
     549//                              candidate->print( std::cerr );
     550//                              std::cerr << std::endl;
     551//                      )
     552
     553//                      AssertionSet newHave, newerNeed( newNeed );
     554//                      TypeEnvironment newEnv( newAlt.env );
     555//                      OpenVarSet newOpenVars( openVars );
     556//                      Type *adjType = candidate->get_type()->clone();
     557//                      adjustExprType( adjType, newEnv, indexer );
     558//                      renameTyVars( adjType );
     559//                      PRINT(
     560//                              std::cerr << "unifying ";
     561//                              curDecl->get_type()->print( std::cerr );
     562//                              std::cerr << " with ";
     563//                              adjType->print( std::cerr );
     564//                              std::cerr << std::endl;
     565//                      )
     566//                      if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
     567//                              PRINT(
     568//                                      std::cerr << "success!" << std::endl;
     569//                              )
     570//                              SymTab::Indexer newDecls( decls );
     571//                              addToIndexer( newHave, newDecls );
     572//                              Alternative newerAlt( newAlt );
     573//                              newerAlt.env = newEnv;
     574//                              assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
     575
     576//                              // everything with an empty idChain was pulled in by the current assertion.
     577//                              // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
     578//                              for ( auto & a : newerNeed ) {
     579//                                      if ( a.second.idChain.empty() ) {
     580//                                              a.second.idChain = cur->second.idChain;
     581//                                              a.second.idChain.push_back( curDecl->get_uniqueId() );
     582//                                      }
     583//                              }
     584
     585//                              Expression *varExpr = data.combine( newerAlt.cvtCost );
     586//                              delete varExpr->get_result();
     587//                              varExpr->set_result( adjType->clone() );
     588//                              PRINT(
     589//                                      std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
     590//                                      curDecl->print( std::cerr );
     591//                                      std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
     592//                                      candidate->print( std::cerr );
     593//                                      std::cerr << std::endl;
     594//                              )
     595//                              // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
     596//                              InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
     597//                              for ( UniqueId id : cur->second.idChain ) {
     598//                                      inferParameters = (*inferParameters)[ id ].inferParams.get();
     599//                              }
     600//                              // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
     601//                              (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
     602//                              inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
     603//                      } else {
     604//                              delete adjType;
     605//                      }
     606//              }
     607//      }
    599608
    600609        template< typename OutputIterator >
    601         void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
    602 //      PRINT(
    603 //          std::cerr << "inferParameters: assertions needed are" << std::endl;
    604 //          printAll( need, std::cerr, 8 );
    605 //          )
    606                 SymTab::Indexer decls( indexer );
     610        void AlternativeFinder::Finder::inferParameters( const AssertionSet &, AssertionSet &, const Alternative &newAlt, OpenVarSet &, OutputIterator out ) {
     611                // SymTab::Indexer decls( indexer );
     612                // addToIndexer( have, decls );
     613                // AssertionSet newNeed;
    607614                // PRINT(
    608                 //      std::cerr << "============= original indexer" << std::endl;
    609                 //      indexer.print( std::cerr );
    610                 //      std::cerr << "============= new indexer" << std::endl;
    611                 //      decls.print( std::cerr );
     615                //      std::cerr << "env is: " << std::endl;
     616                //      newAlt.env.print( std::cerr, 0 );
     617                //      std::cerr << std::endl;
    612618                // )
    613                 addToIndexer( have, decls );
    614                 AssertionSet newNeed;
    615                 PRINT(
    616                         std::cerr << "env is: " << std::endl;
    617                         newAlt.env.print( std::cerr, 0 );
    618                         std::cerr << std::endl;
    619                 )
    620 
    621                 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
    622 //      PRINT(
    623 //          std::cerr << "declaration 14 is ";
    624 //          Declaration::declFromId
    625 //          *out++ = newAlt;
    626 //          )
     619
     620                // inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
     621
     622                // add to output list, assertion resolution is defered
     623                *out++ = newAlt;
    627624        }
    628625
     
    965962                }
    966963                // build and validate new alternative
    967                 Alternative newAlt( appExpr, result.env, cost );
     964                Alternative newAlt{
     965                        appExpr, result.env, result.openVars,
     966                        AssertionList( result.need.begin(), result.need.end() ), cost };
    968967                PRINT(
    969968                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     
    12481247                        if ( isLvalue( alt.expr ) ) {
    12491248                                alternatives.push_back(
    1250                                         Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
     1249                                        Alternative{ alt, new AddressExpr( alt.expr->clone() ), alt.cost } );
    12511250                        } // if
    12521251                } // for
     
    12541253
    12551254        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
    1256                 alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
     1255                alternatives.push_back( Alternative{ expr->clone(), env } );
    12571256        }
    12581257
     
    12991298                AltList candidates;
    13001299                for ( Alternative & alt : finder.alternatives ) {
    1301                         AssertionSet needAssertions, haveAssertions;
    1302                         OpenVarSet openVars;
     1300                        AssertionSet needAssertions( alt.need.begin(), alt.need.end() );
     1301                        AssertionSet haveAssertions;
     1302                        OpenVarSet openVars{ alt.openVars };
    13031303
    13041304                        alt.env.extractOpenVars( openVars );
     
    13281328                                // count one safe conversion for each value that is thrown away
    13291329                                thisCost.incSafe( discardedValues );
    1330                                 Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
    1331                                         alt.cost, thisCost );
     1330                                Alternative newAlt{
     1331                                        restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ),
     1332                                        alt.env, openVars,
     1333                                        AssertionList( needAssertions.begin(), needAssertions.end() ), alt.cost,
     1334                                        thisCost };
    13321335                                inferParameters( needAssertions, haveAssertions, newAlt, openVars,
    13331336                                        back_inserter( candidates ) );
     
    13441347
    13451348        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
    1346                 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
     1349                assertf( castExpr->get_result(), "Implicit virtual cast targets not yet supported." );
    13471350                AlternativeFinder finder( indexer, env );
    13481351                // don't prune here, since it's guaranteed all alternatives will have the same type
    13491352                finder.findWithoutPrune( castExpr->get_arg() );
    13501353                for ( Alternative & alt : finder.alternatives ) {
    1351                         alternatives.push_back( Alternative(
    1352                                 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
    1353                                 alt.env, alt.cost ) );
     1354                        alternatives.push_back( Alternative{
     1355                                alt, new VirtualCastExpr{ alt.expr->clone(), castExpr->get_result()->clone() },
     1356                                alt.cost } );
    13541357                }
    13551358        }
     
    13761379                        // find member of the given type
    13771380                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
    1378                                 addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
     1381                                addAggMembers( structInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
    13791382                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
    1380                                 addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
     1383                                addAggMembers( unionInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
    13811384                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
    1382                                 addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
     1385                                addTupleMembers( tupleType, aggrExpr, *agg, cost, memberExpr->get_member() );
    13831386                        } // if
    13841387                } // for
     
    13861389
    13871390        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
    1388                 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
     1391                alternatives.push_back( Alternative{ memberExpr->clone(), env } );
    13891392        }
    13901393
     
    13991402                        // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    14001403                        // can't construct in place and use vector::back
    1401                         Alternative newAlt( newExpr, env, Cost::zero, cost );
     1404                        Alternative newAlt{ newExpr, env, OpenVarSet{}, AssertionList{}, Cost::zero, cost };
    14021405                        PRINT(
    14031406                                std::cerr << "decl is ";
     
    14171420                // not sufficient to clone here, because variable's type may have changed
    14181421                // since the VariableExpr was originally created.
    1419                 alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
     1422                alternatives.push_back( Alternative{ new VariableExpr{ variableExpr->var }, env } );
    14201423        }
    14211424
    14221425        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
    1423                 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
     1426                alternatives.push_back( Alternative{ constantExpr->clone(), env } );
    14241427        }
    14251428
     
    14271430                if ( sizeofExpr->get_isType() ) {
    14281431                        Type * newType = sizeofExpr->get_type()->clone();
    1429                         alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
     1432                        alternatives.push_back( Alternative{
     1433                                new SizeofExpr{ resolveTypeof( newType, indexer ) }, env } );
    14301434                } else {
    14311435                        // find all alternatives for the argument to sizeof
     
    14411445                        Alternative &choice = winners.front();
    14421446                        referenceToRvalueConversion( choice.expr, choice.cost );
    1443                         alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
     1447                        alternatives.push_back( Alternative{
     1448                                choice, new SizeofExpr( choice.expr->clone() ), Cost::zero } );
    14441449                } // if
    14451450        }
     
    14481453                if ( alignofExpr->get_isType() ) {
    14491454                        Type * newType = alignofExpr->get_type()->clone();
    1450                         alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
     1455                        alternatives.push_back( Alternative{
     1456                                new AlignofExpr{ resolveTypeof( newType, indexer ) }, env } );
    14511457                } else {
    14521458                        // find all alternatives for the argument to sizeof
     
    14621468                        Alternative &choice = winners.front();
    14631469                        referenceToRvalueConversion( choice.expr, choice.cost );
    1464                         alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
     1470                        alternatives.push_back( Alternative{
     1471                                choice, new AlignofExpr{ choice.expr->clone() }, Cost::zero } );
    14651472                } // if
    14661473        }
     
    14721479                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
    14731480                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
    1474                                 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
     1481                                alternatives.push_back( Alternative{
     1482                                        new OffsetofExpr{ aggInst->clone(), dwt }, env } );
    14751483                                renameTypes( alternatives.back().expr );
    14761484                        } else {
     
    14911499
    14921500        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
    1493                 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
     1501                alternatives.push_back( Alternative{ offsetofExpr->clone(), env } );
    14941502        }
    14951503
    14961504        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
    1497                 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
     1505                alternatives.push_back( Alternative{ offsetPackExpr->clone(), env } );
    14981506        }
    14991507
     
    15151523                                Cost cost = Cost::zero;
    15161524                                Expression * newExpr = data.combine( cost );
    1517                                 alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
     1525                                alternatives.push_back( Alternative{
     1526                                        new AttrExpr{ newExpr, argType->clone() }, env, OpenVarSet{}, AssertionList{}, 
     1527                                        Cost::zero, cost } );
    15181528                                for ( DeclarationWithType * retVal : function->returnVals ) {
    15191529                                        alternatives.back().expr->result = retVal->get_type()->clone();
     
    15541564                                Cost cost = Cost::zero;
    15551565                                Expression * newExpr = data.combine( cost );
    1556                                 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
     1566                                alternatives.push_back( Alternative{
     1567                                        newExpr, env, OpenVarSet{}, AssertionList{}, Cost::zero, cost } );
    15571568                                renameTypes( alternatives.back().expr );
    15581569                        } // for
     
    15691580                for ( const Alternative & first : firstFinder.alternatives ) {
    15701581                        for ( const Alternative & second : secondFinder.alternatives ) {
    1571                                 TypeEnvironment compositeEnv;
    1572                                 compositeEnv.simpleCombine( first.env );
     1582                                TypeEnvironment compositeEnv{ first.env };
    15731583                                compositeEnv.simpleCombine( second.env );
    1574 
    1575                                 LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
    1576                                 alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
     1584                                OpenVarSet openVars{ first.openVars };
     1585                                mergeOpenVars( openVars, second.openVars );
     1586                                AssertionList need{ first.need };
     1587                                need.insert( need.end(), second.need.begin(), second.need.end() );
     1588
     1589                                LogicalExpr *newExpr = new LogicalExpr{
     1590                                        first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() };
     1591                                alternatives.push_back( Alternative{
     1592                                        newExpr, compositeEnv, openVars, need, first.cost + second.cost } );
    15771593                        }
    15781594                }
     
    15951611                        for ( const Alternative & second : secondFinder.alternatives ) {
    15961612                                for ( const Alternative & third : thirdFinder.alternatives ) {
    1597                                         TypeEnvironment compositeEnv;
    1598                                         compositeEnv.simpleCombine( first.env );
     1613                                        TypeEnvironment compositeEnv{ first.env };
    15991614                                        compositeEnv.simpleCombine( second.env );
    16001615                                        compositeEnv.simpleCombine( third.env );
    1601 
     1616                                        OpenVarSet openVars{ first.openVars };
     1617                                        mergeOpenVars( openVars, second.openVars );
     1618                                        mergeOpenVars( openVars, third.openVars );
     1619                                        AssertionSet needAssertions( first.need.begin(), first.need.end() );
     1620                                        needAssertions.insert( second.need.begin(), second.need.end() );
     1621                                        needAssertions.insert( third.need.begin(), third.need.end() );
     1622                                        AssertionSet haveAssertions;
     1623                                       
    16021624                                        // unify true and false types, then infer parameters to produce new alternatives
    1603                                         OpenVarSet openVars;
    1604                                         AssertionSet needAssertions, haveAssertions;
    1605                                         Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
    16061625                                        Type* commonType = nullptr;
    1607                                         if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    1608                                                 ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
     1626                                        if ( unify( second.expr->result, third.expr->result, compositeEnv,
     1627                                                        needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
     1628                                                ConditionalExpr *newExpr = new ConditionalExpr{
     1629                                                        first.expr->clone(), second.expr->clone(), third.expr->clone() };
    16091630                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
    16101631                                                // convert both options to the conditional result type
    1611                                                 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
    1612                                                 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
    1613                                                 newAlt.expr = newExpr;
     1632                                                Cost cost = first.cost + second.cost + third.cost;
     1633                                                cost += computeExpressionConversionCost(
     1634                                                        newExpr->arg2, newExpr->result, indexer, compositeEnv );
     1635                                                cost += computeExpressionConversionCost(
     1636                                                        newExpr->arg3, newExpr->result, indexer, compositeEnv );
     1637                                                // output alternative
     1638                                                Alternative newAlt{
     1639                                                        newExpr, compositeEnv, openVars,
     1640                                                        AssertionList( needAssertions.begin(), needAssertions.end() ), cost };
    16141641                                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
    16151642                                        } // if
     
    16251652                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
    16261653                for ( const Alternative & alt : secondFinder.alternatives ) {
    1627                         alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
     1654                        alternatives.push_back( Alternative{
     1655                                alt, new CommaExpr{ newFirstArg->clone(), alt.expr->clone() }, alt.cost } );
    16281656                } // for
    16291657                delete newFirstArg;
     
    16401668                for ( const Alternative & first : firstFinder.alternatives ) {
    16411669                        for ( const Alternative & second : secondFinder.alternatives ) {
    1642                                 TypeEnvironment compositeEnv;
    1643                                 compositeEnv.simpleCombine( first.env );
     1670                                TypeEnvironment compositeEnv{ first.env };
    16441671                                compositeEnv.simpleCombine( second.env );
    1645                                 OpenVarSet openVars;
    1646                                 AssertionSet needAssertions, haveAssertions;
    1647                                 Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
     1672                                OpenVarSet openVars{ first.openVars };
     1673                                mergeOpenVars( openVars, second.openVars );
     1674                                AssertionSet needAssertions( first.need.begin(), first.need.end() );
     1675                                needAssertions.insert( second.need.begin(), second.need.end() );
     1676                                AssertionSet haveAssertions;
     1677
    16481678                                Type* commonType = nullptr;
    1649                                 if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    1650                                         RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
     1679                                if ( unify( first.expr->result, second.expr->result, compositeEnv, needAssertions,
     1680                                                haveAssertions, openVars, indexer, commonType ) ) {
     1681                                        RangeExpr * newExpr =
     1682                                                new RangeExpr{ first.expr->clone(), second.expr->clone() };
    16511683                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
    1652                                         newAlt.expr = newExpr;
     1684                                        Alternative newAlt{
     1685                                                newExpr, compositeEnv, openVars,
     1686                                                AssertionList( needAssertions.begin(), needAssertions.end() ),
     1687                                                first.cost + second.cost };
    16531688                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
    16541689                                } // if
     
    16691704
    16701705                        TypeEnvironment compositeEnv;
    1671                         simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
    1672                         alternatives.push_back(
    1673                                 Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
     1706                        OpenVarSet openVars;
     1707                        AssertionSet need;
     1708                        for ( const Alternative& alt : alts ) {
     1709                                compositeEnv.simpleCombine( alt.env );
     1710                                mergeOpenVars( openVars, alt.openVars );
     1711                                need.insert( alt.need.begin(), alt.need.end() );
     1712                        }
     1713                       
     1714                        alternatives.push_back( Alternative{
     1715                                new TupleExpr{ exprs }, compositeEnv, openVars,
     1716                                AssertionList( need.begin(), need.end() ), sumCost( alts ) } );
    16741717                } // for
    16751718        }
    16761719
    16771720        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
    1678                 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
     1721                alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
    16791722        }
    16801723
    16811724        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
    1682                 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
     1725                alternatives.push_back( Alternative{ impCpCtorExpr->clone(), env } );
    16831726        }
    16841727
     
    16891732                finder.findWithoutPrune( ctorExpr->get_callExpr() );
    16901733                for ( Alternative & alt : finder.alternatives ) {
    1691                         alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
     1734                        alternatives.push_back( Alternative{
     1735                                alt, new ConstructorExpr( alt.expr->clone() ), alt.cost } );
    16921736                }
    16931737        }
    16941738
    16951739        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
    1696                 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
     1740                alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
    16971741        }
    16981742
    16991743        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
    1700                 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
     1744                alternatives.push_back( Alternative{ tupleAssignExpr->clone(), env } );
    17011745        }
    17021746
     
    17071751                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
    17081752                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
    1709                         alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
     1753                        alternatives.push_back( Alternative{ alt, newUnqExpr, alt.cost } );
    17101754                }
    17111755        }
     
    17151759                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
    17161760                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
    1717                 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
     1761                alternatives.push_back( Alternative{ newStmtExpr, env } );
    17181762        }
    17191763
     
    17371781                        for ( Alternative & alt : finder.get_alternatives() ) {
    17381782                                TypeEnvironment newEnv( alt.env );
    1739                                 AssertionSet needAssertions, haveAssertions;
    1740                                 OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
     1783                                AssertionSet needAssertions( alt.need.begin(), alt.need.end() );
     1784                                AssertionSet haveAssertions;
     1785                                OpenVarSet openVars( alt.openVars ); 
     1786                                // xxx - find things in env that don't have a "representative type" and claim
     1787                                // those are open vars?
    17411788                                PRINT(
    17421789                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    17431790                                )
    1744                                 // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
    1745                                 // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
    1746                                 // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    1747                                 // to.
     1791                                // It's possible that a cast can throw away some values in a multiply-valued
     1792                                // expression. (An example is a cast-to-void, which casts from one value to
     1793                                // zero.)  Figure out the prefix of the subexpression results that are cast
     1794                                // directly.  The candidate is invalid if it has fewer results than there are
     1795                                // types to cast to.
    17481796                                int discardedValues = alt.expr->result->size() - toType->size();
    17491797                                if ( discardedValues < 0 ) continue;
    1750                                 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
    1751                                 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
     1798                                // xxx - may need to go into tuple types and extract relevant types and use
     1799                                // unifyList. Note that currently, this does not allow casting a tuple to an
     1800                                // atomic type (e.g. (int)([1, 2, 3]))
     1801                               
    17521802                                // unification run for side-effects
    1753                                 unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
     1803                                unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars,
     1804                                        indexer );
     1805                                // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?
    17541806
    17551807                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
     
    17571809                                        // count one safe conversion for each value that is thrown away
    17581810                                        thisCost.incSafe( discardedValues );
    1759                                         Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
     1811                                        Alternative newAlt{
     1812                                                new InitExpr{
     1813                                                        restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() },
     1814                                                newEnv, openVars,
     1815                                                AssertionList( needAssertions.begin(), needAssertions.end() ),
     1816                                                alt.cost, thisCost };
    17601817                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
    17611818                                }
  • src/ResolvExpr/Cost.h

    r59cf83b r6d6e829  
    1010// Created On       : Sun May 17 09:39:50 2015
    1111// Last Modified By : Aaron B. Moss
    12 // Last Modified On : Tue Oct 02 14:40:00 2018
    13 // Update Count     : 6
     12// Last Modified On : Fri Oct 05 14:32:00 2018
     13// Update Count     : 7
    1414//
    1515
     
    4646                bool operator!=( const Cost &other ) const;
    4747                friend std::ostream &operator<<( std::ostream &os, const Cost &cost );
     48                // returns negative for *this < other, 0 for *this == other, positive for *this > other
     49                int compare( const Cost &other ) const;
    4850
    4951                static const Cost zero;
     
    5658                static const Cost safe;
    5759                static const Cost reference;
     60
    5861          private:
    59                 int compare( const Cost &other ) const;
    60 
    6162                int unsafeCost;     ///< Unsafe (narrowing) conversions
    6263                int polyCost;       ///< Count of parameters and return values bound to some poly type
     
    172173        }
    173174
     175        inline int Cost::compare( const Cost &other ) const {
     176                if ( *this == infinity ) return +1;
     177                if ( other == infinity ) return -1;
     178
     179                int c = unsafeCost - other.unsafeCost; if ( c ) return c;
     180                c = polyCost - other.polyCost; if ( c ) return c;
     181                c = varCost - other.varCost; if ( c ) return c;
     182                c = specCost - other.specCost; if ( c ) return c;
     183                c = safeCost - other.safeCost; if ( c ) return c;
     184                return referenceCost - other.referenceCost;
     185        }
     186
    174187        inline bool Cost::operator==( const Cost &other ) const {
    175188                return unsafeCost == other.unsafeCost
  • src/ResolvExpr/ResolvMode.h

    r59cf83b r6d6e829  
    1010// Created On       : Mon Jun 11 13:28:00 2018
    1111// Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 11 13:28:00 2018
    13 // Update Count     : 1
     12// Last Modified On : Fri Oct 05 13:46:00 2018
     13// Update Count     : 2
    1414//
    1515
     
    2222                const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
    24                 const bool checkAssertions;  ///< Should assertions be checked? [false]
     24                const bool resolveAssns;     ///< Resolve assertions? [false]
    2525
    2626        private:
    27                 constexpr ResolvMode(bool a, bool p, bool ff, bool ca)
    28                         : adjust(a), prune(p), failFast(ff), checkAssertions(ca) {}
     27                constexpr ResolvMode(bool a, bool p, bool ff, bool ra)
     28                : adjust(a), prune(p), failFast(ff), resolveAssns(ra) {}
    2929
    3030        public:
    3131                /// Default settings
    32                 constexpr ResolvMode()
    33                         : adjust(false), prune(true), failFast(true), checkAssertions(false) {}
     32                constexpr ResolvMode() : adjust(false), prune(true), failFast(true), resolveAssns(false) {}
    3433               
    3534                /// With adjust flag set; turns array and function types into equivalent pointers
     
    4342                /// one resulting alternative
    4443                static constexpr ResolvMode withoutFailFast() { return { true, true, false, false }; }
     44
     45                /// The same mode, but with resolveAssns turned on; for top-level calls
     46                ResolvMode atTopLevel() const { return { adjust, prune, failFast, true }; }
    4547        };
    4648} // namespace ResolvExpr
  • src/ResolvExpr/Resolver.cc

    r59cf83b r6d6e829  
    1414//
    1515
    16 #include <stddef.h>                      // for NULL
    1716#include <cassert>                       // for strict_dynamic_cast, assert
    1817#include <memory>                        // for allocator, allocator_traits<...
    1918#include <tuple>                         // for get
    20 #include <vector>
     19#include <vector>                        // for vector
    2120
    2221#include "Alternative.h"                 // for Alternative, AltList
     
    171170                void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    172171                        assertf( untyped, "expected a non-null expression." );
     172
     173                        // xxx - this isn't thread-safe, but should work until we parallelize the resolver
     174                        static unsigned recursion_level = 0;
     175
     176                        ++recursion_level;
    173177                        TypeEnvironment env;
    174178                        AlternativeFinder finder( indexer, env );
    175                         finder.find( untyped, mode );
     179                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
     180                        --recursion_level;
    176181
    177182                        #if 0
     
    186191                        #endif
    187192
     193                        // produce filtered list of alternatives
    188194                        AltList candidates;
    189195                        for ( Alternative & alt : finder.get_alternatives() ) {
     
    193199                        }
    194200
    195                         // xxx - if > 1 alternative with same cost, ignore deleted and pick from remaining
    196                         // choose the lowest cost expression among the candidates
     201                        // produce invalid error if no candidates
     202                        if ( candidates.empty() ) {
     203                                SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
     204                        }
     205
     206                        // search for cheapest candidate
    197207                        AltList winners;
    198                         findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
    199                         if ( winners.size() == 0 ) {
    200                                 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    201                         } else if ( winners.size() != 1 ) {
     208                        bool seen_undeleted = false;
     209                        for ( unsigned i = 0; i < candidates.size(); ++i ) {
     210                                int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
     211
     212                                if ( c > 0 ) continue; // skip more expensive than winner
     213
     214                                if ( c < 0 ) {
     215                                        // reset on new cheapest
     216                                        seen_undeleted = ! findDeletedExpr( candidates[i].expr );
     217                                        winners.clear();
     218                                } else /* if ( c == 0 ) */ {
     219                                        if ( findDeletedExpr( candidates[i].expr ) ) {
     220                                                // skip deleted expression if already seen one equivalent-cost not
     221                                                if ( seen_undeleted ) continue;
     222                                        } else if ( ! seen_undeleted ) {
     223                                                // replace list of equivalent-cost deleted expressions with one non-deleted
     224                                                winners.clear();
     225                                                seen_undeleted = true;
     226                                        }
     227                                }
     228
     229                                winners.emplace_back( candidates[i] );
     230                        }
     231
     232                        // promote alternative.cvtCost to .cost
     233                        // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
     234                        for ( Alternative& winner : winners ) {
     235                                winner.cost = winner.cvtCost;
     236                        }
     237                       
     238                        // produce ambiguous errors, if applicable
     239                        if ( winners.size() != 1 ) {
    202240                                std::ostringstream stream;
    203241                                stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
     
    208246                        }
    209247
    210                         // there is one unambiguous interpretation - move the expression into the with statement
    211                         Alternative & choice = winners.front();
    212                         if ( findDeletedExpr( choice.expr ) ) {
     248                        // single selected choice
     249                        Alternative& choice = winners.front();
     250
     251                        // fail on only expression deleted
     252                        if ( ! seen_undeleted ) {
    213253                                SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
    214254                        }
     255
     256                        // xxx - check for ambiguous expressions
     257                       
     258                        // output selected choice
    215259                        alt = std::move( choice );
    216260                }
     
    358402
    359403        void Resolver::previsit( ObjectDecl *objectDecl ) {
    360                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that class-variable
    361                 // initContext is changed multiple time because the LHS is analysed twice. The second analysis changes
    362                 // initContext because of a function type can contain object declarations in the return and parameter types. So
    363                 // each value of initContext is retained, so the type on the first analysis is preserved and used for selecting
    364                 // the RHS.
     404                // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
     405                // class-variable initContext is changed multiple time because the LHS is analysed twice.
     406                // The second analysis changes initContext because of a function type can contain object
     407                // declarations in the return and parameter types. So each value of initContext is
     408                // retained, so the type on the first analysis is preserved and used for selecting the RHS.
    365409                GuardValue( currentObject );
    366410                currentObject = CurrentObject( objectDecl->get_type() );
     
    398442
    399443        void Resolver::postvisit( FunctionDecl *functionDecl ) {
    400                 // default value expressions have an environment which shouldn't be there and trips up later passes.
    401                 // xxx - it might be necessary to somehow keep the information from this environment, but I can't currently
    402                 // see how it's useful.
     444                // default value expressions have an environment which shouldn't be there and trips up
     445                // later passes.
     446                // xxx - it might be necessary to somehow keep the information from this environment, but I
     447                // can't currently see how it's useful.
    403448                for ( Declaration * d : functionDecl->type->parameters ) {
    404449                        if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
     
    750795                initExpr->expr = nullptr;
    751796                std::swap( initExpr->env, newExpr->env );
    752                 // InitExpr may have inferParams in the case where the expression specializes a function pointer,
    753                 // and newExpr may already have inferParams of its own, so a simple swap is not sufficient.
     797                // InitExpr may have inferParams in the case where the expression specializes a function
     798                // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
     799                // sufficient.
    754800                newExpr->spliceInferParams( initExpr );
    755801                delete initExpr;
    756802
    757                 // get the actual object's type (may not exactly match what comes back from the resolver due to conversions)
     803                // get the actual object's type (may not exactly match what comes back from the resolver
     804                // due to conversions)
    758805                Type * initContext = currentObject.getCurrentType();
    759806
     
    767814                                        if ( isCharType( pt->get_base() ) ) {
    768815                                                if ( CastExpr *ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    769                                                         // strip cast if we're initializing a char[] with a char *, e.g.  char x[] = "hello";
     816                                                        // strip cast if we're initializing a char[] with a char *,
     817                                                        // e.g.  char x[] = "hello";
    770818                                                        newExpr = ce->get_arg();
    771819                                                        ce->set_arg( nullptr );
     
    789837                // move cursor into brace-enclosed initializer-list
    790838                currentObject.enterListInit();
    791                 // xxx - fix this so that the list isn't copied, iterator should be used to change current element
     839                // xxx - fix this so that the list isn't copied, iterator should be used to change current
     840                // element
    792841                std::list<Designation *> newDesignations;
    793842                for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    794                         // iterate designations and initializers in pairs, moving the cursor to the current designated object and resolving
    795                         // the initializer against that object.
     843                        // iterate designations and initializers in pairs, moving the cursor to the current
     844                        // designated object and resolving the initializer against that object.
    796845                        Designation * des = std::get<0>(p);
    797846                        Initializer * init = std::get<1>(p);
     
    823872                // fall back on C-style initializer
    824873                delete ctorInit->get_ctor();
    825                 ctorInit->set_ctor( NULL );
     874                ctorInit->set_ctor( nullptr );
    826875                delete ctorInit->get_dtor();
    827                 ctorInit->set_dtor( NULL );
     876                ctorInit->set_dtor( nullptr );
    828877                maybeAccept( ctorInit->get_init(), *visitor );
    829878        }
     
    868917
    869918                // xxx - todo -- what about arrays?
    870                 // if ( dtor == NULL && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
     919                // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
    871920                //      // can reduce the constructor down to a SingleInit using the
    872921                //      // second argument from the ctor call, since
    873922                //      delete ctorInit->get_ctor();
    874                 //      ctorInit->set_ctor( NULL );
     923                //      ctorInit->set_ctor( nullptr );
    875924
    876925                //      Expression * arg =
  • src/ResolvExpr/TypeEnvironment.h

    r59cf83b r6d6e829  
    6868        typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet;
    6969        typedef std::map< std::string, TypeDecl::Data > OpenVarSet;
     70
     71        /// merges one set of open vars into another
     72        static inline void mergeOpenVars( OpenVarSet& dst, const OpenVarSet& src ) {
     73                for ( const auto& entry : src ) { dst[ entry.first ] = entry.second; }
     74        }
    7075
    7176        void printAssertionSet( const AssertionSet &, std::ostream &, int indent = 0 );
  • src/ResolvExpr/module.mk

    r59cf83b r6d6e829  
    3434       ResolvExpr/CurrentObject.cc \
    3535       ResolvExpr/ExplodedActual.cc \
    36        ResolvExpr/SpecCost.cc
     36       ResolvExpr/SpecCost.cc \
     37       ResolvExpr/ResolveAssertions.cc
  • src/Tuples/Explode.h

    r59cf83b r6d6e829  
    4444        template<typename OutputIterator>
    4545        void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
     46                        const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
    4647                        const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
    47                 *out++ = ResolvExpr::Alternative{ expr, env, cost, cvtCost };
     48                *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
    4849        }
    4950
    5051        /// Append alternative to an ExplodedActual
    5152        static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
    52                         const ResolvExpr::TypeEnvironment&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
     53                        const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
     54                        const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
    5355                ea.exprs.emplace_back( expr );
    54                 /// xxx -- merge environment, cost?
     56                /// xxx -- merge environment, openVars, need, cost?
    5557        }
    5658
     
    6870                                        // distribute reference cast over all components
    6971                                        append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
    70                                                 alt.env, alt.cost, alt.cvtCost );
     72                                                alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
    7173                                }
    7274                                // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
     
    102104                } else {
    103105                        // atomic (non-tuple) type - output a clone of the expression in a new alternative
    104                         append( std::forward<Output>(out), expr->clone(), alt.env, alt.cost, alt.cvtCost );
     106                        append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need, 
     107                                alt.cost, alt.cvtCost );
    105108                }
    106109        }
  • src/Tuples/TupleAssignment.cc

    r59cf83b r6d6e829  
    6262                struct Matcher {
    6363                  public:
    64                         Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, const
    65                                 ResolvExpr::AltList& rhs );
     64                        Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     65                                const ResolvExpr::AltList& rhs );
    6666                        virtual ~Matcher() {}
     67                       
    6768                        virtual void match( std::list< Expression * > &out ) = 0;
    6869                        ObjectDecl * newObject( UniqueName & namer, Expression * expr );
     70
     71                        void combineState( const ResolvExpr::Alternative& alt ) {
     72                                compositeEnv.simpleCombine( alt.env );
     73                                ResolvExpr::mergeOpenVars( openVars, alt.openVars );
     74                                need.insert( alt.need.begin(), alt.need.end() );
     75                        }
     76
     77                        void combineState( const ResolvExpr::AltList& alts ) {
     78                                for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
     79                        }
     80                       
    6981                        ResolvExpr::AltList lhs, rhs;
    7082                        TupleAssignSpotter &spotter;
     
    7284                        std::list< ObjectDecl * > tmpDecls;
    7385                        ResolvExpr::TypeEnvironment compositeEnv;
     86                        ResolvExpr::OpenVarSet openVars;
     87                        ResolvExpr::AssertionSet need;
    7488                };
    7589
     
    245259                }
    246260
    247                 // extract expressions from the assignment alternatives to produce a list of assignments that
    248                 // together form a single alternative
     261                // extract expressions from the assignment alternatives to produce a list of assignments
     262                // that together form a single alternative
    249263                std::list< Expression *> solved_assigns;
    250264                for ( ResolvExpr::Alternative & alt : current ) {
    251265                        solved_assigns.push_back( alt.expr->clone() );
    252                 }
    253                 // combine assignment environments into combined expression environment
    254                 simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv );
     266                        matcher->combineState( alt );
     267                }
     268               
    255269                // xxx -- was push_front
    256                 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative(
    257                         new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv,
    258                         ResolvExpr::sumCost( current ) + matcher->baseCost ) );
     270                currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
     271                        new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
     272                        matcher->openVars,
     273                        ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
     274                        ResolvExpr::sumCost( current ) + matcher->baseCost } );
    259275        }
    260276
     
    263279        : lhs(lhs), rhs(rhs), spotter(spotter),
    264280          baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
    265                 simpleCombineEnvironments( lhs.begin(), lhs.end(), compositeEnv );
    266                 simpleCombineEnvironments( rhs.begin(), rhs.end(), compositeEnv );
     281                combineState( lhs );
     282                combineState( rhs );
    267283        }
    268284
Note: See TracChangeset for help on using the changeset viewer.